mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-26 12:12:10 +01:00
Add tests for GBinding thread-safety
This commit is contained in:
parent
d296ad435d
commit
cc15c933b3
@ -886,6 +886,182 @@ binding_interface (void)
|
|||||||
g_object_unref (target);
|
g_object_unref (target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
GThread *thread;
|
||||||
|
GBinding *binding;
|
||||||
|
GMutex *lock;
|
||||||
|
GCond *cond;
|
||||||
|
gboolean *wait;
|
||||||
|
gint *count; /* (atomic) */
|
||||||
|
} ConcurrentUnbindData;
|
||||||
|
|
||||||
|
static gpointer
|
||||||
|
concurrent_unbind_func (gpointer data)
|
||||||
|
{
|
||||||
|
ConcurrentUnbindData *unbind_data = data;
|
||||||
|
|
||||||
|
g_mutex_lock (unbind_data->lock);
|
||||||
|
g_atomic_int_inc (unbind_data->count);
|
||||||
|
while (*unbind_data->wait)
|
||||||
|
g_cond_wait (unbind_data->cond, unbind_data->lock);
|
||||||
|
g_mutex_unlock (unbind_data->lock);
|
||||||
|
g_binding_unbind (unbind_data->binding);
|
||||||
|
g_object_unref (unbind_data->binding);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
binding_concurrent_unbind (void)
|
||||||
|
{
|
||||||
|
guint i, j;
|
||||||
|
|
||||||
|
g_test_summary ("Test that unbinding from multiple threads concurrently works correctly");
|
||||||
|
|
||||||
|
for (i = 0; i < 50; i++)
|
||||||
|
{
|
||||||
|
BindingSource *source = g_object_new (binding_source_get_type (), NULL);
|
||||||
|
BindingTarget *target = g_object_new (binding_target_get_type (), NULL);
|
||||||
|
GBinding *binding;
|
||||||
|
GQueue threads = G_QUEUE_INIT;
|
||||||
|
GMutex lock;
|
||||||
|
GCond cond;
|
||||||
|
gboolean wait = TRUE;
|
||||||
|
gint count = 0; /* (atomic) */
|
||||||
|
ConcurrentUnbindData *data;
|
||||||
|
|
||||||
|
g_mutex_init (&lock);
|
||||||
|
g_cond_init (&cond);
|
||||||
|
|
||||||
|
binding = g_object_bind_property (source, "foo",
|
||||||
|
target, "bar",
|
||||||
|
G_BINDING_BIDIRECTIONAL);
|
||||||
|
g_object_ref (binding);
|
||||||
|
|
||||||
|
for (j = 0; j < 10; j++)
|
||||||
|
{
|
||||||
|
data = g_new0 (ConcurrentUnbindData, 1);
|
||||||
|
|
||||||
|
data->binding = g_object_ref (binding);
|
||||||
|
data->lock = &lock;
|
||||||
|
data->cond = &cond;
|
||||||
|
data->wait = &wait;
|
||||||
|
data->count = &count;
|
||||||
|
|
||||||
|
data->thread = g_thread_new ("binding-concurrent", concurrent_unbind_func, data);
|
||||||
|
g_queue_push_tail (&threads, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* wait until all threads are started */
|
||||||
|
while (g_atomic_int_get (&count) < 10)
|
||||||
|
g_thread_yield ();
|
||||||
|
|
||||||
|
g_mutex_lock (&lock);
|
||||||
|
wait = FALSE;
|
||||||
|
g_cond_broadcast (&cond);
|
||||||
|
g_mutex_unlock (&lock);
|
||||||
|
|
||||||
|
while ((data = g_queue_pop_head (&threads)))
|
||||||
|
{
|
||||||
|
g_thread_join (data->thread);
|
||||||
|
g_free (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_mutex_clear (&lock);
|
||||||
|
g_cond_clear (&cond);
|
||||||
|
|
||||||
|
g_object_unref (binding);
|
||||||
|
g_object_unref (source);
|
||||||
|
g_object_unref (target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
GObject *object;
|
||||||
|
GMutex *lock;
|
||||||
|
GCond *cond;
|
||||||
|
gint *count; /* (atomic) */
|
||||||
|
gboolean *wait;
|
||||||
|
} ConcurrentFinalizeData;
|
||||||
|
|
||||||
|
static gpointer
|
||||||
|
concurrent_finalize_func (gpointer data)
|
||||||
|
{
|
||||||
|
ConcurrentFinalizeData *finalize_data = data;
|
||||||
|
|
||||||
|
g_mutex_lock (finalize_data->lock);
|
||||||
|
g_atomic_int_inc (finalize_data->count);
|
||||||
|
while (*finalize_data->wait)
|
||||||
|
g_cond_wait (finalize_data->cond, finalize_data->lock);
|
||||||
|
g_mutex_unlock (finalize_data->lock);
|
||||||
|
g_object_unref (finalize_data->object);
|
||||||
|
g_free (finalize_data);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
binding_concurrent_finalizing (void)
|
||||||
|
{
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
g_test_summary ("Test that finalizing source/target from multiple threads concurrently works correctly");
|
||||||
|
|
||||||
|
for (i = 0; i < 50; i++)
|
||||||
|
{
|
||||||
|
BindingSource *source = g_object_new (binding_source_get_type (), NULL);
|
||||||
|
BindingTarget *target = g_object_new (binding_target_get_type (), NULL);
|
||||||
|
GBinding *binding;
|
||||||
|
GMutex lock;
|
||||||
|
GCond cond;
|
||||||
|
gboolean wait = TRUE;
|
||||||
|
ConcurrentFinalizeData *data;
|
||||||
|
GThread *source_thread, *target_thread;
|
||||||
|
gint count = 0; /* (atomic) */
|
||||||
|
|
||||||
|
g_mutex_init (&lock);
|
||||||
|
g_cond_init (&cond);
|
||||||
|
|
||||||
|
binding = g_object_bind_property (source, "foo",
|
||||||
|
target, "bar",
|
||||||
|
G_BINDING_BIDIRECTIONAL);
|
||||||
|
g_object_ref (binding);
|
||||||
|
|
||||||
|
data = g_new0 (ConcurrentFinalizeData, 1);
|
||||||
|
data->object = (GObject *) source;
|
||||||
|
data->wait = &wait;
|
||||||
|
data->lock = &lock;
|
||||||
|
data->cond = &cond;
|
||||||
|
data->count = &count;
|
||||||
|
source_thread = g_thread_new ("binding-concurrent", concurrent_finalize_func, data);
|
||||||
|
|
||||||
|
data = g_new0 (ConcurrentFinalizeData, 1);
|
||||||
|
data->object = (GObject *) target;
|
||||||
|
data->wait = &wait;
|
||||||
|
data->lock = &lock;
|
||||||
|
data->cond = &cond;
|
||||||
|
data->count = &count;
|
||||||
|
target_thread = g_thread_new ("binding-concurrent", concurrent_finalize_func, data);
|
||||||
|
|
||||||
|
/* wait until all threads are started */
|
||||||
|
while (g_atomic_int_get (&count) < 2)
|
||||||
|
g_thread_yield ();
|
||||||
|
|
||||||
|
g_mutex_lock (&lock);
|
||||||
|
wait = FALSE;
|
||||||
|
g_cond_broadcast (&cond);
|
||||||
|
g_mutex_unlock (&lock);
|
||||||
|
|
||||||
|
g_thread_join (source_thread);
|
||||||
|
g_thread_join (target_thread);
|
||||||
|
|
||||||
|
g_mutex_clear (&lock);
|
||||||
|
g_cond_clear (&cond);
|
||||||
|
|
||||||
|
g_object_unref (binding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, char *argv[])
|
main (int argc, char *argv[])
|
||||||
{
|
{
|
||||||
@ -908,6 +1084,8 @@ main (int argc, char *argv[])
|
|||||||
g_test_add_func ("/binding/unbind-multiple", binding_unbind_multiple);
|
g_test_add_func ("/binding/unbind-multiple", binding_unbind_multiple);
|
||||||
g_test_add_func ("/binding/fail", binding_fail);
|
g_test_add_func ("/binding/fail", binding_fail);
|
||||||
g_test_add_func ("/binding/interface", binding_interface);
|
g_test_add_func ("/binding/interface", binding_interface);
|
||||||
|
g_test_add_func ("/binding/concurrent-unbind", binding_concurrent_unbind);
|
||||||
|
g_test_add_func ("/binding/concurrent-finalizing", binding_concurrent_finalizing);
|
||||||
|
|
||||||
return g_test_run ();
|
return g_test_run ();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user