1 #include <unistd.h> 2 #include <glib.h> 3 #include <glib-object.h> 4 5 #define G_TYPE_TEST (my_test_get_type ()) 6 #define MY_TEST(test) (G_TYPE_CHECK_INSTANCE_CAST ((test), G_TYPE_TEST, GTest)) 7 #define MY_IS_TEST(test) (G_TYPE_CHECK_INSTANCE_TYPE ((test), G_TYPE_TEST)) 8 #define MY_TEST_CLASS(tclass) (G_TYPE_CHECK_CLASS_CAST ((tclass), G_TYPE_TEST, GTestClass)) 9 #define MY_IS_TEST_CLASS(tclass) (G_TYPE_CHECK_CLASS_TYPE ((tclass), G_TYPE_TEST)) 10 #define MY_TEST_GET_CLASS(test) (G_TYPE_INSTANCE_GET_CLASS ((test), G_TYPE_TEST, GTestClass)) 11 12 enum { 13 PROP_0, 14 PROP_DUMMY 15 }; 16 17 typedef struct _GTest GTest; 18 typedef struct _GTestClass GTestClass; 19 20 struct _GTest 21 { 22 GObject object; 23 gint id; 24 gint dummy; 25 26 gint count; 27 }; 28 29 struct _GTestClass 30 { 31 GObjectClass parent_class; 32 }; 33 34 static GType my_test_get_type (void); 35 static volatile gboolean stopping; 36 37 static void my_test_class_init (GTestClass * klass); 38 static void my_test_init (GTest * test); 39 static void my_test_dispose (GObject * object); 40 static void my_test_get_property (GObject *object, 41 guint prop_id, 42 GValue *value, 43 GParamSpec *pspec); 44 static void my_test_set_property (GObject *object, 45 guint prop_id, 46 const GValue *value, 47 GParamSpec *pspec); 48 49 static GObjectClass *parent_class = NULL; 50 51 static GType 52 my_test_get_type (void) 53 { 54 static GType test_type = 0; 55 56 if (!test_type) { 57 static const GTypeInfo test_info = { 58 sizeof (GTestClass), 59 NULL, 60 NULL, 61 (GClassInitFunc) my_test_class_init, 62 NULL, 63 NULL, 64 sizeof (GTest), 65 0, 66 (GInstanceInitFunc) my_test_init, 67 NULL 68 }; 69 70 test_type = g_type_register_static (G_TYPE_OBJECT, "GTest", &test_info, 0); 71 } 72 return test_type; 73 } 74 75 static void 76 my_test_class_init (GTestClass * klass) 77 { 78 GObjectClass *gobject_class; 79 80 gobject_class = (GObjectClass *) klass; 81 82 parent_class = g_type_class_ref (G_TYPE_OBJECT); 83 84 gobject_class->dispose = my_test_dispose; 85 gobject_class->get_property = my_test_get_property; 86 gobject_class->set_property = my_test_set_property; 87 88 g_object_class_install_property (gobject_class, 89 PROP_DUMMY, 90 g_param_spec_int ("dummy", 91 NULL, 92 NULL, 93 0, G_MAXINT, 0, 94 G_PARAM_READWRITE)); 95 } 96 97 static void 98 my_test_init (GTest * test) 99 { 100 static guint static_id = 1; 101 test->id = static_id++; 102 } 103 104 static void 105 my_test_dispose (GObject * object) 106 { 107 GTest *test; 108 109 test = MY_TEST (object); 110 111 G_OBJECT_CLASS (parent_class)->dispose (object); 112 } 113 114 static void 115 my_test_get_property (GObject *object, 116 guint prop_id, 117 GValue *value, 118 GParamSpec *pspec) 119 { 120 GTest *test; 121 122 test = MY_TEST (object); 123 124 switch (prop_id) 125 { 126 case PROP_DUMMY: 127 g_value_set_int (value, test->dummy); 128 break; 129 default: 130 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 131 break; 132 } 133 } 134 135 static void 136 my_test_set_property (GObject *object, 137 guint prop_id, 138 const GValue *value, 139 GParamSpec *pspec) 140 { 141 GTest *test; 142 143 test = MY_TEST (object); 144 145 switch (prop_id) 146 { 147 case PROP_DUMMY: 148 test->dummy = g_value_get_int (value); 149 break; 150 default: 151 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 152 break; 153 } 154 } 155 156 static void 157 dummy_notify (GObject *object, 158 GParamSpec *pspec) 159 { 160 GTest *test; 161 162 test = MY_TEST (object); 163 164 test->count++; 165 } 166 167 static void 168 my_test_do_property (GTest * test) 169 { 170 gint dummy; 171 172 g_object_get (test, "dummy", &dummy, NULL); 173 g_object_set (test, "dummy", dummy + 1, NULL); 174 } 175 176 static gpointer 177 run_thread (GTest * test) 178 { 179 gint i = 1; 180 181 while (!stopping) { 182 my_test_do_property (test); 183 if ((i++ % 10000) == 0) 184 { 185 g_print (".%c", 'a' + test->id); 186 g_thread_yield(); /* force context switch */ 187 } 188 } 189 190 return NULL; 191 } 192 193 int 194 main (int argc, char **argv) 195 { 196 gint i; 197 GArray *test_objects; 198 GArray *test_threads; 199 const gint n_threads = 5; 200 201 g_thread_init (NULL); 202 g_print ("START: %s\n", argv[0]); 203 g_log_set_always_fatal (G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL | g_log_set_always_fatal (G_LOG_FATAL_MASK)); 204 g_type_init (); 205 206 test_objects = g_array_new (FALSE, FALSE, sizeof (GTest *)); 207 208 for (i = 0; i < n_threads; i++) { 209 GTest *test; 210 211 test = g_object_new (G_TYPE_TEST, NULL); 212 g_array_append_val (test_objects, test); 213 214 g_assert (test->count == test->dummy); 215 g_signal_connect (test, "notify::dummy", G_CALLBACK (dummy_notify), NULL); 216 } 217 218 test_threads = g_array_new (FALSE, FALSE, sizeof (GThread *)); 219 220 stopping = FALSE; 221 222 for (i = 0; i < n_threads; i++) { 223 GThread *thread; 224 GTest *test; 225 226 test = g_array_index (test_objects, GTest *, i); 227 228 thread = g_thread_create ((GThreadFunc) run_thread, test, TRUE, NULL); 229 g_array_append_val (test_threads, thread); 230 } 231 g_usleep (3000000); 232 233 stopping = TRUE; 234 g_print ("\nstopping\n"); 235 236 /* join all threads */ 237 for (i = 0; i < n_threads; i++) { 238 GThread *thread; 239 240 thread = g_array_index (test_threads, GThread *, i); 241 g_thread_join (thread); 242 } 243 244 g_print ("stopped\n"); 245 246 for (i = 0; i < n_threads; i++) { 247 GTest *test; 248 249 test = g_array_index (test_objects, GTest *, i); 250 251 g_assert (test->count == test->dummy); 252 } 253 254 return 0; 255 } 256