@@ -127,9 +127,9 @@ static void mono_threads_unlock (void);
127
127
static MonoCoopMutex threads_mutex ;
128
128
129
129
/* Controls access to the 'joinable_threads' hash table */
130
- #define joinable_threads_lock () mono_os_mutex_lock (&joinable_threads_mutex)
131
- #define joinable_threads_unlock () mono_os_mutex_unlock (&joinable_threads_mutex)
132
- static mono_mutex_t joinable_threads_mutex ;
130
+ #define joinable_threads_lock () mono_coop_mutex_lock (&joinable_threads_mutex)
131
+ #define joinable_threads_unlock () mono_coop_mutex_unlock (&joinable_threads_mutex)
132
+ static MonoCoopMutex joinable_threads_mutex ;
133
133
134
134
/* Holds current status of static data heap */
135
135
static StaticDataInfo thread_static_info ;
@@ -163,10 +163,19 @@ static MonoGHashTable *threads_starting_up = NULL;
163
163
static GHashTable * joinable_threads ;
164
164
static gint32 joinable_thread_count ;
165
165
166
+ /* mono_threads_join_threads will take threads from joinable_threads list and wait for them. */
167
+ /* When this happens, the tid is not on the list anymore so mono_thread_join assumes the thread has complete */
168
+ /* and will return back to the caller. This could cause a race since caller of join assumes thread has completed */
169
+ /* and on some OS it could cause errors. Keeping the tid's currently pending a native thread join call */
170
+ /* in a separate table (only affecting callers interested in this internal join detail) and look at that table in mono_thread_join */
171
+ /* will close this race. */
172
+ static GHashTable * pending_native_thread_join_calls ;
173
+ static MonoCoopCond pending_native_thread_join_calls_event ;
174
+
166
175
static GHashTable * pending_joinable_threads ;
167
176
static gint32 pending_joinable_thread_count ;
168
177
169
- static mono_cond_t zero_pending_joinable_thread_event ;
178
+ static MonoCoopCond zero_pending_joinable_thread_event ;
170
179
171
180
static void threads_add_pending_joinable_runtime_thread (MonoThreadInfo * mono_thread_info );
172
181
static gboolean threads_wait_pending_joinable_threads (uint32_t timeout );
@@ -3184,11 +3193,12 @@ void mono_thread_init (MonoThreadStartCB start_cb,
3184
3193
mono_coop_mutex_init_recursive (& threads_mutex );
3185
3194
3186
3195
mono_os_mutex_init_recursive (& interlocked_mutex );
3187
- mono_os_mutex_init_recursive (& joinable_threads_mutex );
3196
+ mono_coop_mutex_init_recursive (& joinable_threads_mutex );
3188
3197
3189
3198
mono_os_event_init (& background_change_event , FALSE);
3190
3199
3191
- mono_os_cond_init (& zero_pending_joinable_thread_event );
3200
+ mono_coop_cond_init (& pending_native_thread_join_calls_event );
3201
+ mono_coop_cond_init (& zero_pending_joinable_thread_event );
3192
3202
3193
3203
mono_init_static_data_info (& thread_static_info );
3194
3204
mono_init_static_data_info (& context_static_info );
@@ -3325,7 +3335,8 @@ mono_thread_cleanup (void)
3325
3335
mono_os_mutex_destroy (& interlocked_mutex );
3326
3336
mono_os_mutex_destroy (& delayed_free_table_mutex );
3327
3337
mono_os_mutex_destroy (& small_id_mutex );
3328
- mono_os_cond_destroy (& zero_pending_joinable_runtime_thread_event );
3338
+ mono_coop_cond_destroy (& zero_pending_joinable_thread_event );
3339
+ mono_coop_cond_destroy (& pending_native_thread_join_calls_event );
3329
3340
mono_os_event_destroy (& background_change_event );
3330
3341
#endif
3331
3342
}
@@ -5594,7 +5605,7 @@ threads_remove_pending_joinable_thread_nolock (gpointer tid)
5594
5605
if (pending_joinable_threads && g_hash_table_lookup_extended (pending_joinable_threads , tid , & orig_key , & value )) {
5595
5606
g_hash_table_remove (pending_joinable_threads , tid );
5596
5607
if (UnlockedDecrement (& pending_joinable_thread_count ) == 0 )
5597
- mono_os_cond_broadcast (& zero_pending_joinable_thread_event );
5608
+ mono_coop_cond_broadcast (& zero_pending_joinable_thread_event );
5598
5609
}
5599
5610
}
5600
5611
@@ -5605,12 +5616,12 @@ threads_wait_pending_joinable_threads (uint32_t timeout)
5605
5616
joinable_threads_lock ();
5606
5617
if (timeout == MONO_INFINITE_WAIT ) {
5607
5618
while (UnlockedRead (& pending_joinable_thread_count ) > 0 )
5608
- mono_os_cond_wait (& zero_pending_joinable_thread_event , & joinable_threads_mutex );
5619
+ mono_coop_cond_wait (& zero_pending_joinable_thread_event , & joinable_threads_mutex );
5609
5620
} else {
5610
5621
gint64 start = mono_msec_ticks ();
5611
5622
gint64 elapsed = 0 ;
5612
5623
while (UnlockedRead (& pending_joinable_thread_count ) > 0 && elapsed < timeout ) {
5613
- mono_os_cond_timedwait (& zero_pending_joinable_thread_event , & joinable_threads_mutex , timeout - (uint32_t )elapsed );
5624
+ mono_coop_cond_timedwait (& zero_pending_joinable_thread_event , & joinable_threads_mutex , timeout - (uint32_t )elapsed );
5614
5625
elapsed = mono_msec_ticks () - start ;
5615
5626
}
5616
5627
}
@@ -5658,6 +5669,39 @@ mono_threads_add_joinable_runtime_thread (MonoThreadInfo *thread_info)
5658
5669
}
5659
5670
}
5660
5671
5672
+ static void
5673
+ threads_add_pending_native_thread_join_call_nolock (gpointer tid )
5674
+ {
5675
+ if (!pending_native_thread_join_calls )
5676
+ pending_native_thread_join_calls = g_hash_table_new (NULL , NULL );
5677
+
5678
+ gpointer orig_key ;
5679
+ gpointer value ;
5680
+
5681
+ if (!g_hash_table_lookup_extended (pending_native_thread_join_calls , tid , & orig_key , & value ))
5682
+ g_hash_table_insert (pending_native_thread_join_calls , tid , tid );
5683
+ }
5684
+
5685
+ static void
5686
+ threads_remove_pending_native_thread_join_call_nolock (gpointer tid )
5687
+ {
5688
+ if (pending_native_thread_join_calls )
5689
+ g_hash_table_remove (pending_native_thread_join_calls , tid );
5690
+
5691
+ mono_coop_cond_broadcast (& pending_native_thread_join_calls_event );
5692
+ }
5693
+
5694
+ static void
5695
+ threads_wait_pending_native_thread_join_call_nolock (gpointer tid )
5696
+ {
5697
+ gpointer orig_key ;
5698
+ gpointer value ;
5699
+
5700
+ while (g_hash_table_lookup_extended (pending_native_thread_join_calls , tid , & orig_key , & value )) {
5701
+ mono_coop_cond_wait (& pending_native_thread_join_calls_event , & joinable_threads_mutex );
5702
+ }
5703
+ }
5704
+
5661
5705
/*
5662
5706
* mono_add_joinable_thread:
5663
5707
*
@@ -5689,23 +5733,30 @@ void
5689
5733
mono_threads_join_threads (void )
5690
5734
{
5691
5735
GHashTableIter iter ;
5692
- gpointer key ;
5693
- gpointer value ;
5694
- gboolean found ;
5736
+ gpointer key = NULL ;
5737
+ gpointer value = NULL ;
5738
+ gboolean found = FALSE ;
5695
5739
5696
5740
/* Fastpath */
5697
5741
if (!UnlockedRead (& joinable_thread_count ))
5698
5742
return ;
5699
5743
5700
5744
while (TRUE) {
5701
5745
joinable_threads_lock ();
5746
+ if (found ) {
5747
+ // Previous native thread join call completed.
5748
+ threads_remove_pending_native_thread_join_call_nolock (key );
5749
+ }
5702
5750
found = FALSE;
5703
5751
if (g_hash_table_size (joinable_threads )) {
5704
5752
g_hash_table_iter_init (& iter , joinable_threads );
5705
5753
g_hash_table_iter_next (& iter , & key , (void * * )& value );
5706
5754
g_hash_table_remove (joinable_threads , key );
5707
5755
UnlockedDecrement (& joinable_thread_count );
5708
5756
found = TRUE;
5757
+
5758
+ // Add to table of tid's with pending native thread join call.
5759
+ threads_add_pending_native_thread_join_call_nolock (key );
5709
5760
}
5710
5761
joinable_threads_unlock ();
5711
5762
if (found )
@@ -5736,13 +5787,27 @@ mono_thread_join (gpointer tid)
5736
5787
g_hash_table_remove (joinable_threads , tid );
5737
5788
UnlockedDecrement (& joinable_thread_count );
5738
5789
found = TRUE;
5790
+
5791
+ // Add to table of tid's with pending native join call.
5792
+ threads_add_pending_native_thread_join_call_nolock (tid );
5793
+ }
5794
+
5795
+ if (!found ) {
5796
+ // Wait for any pending native thread join call not yet completed for this tid.
5797
+ threads_wait_pending_native_thread_join_call_nolock (tid );
5739
5798
}
5799
+
5740
5800
joinable_threads_unlock ();
5741
5801
5742
5802
if (!found )
5743
5803
return ;
5744
5804
5745
5805
threads_native_thread_join_nolock (tid , value );
5806
+
5807
+ joinable_threads_lock ();
5808
+ // Native thread join call completed for this tid.
5809
+ threads_remove_pending_native_thread_join_call_nolock (tid );
5810
+ joinable_threads_unlock ();
5746
5811
}
5747
5812
5748
5813
void
0 commit comments