View | Details | Raw Unified | Return to bug 385128
Collapse All | Expand All

(-)a/gobject/gtype.c (-29 / +20 lines)
Lines 2363-2382 gpointer Link Here
2363
g_type_class_ref (GType type)
2363
g_type_class_ref (GType type)
2364
{
2364
{
2365
  TypeNode *node;
2365
  TypeNode *node;
2366
  
2366
  GType ptype;
2367
  /* optimize for common code path
2367
2368
   */
2368
  /* optimize for common code path */
2369
  G_WRITE_LOCK (&type_rw_lock);
2369
  G_WRITE_LOCK (&type_rw_lock);
2370
  node = lookup_type_node_I (type);
2370
  node = lookup_type_node_I (type);
2371
  if (node && node->is_classed && node->data &&
2371
  if (node && node->is_classed && node->data &&
2372
      node->data->class.class && node->data->common.ref_count > 0)
2372
      node->data->class.class &&
2373
      node->data->class.init_state == INITIALIZED)
2373
    {
2374
    {
2374
      type_data_ref_Wm (node);
2375
      type_data_ref_Wm (node);
2375
      G_WRITE_UNLOCK (&type_rw_lock);
2376
      G_WRITE_UNLOCK (&type_rw_lock);
2376
      
2377
      return node->data->class.class;
2377
      return node->data->class.class;
2378
    }
2378
    }
2379
  
2380
  if (!node || !node->is_classed ||
2379
  if (!node || !node->is_classed ||
2381
      (node->data && node->data->common.ref_count < 1))
2380
      (node->data && node->data->common.ref_count < 1))
2382
    {
2381
    {
Lines 2385-2417 g_type_class_ref (GType type) Link Here
2385
		 type_descriptive_name_I (type));
2384
		 type_descriptive_name_I (type));
2386
      return NULL;
2385
      return NULL;
2387
    }
2386
    }
2388
2389
  type_data_ref_Wm (node);
2387
  type_data_ref_Wm (node);
2388
  ptype = NODE_PARENT_TYPE (node);
2389
  G_WRITE_UNLOCK (&type_rw_lock);
2390
2390
2391
  g_static_rec_mutex_lock (&class_init_rec_mutex); /* required locking order: 1) class_init_rec_mutex, 2) type_rw_lock */
2392
  /* here, we either have node->data->class.class == NULL, or
2393
   * node->data->class.init_state == INITIALIZED, because any
2394
   * concurrently running initialization was guarded by class_init_rec_mutex.
2395
   */
2391
  if (!node->data->class.class) /* class uninitialized */
2396
  if (!node->data->class.class) /* class uninitialized */
2392
    {
2397
    {
2393
      GType ptype = NODE_PARENT_TYPE (node);
2398
      /* acquire reference on parent class */
2394
      GTypeClass *pclass = NULL;
2399
      GTypeClass *pclass = ptype ? g_type_class_ref (ptype) : NULL;
2395
      G_WRITE_UNLOCK (&type_rw_lock);
2400
      G_WRITE_LOCK (&type_rw_lock);
2396
      g_static_rec_mutex_lock (&class_init_rec_mutex); /* required locking order: 1) class_init_rec_mutex, 2) type_rw_lock */
2401
      if (node->data->class.class) /* class was initialized during parent class initialization? */
2397
      if (ptype)
2402
        INVALID_RECURSION ("g_type_plugin_*", node->plugin, NODE_NAME (node));
2398
        {
2403
      type_class_init_Wm (node, pclass);
2399
          pclass = g_type_class_ref (ptype);
2400
          G_WRITE_LOCK (&type_rw_lock);
2401
          node = lookup_type_node_I (type);
2402
          if (node->data->class.class)
2403
            INVALID_RECURSION ("g_type_plugin_*", node->plugin, NODE_NAME (node));
2404
        }
2405
      else
2406
        {
2407
          G_WRITE_LOCK (&type_rw_lock);
2408
          node = lookup_type_node_I (type);
2409
        }
2410
      if (!node->data->class.class) /* class could have been initialized meanwhile */
2411
        type_class_init_Wm (node, pclass);
2412
      G_WRITE_UNLOCK (&type_rw_lock);
2404
      G_WRITE_UNLOCK (&type_rw_lock);
2413
      g_static_rec_mutex_unlock (&class_init_rec_mutex);
2414
    }
2405
    }
2406
  g_static_rec_mutex_unlock (&class_init_rec_mutex);
2407
2415
  return node->data->class.class;
2408
  return node->data->class.class;
2416
}
2409
}
2417
2410
2418
- 
2419
       * tests/threadtests.c: added race condition tester from Michael Meeks
2411
       * tests/threadtests.c: added race condition tester from Michael Meeks
2420
       with a couple fixes so it's not triggering development warnings. From:
2412
       with a couple fixes so it's not triggering development warnings. From:
2421
       Bug 537555 - GObject instantiation not thread safe ...
2413
       Bug 537555 - GObject instantiation not thread safe ...
2422
--
2423
gobject/ChangeLog           |    6 +++
2414
gobject/ChangeLog           |    6 +++
2424
gobject/tests/threadtests.c |   75 ++++++++++++++++++++++++++++++++++++++++++-
2415
gobject/tests/threadtests.c |   75 ++++++++++++++++++++++++++++++++++++++++++-
2425
2 files changed, 80 insertions(+), 1 deletions(-)
2416
2 files changed, 80 insertions(+), 1 deletions(-)
(-)a/gobject/tests/threadtests.c (-2 / +74 lines)
Lines 109-114 G_DEFINE_TYPE_WITH_CODE (MyTester2, my_tester2, G_TYPE_OBJECT, Link Here
109
static void my_tester2_init (MyTester2*t) {}
109
static void my_tester2_init (MyTester2*t) {}
110
static void my_tester2_class_init (MyTester2Class*c) { call_counter_init (c); }
110
static void my_tester2_class_init (MyTester2Class*c) { call_counter_init (c); }
111
111
112
static GCond *sync_cond = NULL;
112
static GMutex *sync_mutex = NULL;
113
static GMutex *sync_mutex = NULL;
113
114
114
static gpointer
115
static gpointer
Lines 138-144 test_threaded_class_init (void) Link Here
138
{
139
{
139
  GThread *threads[3] = { NULL, };
140
  GThread *threads[3] = { NULL, };
140
  /* pause newly created threads */
141
  /* pause newly created threads */
141
  sync_mutex = g_mutex_new();
142
  g_mutex_lock (sync_mutex);
142
  g_mutex_lock (sync_mutex);
143
  /* create threads */
143
  /* create threads */
144
  threads[0] = g_thread_create (tester_init_thread, (gpointer) my_tester0_get_type(), TRUE, NULL);
144
  threads[0] = g_thread_create (tester_init_thread, (gpointer) my_tester0_get_type(), TRUE, NULL);
Lines 158-163 test_threaded_class_init (void) Link Here
158
  g_assert_cmpint (g_atomic_int_get (&mtsafe_call_counter), ==, unsafe_call_counter);
158
  g_assert_cmpint (g_atomic_int_get (&mtsafe_call_counter), ==, unsafe_call_counter);
159
}
159
}
160
160
161
typedef struct {
162
  GObject parent;
163
  char   *name;
164
} PropTester;
165
typedef GObjectClass    PropTesterClass;
166
G_DEFINE_TYPE (PropTester, prop_tester, G_TYPE_OBJECT);
167
#define PROP_NAME 1
168
static void
169
prop_tester_init (PropTester* t)
170
{
171
  if (t->name == NULL)
172
    ; // neds unit test framework initialization: g_test_bug ("race initializing properties");
173
}
174
static void
175
prop_tester_set_property (GObject        *object,
176
                          guint           property_id,
177
                          const GValue   *value,
178
                          GParamSpec     *pspec)
179
{}
180
static void
181
prop_tester_class_init (PropTesterClass *c)
182
{
183
  int i;
184
  GParamSpec *param;
185
  GObjectClass *gobject_class = G_OBJECT_CLASS (c);
186
187
  gobject_class->set_property = prop_tester_set_property; /* silence GObject checks */
188
189
  g_mutex_lock (sync_mutex);
190
  g_cond_signal (sync_cond);
191
  g_mutex_unlock (sync_mutex);
192
193
  for (i = 0; i < 100; i++) /* wait a bit. */
194
    g_thread_yield();
195
196
  call_counter_init (c);
197
  param = g_param_spec_string ("name", "name_i18n",
198
			       "yet-more-wasteful-i18n",
199
			       NULL,
200
			       G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE |
201
			       G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB |
202
			       G_PARAM_STATIC_NICK);
203
  g_object_class_install_property (gobject_class, PROP_NAME, param);
204
}
205
206
static gpointer
207
object_create (gpointer data)
208
{
209
  GObject *obj = g_object_new (prop_tester_get_type(), "name", "fish", NULL);
210
  g_object_unref (obj);
211
  return NULL;
212
}
213
214
static void
215
test_threaded_object_init (void)
216
{
217
  GThread *creator;
218
  g_mutex_lock (sync_mutex);
219
220
  creator = g_thread_create (object_create, NULL, TRUE, NULL);
221
  /* really provoke the race */
222
  g_cond_wait (sync_cond, sync_mutex);
223
224
  object_create (NULL);
225
  g_mutex_unlock (sync_mutex);
226
227
  g_thread_join (creator);
228
}
229
161
int
230
int
162
main (int   argc,
231
main (int   argc,
163
      char *argv[])
232
      char *argv[])
Lines 166-172 main (int argc, Link Here
166
  g_test_init (&argc, &argv, NULL);
235
  g_test_init (&argc, &argv, NULL);
167
  g_type_init ();
236
  g_type_init ();
168
237
238
  sync_cond = g_cond_new();
239
  sync_mutex = g_mutex_new();
240
169
  g_test_add_func ("/GObject/threaded-class-init", test_threaded_class_init);
241
  g_test_add_func ("/GObject/threaded-class-init", test_threaded_class_init);
242
  g_test_add_func ("/GObject/threaded-object-init", test_threaded_object_init);
170
243
171
  return g_test_run();
244
  return g_test_run();
172
}
245
}
173
- 

Return to bug 385128