@@ -128,9 +128,9 @@ static void mono_threads_unlock (void);
128
128
static MonoCoopMutex threads_mutex ;
129
129
130
130
/* Controls access to the 'joinable_threads' hash table */
131
- #define joinable_threads_lock () mono_os_mutex_lock (&joinable_threads_mutex)
132
- #define joinable_threads_unlock () mono_os_mutex_unlock (&joinable_threads_mutex)
133
- static mono_mutex_t joinable_threads_mutex ;
131
+ #define joinable_threads_lock () mono_coop_mutex_lock (&joinable_threads_mutex)
132
+ #define joinable_threads_unlock () mono_coop_mutex_unlock (&joinable_threads_mutex)
133
+ static MonoCoopMutex joinable_threads_mutex ;
134
134
135
135
/* Holds current status of static data heap */
136
136
static StaticDataInfo thread_static_info ;
@@ -161,10 +161,19 @@ static MonoGHashTable *threads_starting_up = NULL;
161
161
static GHashTable * joinable_threads ;
162
162
static gint32 joinable_thread_count ;
163
163
164
+ /* mono_threads_join_threads will take threads from joinable_threads list and wait for them. */
165
+ /* When this happens, the tid is not on the list anymore so mono_thread_join assumes the thread has complete */
166
+ /* and will return back to the caller. This could cause a race since caller of join assumes thread has completed */
167
+ /* and on some OS it could cause errors. Keeping the tid's currently pending a native thread join call */
168
+ /* in a separate table (only affecting callers interested in this internal join detail) and look at that table in mono_thread_join */
169
+ /* will close this race. */
170
+ static GHashTable * pending_native_thread_join_calls ;
171
+ static MonoCoopCond pending_native_thread_join_calls_event ;
172
+
164
173
static GHashTable * pending_joinable_threads ;
165
174
static gint32 pending_joinable_thread_count ;
166
175
167
- static mono_cond_t zero_pending_joinable_thread_event ;
176
+ static MonoCoopCond zero_pending_joinable_thread_event ;
168
177
169
178
static void threads_add_pending_joinable_runtime_thread (MonoThreadInfo * mono_thread_info );
170
179
static gboolean threads_wait_pending_joinable_threads (uint32_t timeout );
@@ -3036,11 +3045,12 @@ void mono_thread_init (MonoThreadStartCB start_cb,
3036
3045
mono_coop_mutex_init_recursive (& threads_mutex );
3037
3046
3038
3047
mono_os_mutex_init_recursive (& interlocked_mutex );
3039
- mono_os_mutex_init_recursive (& joinable_threads_mutex );
3048
+ mono_coop_mutex_init_recursive (& joinable_threads_mutex );
3040
3049
3041
3050
mono_os_event_init (& background_change_event , FALSE);
3042
3051
3043
- mono_os_cond_init (& zero_pending_joinable_thread_event );
3052
+ mono_coop_cond_init (& pending_native_thread_join_calls_event );
3053
+ mono_coop_cond_init (& zero_pending_joinable_thread_event );
3044
3054
3045
3055
mono_init_static_data_info (& thread_static_info );
3046
3056
mono_init_static_data_info (& context_static_info );
@@ -3161,7 +3171,8 @@ mono_thread_cleanup (void)
3161
3171
mono_os_mutex_destroy (& interlocked_mutex );
3162
3172
mono_os_mutex_destroy (& delayed_free_table_mutex );
3163
3173
mono_os_mutex_destroy (& small_id_mutex );
3164
- mono_os_cond_destroy (& zero_pending_joinable_runtime_thread_event );
3174
+ mono_coop_cond_destroy (& zero_pending_joinable_thread_event );
3175
+ mono_coop_cond_destroy (& pending_native_thread_join_calls_event );
3165
3176
mono_os_event_destroy (& background_change_event );
3166
3177
#endif
3167
3178
}
@@ -5280,7 +5291,7 @@ threads_remove_pending_joinable_thread_nolock (gpointer tid)
5280
5291
if (pending_joinable_threads && g_hash_table_lookup_extended (pending_joinable_threads , tid , & orig_key , & value )) {
5281
5292
g_hash_table_remove (pending_joinable_threads , tid );
5282
5293
if (UnlockedDecrement (& pending_joinable_thread_count ) == 0 )
5283
- mono_os_cond_broadcast (& zero_pending_joinable_thread_event );
5294
+ mono_coop_cond_broadcast (& zero_pending_joinable_thread_event );
5284
5295
}
5285
5296
}
5286
5297
@@ -5291,12 +5302,12 @@ threads_wait_pending_joinable_threads (uint32_t timeout)
5291
5302
joinable_threads_lock ();
5292
5303
if (timeout == MONO_INFINITE_WAIT ) {
5293
5304
while (UnlockedRead (& pending_joinable_thread_count ) > 0 )
5294
- mono_os_cond_wait (& zero_pending_joinable_thread_event , & joinable_threads_mutex );
5305
+ mono_coop_cond_wait (& zero_pending_joinable_thread_event , & joinable_threads_mutex );
5295
5306
} else {
5296
5307
gint64 start = mono_msec_ticks ();
5297
5308
gint64 elapsed = 0 ;
5298
5309
while (UnlockedRead (& pending_joinable_thread_count ) > 0 && elapsed < timeout ) {
5299
- mono_os_cond_timedwait (& zero_pending_joinable_thread_event , & joinable_threads_mutex , timeout - (uint32_t )elapsed );
5310
+ mono_coop_cond_timedwait (& zero_pending_joinable_thread_event , & joinable_threads_mutex , timeout - (uint32_t )elapsed );
5300
5311
elapsed = mono_msec_ticks () - start ;
5301
5312
}
5302
5313
}
@@ -5344,6 +5355,39 @@ mono_threads_add_joinable_runtime_thread (gpointer thread_info)
5344
5355
}
5345
5356
}
5346
5357
5358
+ static void
5359
+ threads_add_pending_native_thread_join_call_nolock (gpointer tid )
5360
+ {
5361
+ if (!pending_native_thread_join_calls )
5362
+ pending_native_thread_join_calls = g_hash_table_new (NULL , NULL );
5363
+
5364
+ gpointer orig_key ;
5365
+ gpointer value ;
5366
+
5367
+ if (!g_hash_table_lookup_extended (pending_native_thread_join_calls , tid , & orig_key , & value ))
5368
+ g_hash_table_insert (pending_native_thread_join_calls , tid , tid );
5369
+ }
5370
+
5371
+ static void
5372
+ threads_remove_pending_native_thread_join_call_nolock (gpointer tid )
5373
+ {
5374
+ if (pending_native_thread_join_calls )
5375
+ g_hash_table_remove (pending_native_thread_join_calls , tid );
5376
+
5377
+ mono_coop_cond_broadcast (& pending_native_thread_join_calls_event );
5378
+ }
5379
+
5380
+ static void
5381
+ threads_wait_pending_native_thread_join_call_nolock (gpointer tid )
5382
+ {
5383
+ gpointer orig_key ;
5384
+ gpointer value ;
5385
+
5386
+ while (g_hash_table_lookup_extended (pending_native_thread_join_calls , tid , & orig_key , & value )) {
5387
+ mono_coop_cond_wait (& pending_native_thread_join_calls_event , & joinable_threads_mutex );
5388
+ }
5389
+ }
5390
+
5347
5391
/*
5348
5392
* mono_add_joinable_thread:
5349
5393
*
@@ -5375,23 +5419,30 @@ void
5375
5419
mono_threads_join_threads (void )
5376
5420
{
5377
5421
GHashTableIter iter ;
5378
- gpointer key ;
5379
- gpointer value ;
5380
- gboolean found ;
5422
+ gpointer key = NULL ;
5423
+ gpointer value = NULL ;
5424
+ gboolean found = FALSE ;
5381
5425
5382
5426
/* Fastpath */
5383
5427
if (!UnlockedRead (& joinable_thread_count ))
5384
5428
return ;
5385
5429
5386
5430
while (TRUE) {
5387
5431
joinable_threads_lock ();
5432
+ if (found ) {
5433
+ // Previous native thread join call completed.
5434
+ threads_remove_pending_native_thread_join_call_nolock (key );
5435
+ }
5388
5436
found = FALSE;
5389
5437
if (g_hash_table_size (joinable_threads )) {
5390
5438
g_hash_table_iter_init (& iter , joinable_threads );
5391
5439
g_hash_table_iter_next (& iter , & key , (void * * )& value );
5392
5440
g_hash_table_remove (joinable_threads , key );
5393
5441
UnlockedDecrement (& joinable_thread_count );
5394
5442
found = TRUE;
5443
+
5444
+ // Add to table of tid's with pending native thread join call.
5445
+ threads_add_pending_native_thread_join_call_nolock (key );
5395
5446
}
5396
5447
joinable_threads_unlock ();
5397
5448
if (found )
@@ -5422,13 +5473,27 @@ mono_thread_join (gpointer tid)
5422
5473
g_hash_table_remove (joinable_threads , tid );
5423
5474
UnlockedDecrement (& joinable_thread_count );
5424
5475
found = TRUE;
5476
+
5477
+ // Add to table of tid's with pending native join call.
5478
+ threads_add_pending_native_thread_join_call_nolock (tid );
5479
+ }
5480
+
5481
+ if (!found ) {
5482
+ // Wait for any pending native thread join call not yet completed for this tid.
5483
+ threads_wait_pending_native_thread_join_call_nolock (tid );
5425
5484
}
5485
+
5426
5486
joinable_threads_unlock ();
5427
5487
5428
5488
if (!found )
5429
5489
return ;
5430
5490
5431
5491
threads_native_thread_join_nolock (tid , value );
5492
+
5493
+ joinable_threads_lock ();
5494
+ // Native thread join call completed for this tid.
5495
+ threads_remove_pending_native_thread_join_call_nolock (tid );
5496
+ joinable_threads_unlock ();
5432
5497
}
5433
5498
5434
5499
void
0 commit comments