MonoNativeThreadId tid;
int do_initialization = 0;
MonoDomain *last_domain = NULL;
+ MonoException * pending_tae = NULL;
mono_error_init (error);
if (do_initialization) {
MonoException *exc = NULL;
+ MonoInternalThread *thread = mono_thread_internal_current ();
+ ++thread->cctor_exec_depth;
+ mono_memory_barrier ();
mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
- if (exc != NULL && mono_error_ok (error)) {
- mono_error_set_exception_instance (error, exc);
- }
+ --thread->cctor_exec_depth;
+
+ //exception extracted, error will be set to the right value later
+ if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
+ exc = mono_error_convert_to_exception (error);
+ else
+ mono_error_cleanup (error);
+
+ mono_error_init (error);
/* If the initialization failed, mark the class as unusable. */
/* Avoid infinite loops */
- if (!(mono_error_ok(error) ||
+ if (!(!exc ||
(klass->image == mono_defaults.corlib &&
!strcmp (klass->name_space, "System") &&
!strcmp (klass->name, "TypeInitializationException")))) {
MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
g_free (full_name);
- return_val_if_nok (error, FALSE);
- mono_error_set_exception_instance (error, exc_to_throw);
+ mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
- MonoException *exc_to_store = mono_error_convert_to_exception (error);
- /* What we really want to do here is clone the error object and store one copy in the
- * domain's exception hash and use the other one to error out here. */
- mono_error_init (error);
- mono_error_set_exception_instance (error, exc_to_store);
/*
* Store the exception object so it could be thrown on subsequent
* accesses.
mono_domain_lock (domain);
if (!domain->type_init_exception_hash)
domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "type initialization exceptions table");
- mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_store);
+ mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
mono_domain_unlock (domain);
}
mono_domain_set (last_domain, TRUE);
lock->done = TRUE;
mono_type_init_unlock (lock);
+ if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class)
+ pending_tae = exc;
+ //TAEs are blocked around .cctors, they must escape as soon as no cctor is left to run.
+ if (!thread->cctor_exec_depth && !pending_tae && !mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ())
+ pending_tae = mono_thread_resume_interruption ();
} else {
/* this just blocks until the initializing thread is done */
mono_type_init_lock (lock);
vtable->initialized = 1;
mono_type_initialization_unlock ();
- if (vtable->init_failed) {
+ //TAE wins over TIE
+ if (pending_tae)
+ mono_error_set_exception_instance (error, pending_tae);
+ else if (vtable->init_failed) {
/* Either we were the initializing thread or we waited for the initialization */
mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
return FALSE;
/* Check that the managed and unmanaged layout of MonoInternalThread matches */
#ifndef MONO_CROSS_COMPILE
if (mono_check_corlib_version () == NULL)
- g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
+ g_assert (((char*)&internal->cctor_exec_depth - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
#endif
return internal;
if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
return MonoResumeThread;
+ /*
+ The target thread is running at least one .cctor, which must not be interrupted, so we give up.
+ The .cctor code will give them a chance when appropriate.
+ */
+ if (thread->cctor_exec_depth)
+ return MonoResumeThread;
+
/*someone is already interrupting it*/
if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
return MonoResumeThread;