Skip to content

Commit b610c99

Browse files
authored
[mono] Fix class initialization spurious wakeups (#96903)
* mono_runtime_class_init_full: handle spurious wakeups the condition variable may be signaled even if the initialization by the other thread is not done yet. Handle spurious wakeups the same way as timeouts: go around once more from the beginning. Fixes #96872 and #96804 * fix unbalanced handle frames if we goto retry_top, don't set up a new handle frame that lacks a matching HANDLE_FUNCTION_RETURN_VAL. Instead setup the handle frame once upfront
1 parent 283a2de commit b610c99

File tree

1 file changed

+10
-7
lines changed

1 file changed

+10
-7
lines changed

src/mono/mono/metadata/object.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -457,21 +457,24 @@ mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
457457
* on this cond var.
458458
*/
459459

460+
HANDLE_FUNCTION_ENTER ();
461+
460462
retry_top:
463+
(void)0; // appease C compiler; label must preceed a statement not a var declaration
464+
465+
gboolean ret = FALSE;
466+
461467
mono_type_initialization_lock ();
462468
/* double check... */
463469
if (vtable->initialized) {
464470
mono_type_initialization_unlock ();
465-
return TRUE;
471+
goto return_true;
466472
}
467473

468474
gboolean do_initialization = FALSE;
469475
TypeInitializationLock *lock = NULL;
470476
gboolean pending_tae = FALSE;
471477

472-
gboolean ret = FALSE;
473-
474-
HANDLE_FUNCTION_ENTER ();
475478

476479
if (vtable->init_failed) {
477480
/* The type initialization already failed once, rethrow the same exception */
@@ -614,8 +617,8 @@ mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
614617
if (!lock->done) {
615618
int timeout_ms = 500;
616619
int wait_result = mono_coop_cond_timedwait (&lock->cond, &lock->mutex, timeout_ms);
617-
if (wait_result == -1) {
618-
/* timed out - go around again from the beginning. If we got here
620+
if (wait_result == -1 || (wait_result == 0 && !lock->done)) {
621+
/* timed out or spurious wakeup - go around again from the beginning. If we got here
619622
* from the "is_blocked = FALSE" case, above (another thread was
620623
* blocked on the current thread, but on a lock that was already
621624
* done but it didn't get to wake up yet), then it might still be
@@ -646,7 +649,7 @@ mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
646649
g_hash_table_remove (type_initialization_hash, vtable);
647650
mono_type_initialization_unlock ();
648651
goto retry_top;
649-
} else if (wait_result == 0) {
652+
} else if (wait_result == 0 && lock->done) {
650653
/* Success: we were signaled that the other thread is done. Proceed */
651654
} else {
652655
g_assert_not_reached ();

0 commit comments

Comments
 (0)