1 /* GLib testing framework examples and tests
2 * Copyright (C) 2008 Imendio AB
5 * This work is provided "as is"; redistribution and modification
6 * in whole or in part, in any medium, physical or electronic is
7 * permitted without restriction.
9 * This work is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * In no event shall the authors or contributors be liable for any
14 * direct, indirect, incidental, special, exemplary, or consequential
15 * damages (including, but not limited to, procurement of substitute
16 * goods or services; loss of use, data, or profits; or business
17 * interruption) however caused and on any theory of liability, whether
18 * in contract, strict liability, or tort (including negligence or
19 * otherwise) arising in any way out of the use of this software, even
20 * if advised of the possibility of such damage.
23 #include <glib-object.h>
25 static volatile int mtsafe_call_counter = 0; /* multi thread safe call counter */
26 static int unsafe_call_counter = 0; /* single-threaded call counter */
28 #define NUM_COUNTER_INCREMENTS 100000
31 call_counter_init (gpointer tclass)
34 for (i = 0; i < NUM_COUNTER_INCREMENTS; i++)
36 int saved_unsafe_call_counter = unsafe_call_counter;
37 g_atomic_int_add (&mtsafe_call_counter, 1); /* real call count update */
38 g_thread_yield(); /* let concurrent threads corrupt the unsafe_call_counter state */
39 unsafe_call_counter = 1 + saved_unsafe_call_counter; /* non-atomic counter update */
43 static void interface_per_class_init () { call_counter_init (NULL); }
45 /* define 3 test interfaces */
46 typedef GTypeInterface MyFace0Interface;
47 G_DEFINE_INTERFACE (MyFace0, my_face0, G_TYPE_OBJECT);
48 static void my_face0_default_init (MyFace0Interface *iface) { call_counter_init (iface); }
49 typedef GTypeInterface MyFace1Interface;
50 G_DEFINE_INTERFACE (MyFace1, my_face1, G_TYPE_OBJECT);
51 static void my_face1_default_init (MyFace1Interface *iface) { call_counter_init (iface); }
52 typedef GTypeInterface MyFace2Interface;
53 G_DEFINE_INTERFACE (MyFace2, my_face2, G_TYPE_OBJECT);
54 static void my_face2_default_init (MyFace2Interface *iface) { call_counter_init (iface); }
56 /* define 3 test objects, adding interfaces 0 & 1, and adding interface 2 after class initialization */
57 typedef GObject MyTester0;
58 typedef GObjectClass MyTester0Class;
59 G_DEFINE_TYPE_WITH_CODE (MyTester0, my_tester0, G_TYPE_OBJECT,
60 G_IMPLEMENT_INTERFACE (my_face0_get_type(), interface_per_class_init);
61 G_IMPLEMENT_INTERFACE (my_face1_get_type(), interface_per_class_init);
63 static void my_tester0_init (MyTester0*t) {}
64 static void my_tester0_class_init (MyTester0Class*c) { call_counter_init (c); }
65 typedef GObject MyTester1;
66 typedef GObjectClass MyTester1Class;
67 G_DEFINE_TYPE_WITH_CODE (MyTester1, my_tester1, G_TYPE_OBJECT,
68 G_IMPLEMENT_INTERFACE (my_face0_get_type(), interface_per_class_init);
69 G_IMPLEMENT_INTERFACE (my_face1_get_type(), interface_per_class_init);
71 static void my_tester1_init (MyTester1*t) {}
72 static void my_tester1_class_init (MyTester1Class*c) { call_counter_init (c); }
73 typedef GObject MyTester2;
74 typedef GObjectClass MyTester2Class;
75 G_DEFINE_TYPE_WITH_CODE (MyTester2, my_tester2, G_TYPE_OBJECT,
76 G_IMPLEMENT_INTERFACE (my_face0_get_type(), interface_per_class_init);
77 G_IMPLEMENT_INTERFACE (my_face1_get_type(), interface_per_class_init);
79 static void my_tester2_init (MyTester2*t) {}
80 static void my_tester2_class_init (MyTester2Class*c) { call_counter_init (c); }
82 static GCond *sync_cond = NULL;
83 static GMutex *sync_mutex = NULL;
86 tester_init_thread (gpointer data)
88 const GInterfaceInfo face2_interface_info = { (GInterfaceInitFunc) interface_per_class_init, NULL, NULL };
90 /* first, syncronize with other threads,
91 * then run interface and class initializers,
92 * using unsafe_call_counter concurrently
94 g_mutex_lock (sync_mutex);
95 g_mutex_unlock (sync_mutex);
96 /* test default interface initialization for face0 */
97 g_type_default_interface_unref (g_type_default_interface_ref (my_face0_get_type()));
98 /* test class initialization, face0 per-class initializer, face1 default and per-class initializer */
99 klass = g_type_class_ref ((GType) data);
100 /* test face2 default and per-class initializer, after class_init */
101 g_type_add_interface_static (G_TYPE_FROM_CLASS (klass), my_face2_get_type(), &face2_interface_info);
103 g_type_class_unref (klass);
108 test_threaded_class_init (void)
110 GThread *threads[3] = { NULL, };
111 /* pause newly created threads */
112 g_mutex_lock (sync_mutex);
114 threads[0] = g_thread_create (tester_init_thread, (gpointer) my_tester0_get_type(), TRUE, NULL);
115 threads[1] = g_thread_create (tester_init_thread, (gpointer) my_tester1_get_type(), TRUE, NULL);
116 threads[2] = g_thread_create (tester_init_thread, (gpointer) my_tester2_get_type(), TRUE, NULL);
117 /* execute threads */
118 g_mutex_unlock (sync_mutex);
119 while (g_atomic_int_get (&mtsafe_call_counter) < (3 + 3 + 3 * 3) * NUM_COUNTER_INCREMENTS)
121 if (g_test_verbose())
122 g_print ("Initializers counted: %u\n", g_atomic_int_get (&mtsafe_call_counter));
123 g_usleep (50 * 1000); /* wait for threads to complete */
125 if (g_test_verbose())
126 g_print ("Total initializers: %u\n", g_atomic_int_get (&mtsafe_call_counter));
127 /* ensure non-corrupted counter updates */
128 g_assert_cmpint (g_atomic_int_get (&mtsafe_call_counter), ==, unsafe_call_counter);
135 typedef GObjectClass PropTesterClass;
136 G_DEFINE_TYPE (PropTester, prop_tester, G_TYPE_OBJECT);
139 prop_tester_init (PropTester* t)
142 ; /* neds unit test framework initialization: g_test_bug ("race initializing properties"); */
145 prop_tester_set_property (GObject *object,
151 prop_tester_class_init (PropTesterClass *c)
155 GObjectClass *gobject_class = G_OBJECT_CLASS (c);
157 gobject_class->set_property = prop_tester_set_property; /* silence GObject checks */
159 g_mutex_lock (sync_mutex);
160 g_cond_signal (sync_cond);
161 g_mutex_unlock (sync_mutex);
163 for (i = 0; i < 100; i++) /* wait a bit. */
166 call_counter_init (c);
167 param = g_param_spec_string ("name", "name_i18n",
168 "yet-more-wasteful-i18n",
170 G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE |
171 G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB |
172 G_PARAM_STATIC_NICK);
173 g_object_class_install_property (gobject_class, PROP_NAME, param);
177 object_create (gpointer data)
179 GObject *obj = g_object_new (prop_tester_get_type(), "name", "fish", NULL);
180 g_object_unref (obj);
185 test_threaded_object_init (void)
188 g_mutex_lock (sync_mutex);
190 creator = g_thread_create (object_create, NULL, TRUE, NULL);
191 /* really provoke the race */
192 g_cond_wait (sync_cond, sync_mutex);
194 object_create (NULL);
195 g_mutex_unlock (sync_mutex);
197 g_thread_join (creator);
204 g_thread_init (NULL);
205 g_test_init (&argc, &argv, NULL);
208 sync_cond = g_cond_new();
209 sync_mutex = g_mutex_new();
211 g_test_add_func ("/GObject/threaded-class-init", test_threaded_class_init);
212 g_test_add_func ("/GObject/threaded-object-init", test_threaded_object_init);