The following can happen:
* Thread T1 starts initialization of C1
* Thread T2 starts initialization of C2
* T2 starts initialization of C1, it gets blocked on T1.
* T1 finishes initializing C1.
* T1 starts initialization of C3.
* T1 starts initialization of C2. It sees that T2 is
still blocked on T1, but its not actually blocked, since
C1 is finished. Still, we record that T1 is blocked.
* T3 starts initialization of C2, it gets into an infinite
loop in the while loop, since the blocked_thread_hash
now indicates that T1 and T2 are blocked on each other.
The solution is to not mark a thread as blocked, if its waiting
for a thread which is waiting on a finished lock. Fixes hangs
when running csc.
return TRUE;
}
/* see if the thread doing the initialization is already blocked on this thread */
+ gboolean is_blocked = TRUE;
blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
/* the thread doing the initialization is blocked on this thread,
but on a lock that has already been freed. It just hasn't got
time to awake */
+ is_blocked = FALSE;
break;
}
}
}
++lock->waiting_count;
/* record the fact that we are waiting on the initializing thread */
- g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
+ if (is_blocked)
+ g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
}
mono_type_initialization_unlock ();