Skip to content

Commit

Permalink
[release/8.0-staging] [mono] Fix class initialization spurious wakeups (
Browse files Browse the repository at this point in the history
#96905)

* 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

---------

Co-authored-by: Aleksey Kliger <alklig@microsoft.com>
  • Loading branch information
github-actions[bot] and lambdageek authored Jan 13, 2024
1 parent 279dd28 commit fe8a9d0
Showing 1 changed file with 10 additions and 7 deletions.
17 changes: 10 additions & 7 deletions src/mono/mono/metadata/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -458,21 +458,24 @@ mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
* on this cond var.
*/

HANDLE_FUNCTION_ENTER ();

retry_top:
(void)0; // appease C compiler; label must preceed a statement not a var declaration

gboolean ret = FALSE;

mono_type_initialization_lock ();
/* double check... */
if (vtable->initialized) {
mono_type_initialization_unlock ();
return TRUE;
goto return_true;
}

gboolean do_initialization = FALSE;
TypeInitializationLock *lock = NULL;
gboolean pending_tae = FALSE;

gboolean ret = FALSE;

HANDLE_FUNCTION_ENTER ();

if (vtable->init_failed) {
/* The type initialization already failed once, rethrow the same exception */
Expand Down Expand Up @@ -615,8 +618,8 @@ mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
if (!lock->done) {
int timeout_ms = 500;
int wait_result = mono_coop_cond_timedwait (&lock->cond, &lock->mutex, timeout_ms);
if (wait_result == -1) {
/* timed out - go around again from the beginning. If we got here
if (wait_result == -1 || (wait_result == 0 && !lock->done)) {
/* timed out or spurious wakeup - go around again from the beginning. If we got here
* from the "is_blocked = FALSE" case, above (another thread was
* blocked on the current thread, but on a lock that was already
* done but it didn't get to wake up yet), then it might still be
Expand Down Expand Up @@ -647,7 +650,7 @@ mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
g_hash_table_remove (type_initialization_hash, vtable);
mono_type_initialization_unlock ();
goto retry_top;
} else if (wait_result == 0) {
} else if (wait_result == 0 && lock->done) {
/* Success: we were signaled that the other thread is done. Proceed */
} else {
g_assert_not_reached ();
Expand Down

0 comments on commit fe8a9d0

Please sign in to comment.