summaryrefslogtreecommitdiff
path: root/gobject/gsignal.c
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2005-07-15 16:51:10 +0000
committerMatthias Clasen <matthiasc@src.gnome.org>2005-07-15 16:51:10 +0000
commit39ea11ce6b107bf3969a2f94807675b458a5a887 (patch)
treeb06f87caa8052fd3a656168201eadba77cc133e8 /gobject/gsignal.c
parent58729b464b44595704c4e8e65869fd2228554ed5 (diff)
Make refcounting threadsafe by using atomic operations. (#166020, Wim
2005-07-15 Matthias Clasen <mclasen@redhat.com> Make refcounting threadsafe by using atomic operations. (#166020, Wim Taymans) * gobject.c: Use a recursive lock to protect the notify queue. (g_object_unref): Get rid of g_object_last_unref and do the last unref handling in g_object_unref. (g_object_ref, g_object_unref): Use atomic operations. * gsignal.c (struct _HandlerMatch): Use a full integer for the ref_count field. (handler_ref, handler_unref_R): Use atomic operations. * gparam.c (g_param_spec_ref, g_param_spec_unref): Use atomic operations instead of a lock to make the refcounting threadsafe. * gclosure.c (g_closure_ref, g_closure_unref): Use atomic operations. This is more complicated here, since the refcount is stored in a bitfield, so we also have to access all other bitfield members atomically. * gsignal.c (handlers_find): Read the meta_marshal flag of the closure atomically. * tests/Makefile.am (SUBDIRS): Add tests/refcount * configure.in: Add tests/refcount * tests/refcount/properties.c: Test property changes from multiple threads. * tests/refcount/signals.c: Test signal emission from multiple threads. * tests/refcount/objects.c: Test refcounting from multiple threads. * tests/refcount/objects2.c: * tests/refcount/properties2.c: Tests to measure the overhead of threadsafe refcounting. * glib/giochannel.c (g_io_channel_ref, g_io_channel_unref): Use atomic operations to make refcounting threadsafe. (#166020, Wim Taymans)
Diffstat (limited to 'gobject/gsignal.c')
-rw-r--r--gobject/gsignal.c94
1 files changed, 57 insertions, 37 deletions
diff --git a/gobject/gsignal.c b/gobject/gsignal.c
index 2ecb3fc07..b834fd8d8 100644
--- a/gobject/gsignal.c
+++ b/gobject/gsignal.c
@@ -222,8 +222,7 @@ struct _Handler
Handler *next;
Handler *prev;
GQuark detail;
- guint ref_count : 16;
-#define HANDLER_MAX_REF_COUNT (1 << 16)
+ guint ref_count; /* ABI change, was 16 bits but since it's internal... */
guint block_count : 12;
#define HANDLER_MAX_BLOCK_COUNT (1 << 12)
guint after : 1;
@@ -455,6 +454,17 @@ handler_match_free1_R (HandlerMatch *node,
return next;
}
+/* copy of gclosure.c code here to make the first 32 bits of the closure
+ * atomic. */
+typedef union
+{
+ GClosure bits;
+ gint atomic;
+} GAtomicClosureBits;
+
+#define BITS_AS_INT(b) (((GAtomicClosureBits*)(b))->atomic)
+#define CLOSURE_READ_BITS(cl,bits) (BITS_AS_INT(bits) = g_atomic_int_get ((gint*)(cl)))
+
static HandlerMatch*
handlers_find (gpointer instance,
GSignalMatchType mask,
@@ -481,20 +491,26 @@ handlers_find (gpointer instance,
}
mask = ~mask;
- for (handler = hlist ? hlist->handlers : NULL; handler; handler = handler->next)
- if (handler->sequential_number &&
- ((mask & G_SIGNAL_MATCH_DETAIL) || handler->detail == detail) &&
- ((mask & G_SIGNAL_MATCH_CLOSURE) || handler->closure == closure) &&
- ((mask & G_SIGNAL_MATCH_DATA) || handler->closure->data == data) &&
- ((mask & G_SIGNAL_MATCH_UNBLOCKED) || handler->block_count == 0) &&
- ((mask & G_SIGNAL_MATCH_FUNC) || (handler->closure->marshal == node->c_marshaller &&
- handler->closure->meta_marshal == 0 &&
- ((GCClosure*) handler->closure)->callback == func)))
- {
- mlist = handler_match_prepend (mlist, handler, signal_id);
- if (one_and_only)
- return mlist;
- }
+ for (handler = hlist ? hlist->handlers : NULL; handler; handler = handler->next)
+ {
+ GClosure bits;
+
+ CLOSURE_READ_BITS (handler->closure, &bits);
+
+ if (handler->sequential_number &&
+ ((mask & G_SIGNAL_MATCH_DETAIL) || handler->detail == detail) &&
+ ((mask & G_SIGNAL_MATCH_CLOSURE) || handler->closure == closure) &&
+ ((mask & G_SIGNAL_MATCH_DATA) || handler->closure->data == data) &&
+ ((mask & G_SIGNAL_MATCH_UNBLOCKED) || handler->block_count == 0) &&
+ ((mask & G_SIGNAL_MATCH_FUNC) || (handler->closure->marshal == node->c_marshaller &&
+ bits.meta_marshal == 0 &&
+ ((GCClosure*) handler->closure)->callback == func)))
+ {
+ mlist = handler_match_prepend (mlist, handler, signal_id);
+ if (one_and_only)
+ return mlist;
+ }
+ }
}
else
{
@@ -519,19 +535,25 @@ handlers_find (gpointer instance,
}
for (handler = hlist->handlers; handler; handler = handler->next)
- if (handler->sequential_number &&
- ((mask & G_SIGNAL_MATCH_DETAIL) || handler->detail == detail) &&
- ((mask & G_SIGNAL_MATCH_CLOSURE) || handler->closure == closure) &&
- ((mask & G_SIGNAL_MATCH_DATA) || handler->closure->data == data) &&
- ((mask & G_SIGNAL_MATCH_UNBLOCKED) || handler->block_count == 0) &&
- ((mask & G_SIGNAL_MATCH_FUNC) || (handler->closure->marshal == node->c_marshaller &&
- handler->closure->meta_marshal == 0 &&
- ((GCClosure*) handler->closure)->callback == func)))
- {
- mlist = handler_match_prepend (mlist, handler, hlist->signal_id);
- if (one_and_only)
- return mlist;
- }
+ {
+ GClosure bits;
+
+ CLOSURE_READ_BITS (handler->closure, &bits);
+
+ if (handler->sequential_number &&
+ ((mask & G_SIGNAL_MATCH_DETAIL) || handler->detail == detail) &&
+ ((mask & G_SIGNAL_MATCH_CLOSURE) || handler->closure == closure) &&
+ ((mask & G_SIGNAL_MATCH_DATA) || handler->closure->data == data) &&
+ ((mask & G_SIGNAL_MATCH_UNBLOCKED) || handler->block_count == 0) &&
+ ((mask & G_SIGNAL_MATCH_FUNC) || (handler->closure->marshal == node->c_marshaller &&
+ bits.meta_marshal == 0 &&
+ ((GCClosure*) handler->closure)->callback == func)))
+ {
+ mlist = handler_match_prepend (mlist, handler, hlist->signal_id);
+ if (one_and_only)
+ return mlist;
+ }
+ }
}
}
}
@@ -567,12 +589,7 @@ handler_ref (Handler *handler)
{
g_return_if_fail (handler->ref_count > 0);
-#ifndef G_DISABLE_CHECKS
- if (handler->ref_count >= HANDLER_MAX_REF_COUNT - 1)
- g_error (G_STRLOC ": handler ref_count overflow, %s", REPORT_BUG);
-#endif
-
- handler->ref_count += 1;
+ g_atomic_int_inc (&handler->ref_count);
}
static inline void
@@ -580,10 +597,13 @@ handler_unref_R (guint signal_id,
gpointer instance,
Handler *handler)
{
+ gboolean is_zero;
+
g_return_if_fail (handler->ref_count > 0);
- handler->ref_count -= 1;
- if (!handler->ref_count)
+ is_zero = g_atomic_int_dec_and_test (&handler->ref_count);
+
+ if (G_UNLIKELY (is_zero))
{
HandlerList *hlist = NULL;