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)
This commit is contained in:
Matthias Clasen
2005-07-15 16:51:10 +00:00
committed by Matthias Clasen
parent 58729b464b
commit 39ea11ce6b
18 changed files with 1576 additions and 242 deletions

View File

@@ -64,7 +64,6 @@ static gchar* value_param_lcopy_value (const GValue *value,
/* --- variables --- */
static GQuark quark_floating = 0;
G_LOCK_DEFINE_STATIC (pspec_ref_count);
/* --- functions --- */
@@ -169,43 +168,26 @@ GParamSpec*
g_param_spec_ref (GParamSpec *pspec)
{
g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL);
g_return_val_if_fail (pspec->ref_count > 0, NULL);
g_atomic_int_inc (&pspec->ref_count);
G_LOCK (pspec_ref_count);
if (pspec->ref_count > 0)
{
pspec->ref_count += 1;
G_UNLOCK (pspec_ref_count);
}
else
{
G_UNLOCK (pspec_ref_count);
g_return_val_if_fail (pspec->ref_count > 0, NULL);
}
return pspec;
}
void
g_param_spec_unref (GParamSpec *pspec)
{
gboolean is_zero;
g_return_if_fail (G_IS_PARAM_SPEC (pspec));
g_return_if_fail (pspec->ref_count > 0);
G_LOCK (pspec_ref_count);
if (pspec->ref_count > 0)
{
gboolean need_finalize;
is_zero = g_atomic_int_dec_and_test (&pspec->ref_count);
/* sync with _sink */
pspec->ref_count -= 1;
need_finalize = pspec->ref_count == 0;
G_UNLOCK (pspec_ref_count);
if (need_finalize)
G_PARAM_SPEC_GET_CLASS (pspec)->finalize (pspec);
}
else
if (G_UNLIKELY (is_zero))
{
G_UNLOCK (pspec_ref_count);
g_return_if_fail (pspec->ref_count > 0);
G_PARAM_SPEC_GET_CLASS (pspec)->finalize (pspec);
}
}
@@ -213,29 +195,11 @@ void
g_param_spec_sink (GParamSpec *pspec)
{
g_return_if_fail (G_IS_PARAM_SPEC (pspec));
g_return_if_fail (pspec->ref_count > 0);
G_LOCK (pspec_ref_count);
if (pspec->ref_count > 0)
if (g_datalist_id_remove_no_notify (&pspec->qdata, quark_floating))
{
if (g_datalist_id_remove_no_notify (&pspec->qdata, quark_floating))
{
/* sync with _unref */
if (pspec->ref_count > 1)
pspec->ref_count -= 1;
else
{
G_UNLOCK (pspec_ref_count);
g_param_spec_unref (pspec);
return;
}
}
G_UNLOCK (pspec_ref_count);
}
else
{
G_UNLOCK (pspec_ref_count);
g_return_if_fail (pspec->ref_count > 0);
g_param_spec_unref (pspec);
}
}