diff options
Diffstat (limited to 'mono/metadata/threads.c')
-rwxr-xr-x | mono/metadata/threads.c | 1038 |
1 files changed, 523 insertions, 515 deletions
diff --git a/mono/metadata/threads.c b/mono/metadata/threads.c index a8720ba5bf..1b421c4a69 100755 --- a/mono/metadata/threads.c +++ b/mono/metadata/threads.c @@ -48,6 +48,7 @@ #include <mono/utils/hazard-pointer.h> #include <mono/utils/mono-tls.h> #include <mono/utils/atomic.h> +#include <mono/utils/mono-memory-model.h> #include <mono/metadata/gc-internal.h> @@ -77,6 +78,9 @@ size_t pthread_get_stacksize_np(pthread_t); #define SPIN_UNLOCK(i) i = 0 +#define LOCK_THREAD(thread) lock_thread((thread)) +#define UNLOCK_THREAD(thread) unlock_thread((thread)) + /* Provide this for systems with glib < 2.6 */ #ifndef G_GSIZE_FORMAT # if GLIB_SIZEOF_LONG == 8 @@ -86,13 +90,13 @@ size_t pthread_get_stacksize_np(pthread_t); # endif #endif -struct StartInfo +typedef struct { guint32 (*func)(void *); MonoThread *obj; MonoObject *delegate; void *start_arg; -}; +} StartInfo; typedef union { gint32 ival; @@ -194,7 +198,6 @@ static void mono_free_static_data (gpointer* static_data, gboolean threadlocal); static void mono_init_static_data_info (StaticDataInfo *static_data); static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align); static gboolean mono_thread_resume (MonoInternalThread* thread); -static void mono_thread_start (MonoThread *thread); static void signal_thread_state_change (MonoInternalThread *thread); static void abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort); static void suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt); @@ -323,14 +326,14 @@ static gboolean handle_remove(MonoInternalThread *thread) static void ensure_synch_cs_set (MonoInternalThread *thread) { CRITICAL_SECTION *synch_cs; - + if (thread->synch_cs != NULL) { return; } - + synch_cs = g_new0 (CRITICAL_SECTION, 1); InitializeCriticalSection (synch_cs); - + if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs, synch_cs, NULL) != NULL) { /* Another thread must have installed this CS */ @@ -339,6 +342,22 @@ static void ensure_synch_cs_set (MonoInternalThread *thread) } } +static inline void +lock_thread (MonoInternalThread *thread) +{ + if (!thread->synch_cs) + ensure_synch_cs_set (thread); + + g_assert (thread->synch_cs); + EnterCriticalSection (thread->synch_cs); +} + +static inline void +unlock_thread (MonoInternalThread *thread) +{ + LeaveCriticalSection (thread->synch_cs); +} + /* * NOTE: this function can be called also for threads different from the current one: * make sure no code called from it will ever assume it is run on the thread that is @@ -366,14 +385,16 @@ static void thread_cleanup (MonoInternalThread *thread) mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL); } - ensure_synch_cs_set (thread); - - EnterCriticalSection (thread->synch_cs); + if (thread->synch_cs) + LOCK_THREAD (thread); + else + g_assert (shutting_down); thread->state |= ThreadState_Stopped; thread->state &= ~ThreadState_Background; - LeaveCriticalSection (thread->synch_cs); + if (thread->synch_cs) + UNLOCK_THREAD (thread); /* An interruption request has leaked to cleanup. Adjust the global counter. @@ -429,7 +450,6 @@ static void thread_cleanup (MonoInternalThread *thread) MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref); thread->thread_pinning_ref = NULL; } - } static gpointer @@ -474,13 +494,6 @@ set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, M *current_thread_ptr = current; } -static MonoInternalThread* -create_internal_thread_object (void) -{ - MonoVTable *vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class); - return (MonoInternalThread*)mono_gc_alloc_mature (vt); -} - static MonoThread* create_thread_object (MonoDomain *domain) { @@ -496,6 +509,28 @@ new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal) return thread; } +static MonoInternalThread* +create_internal_thread (void) +{ + MonoInternalThread *thread; + MonoVTable *vt; + + vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class); + thread = (MonoInternalThread*)mono_gc_alloc_mature (vt); + + thread->synch_cs = g_new0 (CRITICAL_SECTION, 1); + InitializeCriticalSection (thread->synch_cs); + + thread->apartment_state = ThreadApartmentState_Unknown; + thread->managed_id = get_next_managed_thread_id (); + if (mono_gc_is_moving ()) { + thread->thread_pinning_ref = thread; + MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref); + } + + return thread; +} + static void init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate) { @@ -511,7 +546,7 @@ init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate) static guint32 WINAPI start_wrapper_internal(void *data) { MonoThreadInfo *info; - struct StartInfo *start_info=(struct StartInfo *)data; + StartInfo *start_info = (StartInfo *)data; guint32 (*start_func)(void *); void *start_arg; gsize tid; @@ -653,106 +688,53 @@ static guint32 WINAPI start_wrapper(void *data) return start_wrapper_internal (data); } -void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func) -{ - if (mono_thread_start_cb) { - mono_thread_start_cb (tid, stack_start, func); - } -} - -void mono_threads_set_default_stacksize (guint32 stacksize) -{ - default_stacksize = stacksize; -} - -guint32 mono_threads_get_default_stacksize (void) -{ - return default_stacksize; -} - /* - * mono_create_thread: + * create_thread: * - * This is a wrapper around CreateThread which handles differences in the type of - * the the 'tid' argument. + * Common thread creation code. + * LOCKING: Acquires the threads lock. */ -gpointer mono_create_thread (WapiSecurityAttributes *security, - guint32 stacksize, WapiThreadStart start, - gpointer param, guint32 create, gsize *tid) -{ - gpointer res; - -#ifdef HOST_WIN32 - DWORD real_tid; - - res = mono_threads_CreateThread (security, stacksize, start, param, create, &real_tid); - if (tid) - *tid = real_tid; -#else - res = CreateThread (security, stacksize, start, param, create, tid); -#endif - - return res; -} - -/* - * The thread start argument may be an object reference, and there is - * no ref to keep it alive when the new thread is started but not yet - * registered with the collector. So we store it in a GC tracked hash - * table. - * - * LOCKING: Assumes the threads lock is held. - */ -static void -register_thread_start_argument (MonoThread *thread, struct StartInfo *start_info) -{ - if (thread_start_args == NULL) { - MONO_GC_REGISTER_ROOT_FIXED (thread_start_args); - thread_start_args = mono_g_hash_table_new (NULL, NULL); - } - mono_g_hash_table_insert (thread_start_args, thread, start_info->start_arg); -} - -/* - * mono_thread_create_internal: - * - * If NO_DETACH is TRUE, then the thread is not detached using pthread_detach (). This is needed to fix the race condition where waiting for a thred to exit only waits for its exit event to be - * signalled, which can cause shutdown crashes if the thread shutdown code accesses data already freed by the runtime shutdown. - * Currently, this is only used for the finalizer thread. - */ -MonoInternalThread* -mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, gboolean no_detach, guint32 stack_size) +static gboolean +create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *start_info, gboolean threadpool_thread, gboolean no_detach, guint32 stack_size, + gboolean throw_on_failure) { - MonoThread *thread; - MonoInternalThread *internal; HANDLE thread_handle; - struct StartInfo *start_info; - gsize tid; + MonoNativeThreadId tid; guint32 create_flags; - thread = create_thread_object (domain); - internal = create_internal_thread_object (); - MONO_OBJECT_SETREF (thread, internal_thread, internal); - - start_info=g_new0 (struct StartInfo, 1); - start_info->func = func; - start_info->obj = thread; - start_info->start_arg = arg; - mono_threads_lock (); if (shutting_down) { - mono_threads_unlock (); g_free (start_info); - return NULL; + mono_threads_unlock (); + return FALSE; + } + /* + * The thread start argument may be an object reference, and there is + * no ref to keep it alive when the new thread is started but not yet + * registered with the collector. So we store it in a GC tracked hash + * table. + */ + if (thread_start_args == NULL) { + MONO_GC_REGISTER_ROOT_FIXED (thread_start_args); + thread_start_args = mono_g_hash_table_new (NULL, NULL); } + mono_g_hash_table_insert (thread_start_args, thread, start_info->start_arg); if (threads_starting_up == NULL) { MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up); threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC); } + mono_g_hash_table_insert (threads_starting_up, thread, thread); + mono_threads_unlock (); - register_thread_start_argument (thread, start_info); - mono_g_hash_table_insert (threads_starting_up, thread, thread); - mono_threads_unlock (); + internal->start_notify = CreateSemaphore (NULL, 0, 0x7fffffff, NULL); + if (!internal->start_notify) { + mono_threads_lock (); + mono_g_hash_table_remove (threads_starting_up, thread); + mono_threads_unlock (); + g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ()); + g_free (start_info); + return FALSE; + } if (stack_size == 0) stack_size = default_stacksize_for_thread (internal); @@ -765,37 +747,103 @@ mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gb if (no_detach) create_flags |= CREATE_NO_DETACH; #endif - thread_handle = mono_create_thread (NULL, stack_size, (LPTHREAD_START_ROUTINE)start_wrapper, start_info, - create_flags, &tid); - THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle)); + thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)start_wrapper, start_info, + stack_size, create_flags, &tid); if (thread_handle == NULL) { /* The thread couldn't be created, so throw an exception */ mono_threads_lock (); mono_g_hash_table_remove (threads_starting_up, thread); mono_threads_unlock (); g_free (start_info); - mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread")); - return NULL; - } - - internal->handle=thread_handle; - internal->tid=tid; - internal->apartment_state=ThreadApartmentState_Unknown; - internal->managed_id = get_next_managed_thread_id (); - if (mono_gc_is_moving ()) { - internal->thread_pinning_ref = internal; - MONO_GC_REGISTER_ROOT_PINNING (internal->thread_pinning_ref); + if (throw_on_failure) + mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread")); + else + g_warning ("%s: CreateThread error 0x%x", __func__, GetLastError ()); + return FALSE; } + THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle)); - internal->synch_cs = g_new0 (CRITICAL_SECTION, 1); - InitializeCriticalSection (internal->synch_cs); + internal->handle = thread_handle; + internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid); internal->threadpool_thread = threadpool_thread; if (threadpool_thread) mono_thread_set_state (internal, ThreadState_Background); - if (handle_store (thread, FALSE)) - ResumeThread (thread_handle); + THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid)); + + /* Only store the handle when the thread is about to be + * launched, to avoid the main thread deadlocking while trying + * to clean up a thread that will never be signalled. + */ + if (!handle_store (thread, FALSE)) + return FALSE; + + ResumeThread (internal->handle); + + if (internal->start_notify) { + /* + * Wait for the thread to set up its TLS data etc, so + * theres no potential race condition if someone tries + * to look up the data believing the thread has + * started + */ + THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid)); + + WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE); + CloseHandle (internal->start_notify); + internal->start_notify = NULL; + } + + THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid)); + + return TRUE; +} + +void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func) +{ + if (mono_thread_start_cb) { + mono_thread_start_cb (tid, stack_start, func); + } +} + +void mono_threads_set_default_stacksize (guint32 stacksize) +{ + default_stacksize = stacksize; +} + +guint32 mono_threads_get_default_stacksize (void) +{ + return default_stacksize; +} + +/* + * mono_thread_create_internal: + * + * If NO_DETACH is TRUE, then the thread is not detached using pthread_detach (). This is needed to fix the race condition where waiting for a thred to exit only waits for its exit event to be + * signalled, which can cause shutdown crashes if the thread shutdown code accesses data already freed by the runtime shutdown. + * Currently, this is only used for the finalizer thread. + */ +MonoInternalThread* +mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, gboolean no_detach, guint32 stack_size) +{ + MonoThread *thread; + MonoInternalThread *internal; + StartInfo *start_info; + gboolean res; + + thread = create_thread_object (domain); + internal = create_internal_thread (); + MONO_OBJECT_SETREF (thread, internal_thread, internal); + + start_info = g_new0 (StartInfo, 1); + start_info->func = func; + start_info->obj = thread; + start_info->start_arg = arg; + + res = create_thread (thread, internal, start_info, threadpool_thread, no_detach, stack_size, TRUE); + if (!res) + return NULL; /* Check that the managed and unmanaged layout of MonoInternalThread matches */ if (mono_check_corlib_version () == NULL) @@ -810,9 +858,8 @@ mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg) mono_thread_create_internal (domain, func, arg, FALSE, FALSE, 0); } -#if defined(HOST_WIN32) && defined(__GNUC__) +#if defined(HOST_WIN32) && HAVE_DECL___READFSDWORD==0 static __inline__ __attribute__((always_inline)) -/* This is not defined by gcc */ unsigned long long __readfsdword (unsigned long offset) { @@ -849,6 +896,17 @@ mono_thread_get_stack_bounds (guint8 **staddr, size_t *stsize) *staddr = (guint8*)pthread_get_stackaddr_np (pthread_self()); *stsize = pthread_get_stacksize_np (pthread_self()); + +#ifdef TARGET_OSX + /* + * Mavericks reports stack sizes as 512kb: + * http://permalink.gmane.org/gmane.comp.java.openjdk.hotspot.devel/11590 + * https://bugs.openjdk.java.net/browse/JDK-8020753 + */ + if (*stsize == 512 * 1024) + *stsize = 2048 * mono_pagesize (); +#endif + /* staddr points to the start of the stack, not the end */ *staddr -= *stsize; @@ -964,7 +1022,7 @@ mono_thread_attach_full (MonoDomain *domain, gboolean force_attach) g_error ("Thread %"G_GSIZE_FORMAT" calling into managed code is not registered with the GC. On UNIX, this can be fixed by #include-ing <gc.h> before <pthread.h> in the file containing the thread creation code.", GetCurrentThreadId ()); } - thread = create_internal_thread_object (); + thread = create_internal_thread (); thread_handle = GetCurrentThread (); g_assert (thread_handle); @@ -983,18 +1041,8 @@ mono_thread_attach_full (MonoDomain *domain, gboolean force_attach) #ifdef PLATFORM_ANDROID thread->android_tid = (gpointer) gettid (); #endif - thread->apartment_state=ThreadApartmentState_Unknown; - thread->managed_id = get_next_managed_thread_id (); - if (mono_gc_is_moving ()) { - thread->thread_pinning_ref = thread; - MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref); - } - thread->stack_ptr = &tid; - thread->synch_cs = g_new0 (CRITICAL_SECTION, 1); - InitializeCriticalSection (thread->synch_cs); - THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle)); info = mono_thread_info_current (); @@ -1079,23 +1127,20 @@ mono_thread_exit () void ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this) { - MonoInternalThread *internal = create_internal_thread_object (); + MonoInternalThread *internal = create_internal_thread (); internal->state = ThreadState_Unstarted; - internal->apartment_state = ThreadApartmentState_Unknown; - internal->managed_id = get_next_managed_thread_id (); InterlockedCompareExchangePointer ((gpointer)&this->internal_thread, internal, NULL); } -HANDLE ves_icall_System_Threading_Thread_Thread_internal(MonoThread *this, - MonoObject *start) +HANDLE +ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this, + MonoObject *start) { - guint32 (*start_func)(void *); - struct StartInfo *start_info; - HANDLE thread; - gsize tid; + StartInfo *start_info; MonoInternalThread *internal; + gboolean res; THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this, start)); @@ -1103,87 +1148,48 @@ HANDLE ves_icall_System_Threading_Thread_Thread_internal(MonoThread *this, ves_icall_System_Threading_Thread_ConstructInternalThread (this); internal = this->internal_thread; - ensure_synch_cs_set (internal); - - EnterCriticalSection (internal->synch_cs); + LOCK_THREAD (internal); if ((internal->state & ThreadState_Unstarted) == 0) { - LeaveCriticalSection (internal->synch_cs); + UNLOCK_THREAD (internal); mono_raise_exception (mono_get_exception_thread_state ("Thread has already been started.")); return NULL; } if ((internal->state & ThreadState_Aborted) != 0) { - LeaveCriticalSection (internal->synch_cs); + UNLOCK_THREAD (internal); return this; } - start_func = NULL; - { - /* This is freed in start_wrapper */ - start_info = g_new0 (struct StartInfo, 1); - start_info->func = start_func; - start_info->start_arg = this->start_obj; /* FIXME: GC object stored in unmanaged memory */ - start_info->delegate = start; - start_info->obj = this; - g_assert (this->obj.vtable->domain == mono_domain_get ()); - - internal->start_notify=CreateSemaphore (NULL, 0, 0x7fffffff, NULL); - if (internal->start_notify==NULL) { - LeaveCriticalSection (internal->synch_cs); - g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ()); - g_free (start_info); - return(NULL); - } - - mono_threads_lock (); - register_thread_start_argument (this, start_info); - if (threads_starting_up == NULL) { - MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up); - threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC); - } - mono_g_hash_table_insert (threads_starting_up, this, this); - mono_threads_unlock (); - - thread=mono_create_thread(NULL, default_stacksize_for_thread (internal), (LPTHREAD_START_ROUTINE)start_wrapper, start_info, - CREATE_SUSPENDED, &tid); - if(thread==NULL) { - LeaveCriticalSection (internal->synch_cs); - mono_threads_lock (); - mono_g_hash_table_remove (threads_starting_up, this); - mono_threads_unlock (); - g_warning("%s: CreateThread error 0x%x", __func__, GetLastError()); - return(NULL); - } - - internal->handle=thread; - internal->tid=tid; - if (mono_gc_is_moving ()) { - internal->thread_pinning_ref = internal; - MONO_GC_REGISTER_ROOT_PINNING (internal->thread_pinning_ref); - } - - - /* Don't call handle_store() here, delay it to Start. - * We can't join a thread (trying to will just block - * forever) until it actually starts running, so don't - * store the handle till then. - */ + /* This is freed in start_wrapper */ + start_info = g_new0 (StartInfo, 1); + start_info->func = NULL; + start_info->start_arg = this->start_obj; /* FIXME: GC object stored in unmanaged memory */ + start_info->delegate = start; + start_info->obj = this; + g_assert (this->obj.vtable->domain == mono_domain_get ()); + + res = create_thread (this, internal, start_info, FALSE, FALSE, 0, FALSE); + if (!res) { + UNLOCK_THREAD (internal); + return NULL; + } - mono_thread_start (this); - - internal->state &= ~ThreadState_Unstarted; + internal->state &= ~ThreadState_Unstarted; - THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread)); + THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread)); - LeaveCriticalSection (internal->synch_cs); - return(thread); - } + UNLOCK_THREAD (internal); + return internal->handle; } -void ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this, HANDLE thread) +/* + * This is called from the finalizer of the internal thread object. Since threads keep a reference to their + * thread object while running, by the time this function is called, the thread has already exited/detached, + * i.e. thread_cleanup () has ran. + */ +void +ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this, HANDLE thread) { - MONO_ARCH_SAVE_REGS; - THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread)); if (thread) @@ -1203,38 +1209,6 @@ void ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInterna } } -static void mono_thread_start (MonoThread *thread) -{ - MonoInternalThread *internal = thread->internal_thread; - - THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid)); - - /* Only store the handle when the thread is about to be - * launched, to avoid the main thread deadlocking while trying - * to clean up a thread that will never be signalled. - */ - if (!handle_store (thread, FALSE)) - return; - - ResumeThread (internal->handle); - - if(internal->start_notify!=NULL) { - /* Wait for the thread to set up its TLS data etc, so - * theres no potential race condition if someone tries - * to look up the data believing the thread has - * started - */ - - THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid)); - - WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE); - CloseHandle (internal->start_notify); - internal->start_notify = NULL; - } - - THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid)); -} - void ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms) { guint32 res; @@ -1273,8 +1247,6 @@ void ves_icall_System_Threading_Thread_SpinWait_nop (void) gint32 ves_icall_System_Threading_Thread_GetDomainID (void) { - MONO_ARCH_SAVE_REGS; - return mono_domain_get()->domain_id; } @@ -1300,9 +1272,7 @@ mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len) { gunichar2 *res; - ensure_synch_cs_set (this_obj); - - EnterCriticalSection (this_obj->synch_cs); + LOCK_THREAD (this_obj); if (!this_obj->name) { *name_len = 0; @@ -1313,7 +1283,7 @@ mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len) memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len); } - LeaveCriticalSection (this_obj->synch_cs); + UNLOCK_THREAD (this_obj); return res; } @@ -1323,16 +1293,14 @@ ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj { MonoString* str; - ensure_synch_cs_set (this_obj); - - EnterCriticalSection (this_obj->synch_cs); + LOCK_THREAD (this_obj); if (!this_obj->name) str = NULL; else str = mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len); - LeaveCriticalSection (this_obj->synch_cs); + UNLOCK_THREAD (this_obj); return str; } @@ -1340,12 +1308,10 @@ ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj void mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed) { - ensure_synch_cs_set (this_obj); - - EnterCriticalSection (this_obj->synch_cs); + LOCK_THREAD (this_obj); if (this_obj->flags & MONO_THREAD_FLAG_NAME_SET) { - LeaveCriticalSection (this_obj->synch_cs); + UNLOCK_THREAD (this_obj); mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once.")); return; @@ -1361,7 +1327,8 @@ mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, g if (managed) this_obj->flags |= MONO_THREAD_FLAG_NAME_SET; - LeaveCriticalSection (this_obj->synch_cs); + UNLOCK_THREAD (this_obj); + if (this_obj->name) { char *tname = mono_string_to_utf8 (name); mono_profiler_thread_name (this_obj->tid, tname); @@ -1389,7 +1356,7 @@ byte_array_to_domain (MonoArray *arr, MonoDomain *domain) return arr; copy = mono_array_new (domain, mono_defaults.byte_class, arr->max_length); - mono_gc_memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length); + memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length); return copy; } @@ -1438,18 +1405,16 @@ gboolean ves_icall_System_Threading_Thread_Join_internal(MonoInternalThread *thi mono_thread_current_check_pending_interrupt (); - ensure_synch_cs_set (this); - - EnterCriticalSection (this->synch_cs); + LOCK_THREAD (this); if ((this->state & ThreadState_Unstarted) != 0) { - LeaveCriticalSection (this->synch_cs); + UNLOCK_THREAD (this); mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started.")); return FALSE; } - LeaveCriticalSection (this->synch_cs); + UNLOCK_THREAD (this); if(ms== -1) { ms=INFINITE; @@ -1640,8 +1605,6 @@ ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, H guint32 ret; MonoInternalThread *thread = mono_thread_internal_current (); - MONO_ARCH_SAVE_REGS; - if (ms == -1) ms = INFINITE; @@ -1660,8 +1623,6 @@ HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, { HANDLE mutex; - MONO_ARCH_SAVE_REGS; - *created = TRUE; if (name == NULL) { @@ -1678,8 +1639,6 @@ HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, } MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) { - MONO_ARCH_SAVE_REGS; - return(ReleaseMutex (handle)); } @@ -1689,8 +1648,6 @@ HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name, { HANDLE ret; - MONO_ARCH_SAVE_REGS; - *error = ERROR_SUCCESS; ret = OpenMutex (rights, FALSE, mono_string_chars (name)); @@ -1706,8 +1663,6 @@ HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 ini { HANDLE sem; - MONO_ARCH_SAVE_REGS; - *created = TRUE; if (name == NULL) { @@ -1728,8 +1683,6 @@ gint32 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE ha { gint32 prevcount; - MONO_ARCH_SAVE_REGS; - *fail = !ReleaseSemaphore (handle, releaseCount, &prevcount); return (prevcount); @@ -1739,8 +1692,6 @@ HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString * { HANDLE ret; - MONO_ARCH_SAVE_REGS; - *error = ERROR_SUCCESS; ret = OpenSemaphore (rights, FALSE, mono_string_chars (name)); @@ -1755,8 +1706,6 @@ HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manua { HANDLE event; - MONO_ARCH_SAVE_REGS; - *created = TRUE; if (name == NULL) { @@ -1774,21 +1723,15 @@ HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manua } gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) { - MONO_ARCH_SAVE_REGS; - return (SetEvent(handle)); } gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) { - MONO_ARCH_SAVE_REGS; - return (ResetEvent(handle)); } void ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) { - MONO_ARCH_SAVE_REGS; - CloseHandle (handle); } @@ -1798,8 +1741,6 @@ HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name, { HANDLE ret; - MONO_ARCH_SAVE_REGS; - *error = ERROR_SUCCESS; ret = OpenEvent (rights, FALSE, mono_string_chars (name)); @@ -1812,53 +1753,46 @@ HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name, gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location) { - MONO_ARCH_SAVE_REGS; - return InterlockedIncrement (location); } gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location) { - gint64 ret; - - MONO_ARCH_SAVE_REGS; - - mono_interlocked_lock (); - - ret = ++ *location; - - mono_interlocked_unlock (); - - - return ret; +#if SIZEOF_VOID_P == 4 + if (G_UNLIKELY ((size_t)location & 0x7)) { + gint64 ret; + mono_interlocked_lock (); + (*location)++; + ret = *location; + mono_interlocked_unlock (); + return ret; + } +#endif + return InterlockedIncrement64 (location); } gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location) { - MONO_ARCH_SAVE_REGS; - return InterlockedDecrement(location); } gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location) { - gint64 ret; - - MONO_ARCH_SAVE_REGS; - - mono_interlocked_lock (); - - ret = -- *location; - - mono_interlocked_unlock (); - - return ret; +#if SIZEOF_VOID_P == 4 + if (G_UNLIKELY ((size_t)location & 0x7)) { + gint64 ret; + mono_interlocked_lock (); + (*location)--; + ret = *location; + mono_interlocked_unlock (); + return ret; + } +#endif + return InterlockedDecrement64 (location); } gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value) { - MONO_ARCH_SAVE_REGS; - return InterlockedExchange(location, value); } @@ -1879,8 +1813,6 @@ gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, { IntFloatUnion val, ret; - MONO_ARCH_SAVE_REGS; - val.fval = value; ret.ival = InterlockedExchange((gint32 *) location, val.ival); @@ -1890,54 +1822,32 @@ gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gint64 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value) { -#if SIZEOF_VOID_P == 8 - return (gint64) InterlockedExchangePointer((gpointer *) location, (gpointer)value); -#else - gint64 res; - - /* - * According to MSDN, this function is only atomic with regards to the - * other Interlocked functions on 32 bit platforms. - */ - mono_interlocked_lock (); - res = *location; - *location = value; - mono_interlocked_unlock (); - - return res; +#if SIZEOF_VOID_P == 4 + if (G_UNLIKELY ((size_t)location & 0x7)) { + gint64 ret; + mono_interlocked_lock (); + ret = *location; + *location = value; + mono_interlocked_unlock (); + return ret; + } #endif + return InterlockedExchange64 (location, value); } gdouble ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value) { -#if SIZEOF_VOID_P == 8 LongDoubleUnion val, ret; val.fval = value; - ret.ival = (gint64)InterlockedExchangePointer((gpointer *) location, (gpointer)val.ival); + ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival); return ret.fval; -#else - gdouble res; - - /* - * According to MSDN, this function is only atomic with regards to the - * other Interlocked functions on 32 bit platforms. - */ - mono_interlocked_lock (); - res = *location; - *location = value; - mono_interlocked_unlock (); - - return res; -#endif } gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand) { - MONO_ARCH_SAVE_REGS; - return InterlockedCompareExchange(location, value, comparand); } @@ -1958,8 +1868,6 @@ gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *lo { IntFloatUnion val, ret, cmp; - MONO_ARCH_SAVE_REGS; - val.fval = value; cmp.fval = comparand; ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival); @@ -1995,7 +1903,7 @@ gint64 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand) { #if SIZEOF_VOID_P == 4 - if ((size_t)location & 0x7) { + if (G_UNLIKELY ((size_t)location & 0x7)) { gint64 old; mono_interlocked_lock (); old = *location; @@ -2029,63 +1937,44 @@ ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoOb gint32 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value) { -#if SIZEOF_VOID_P == 8 - /* Should be implemented as a JIT intrinsic */ - mono_raise_exception (mono_get_exception_not_implemented (NULL)); - return 0; -#else - gint32 orig; - - mono_interlocked_lock (); - orig = *location; - *location = orig + value; - mono_interlocked_unlock (); - - return orig + value; -#endif + return InterlockedAdd (location, value); } gint64 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value) { -#if SIZEOF_VOID_P == 8 - /* Should be implemented as a JIT intrinsic */ - mono_raise_exception (mono_get_exception_not_implemented (NULL)); - return 0; -#else - gint64 orig; - - mono_interlocked_lock (); - orig = *location; - *location = orig + value; - mono_interlocked_unlock (); - - return orig + value; +#if SIZEOF_VOID_P == 4 + if (G_UNLIKELY ((size_t)location & 0x7)) { + gint64 ret; + mono_interlocked_lock (); + *location += value; + ret = *location; + mono_interlocked_unlock (); + return ret; + } #endif + return InterlockedAdd64 (location, value); } gint64 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location) { -#if SIZEOF_VOID_P == 8 - /* 64 bit reads are already atomic */ - return *location; -#else - gint64 res; - - mono_interlocked_lock (); - res = *location; - mono_interlocked_unlock (); - - return res; +#if SIZEOF_VOID_P == 4 + if (G_UNLIKELY ((size_t)location & 0x7)) { + gint64 ret; + mono_interlocked_lock (); + ret = *location; + mono_interlocked_unlock (); + return ret; + } #endif + return InterlockedRead64 (location); } void ves_icall_System_Threading_Thread_MemoryBarrier (void) { - mono_threads_lock (); - mono_threads_unlock (); + mono_memory_barrier (); } void @@ -2121,13 +2010,11 @@ ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this) { guint32 state; - ensure_synch_cs_set (this); - - EnterCriticalSection (this->synch_cs); + LOCK_THREAD (this); state = this->state; - LeaveCriticalSection (this->synch_cs); + UNLOCK_THREAD (this); return state; } @@ -2137,16 +2024,14 @@ void ves_icall_System_Threading_Thread_Interrupt_internal (MonoInternalThread *t MonoInternalThread *current; gboolean throw; - ensure_synch_cs_set (this); + LOCK_THREAD (this); current = mono_thread_internal_current (); - EnterCriticalSection (this->synch_cs); - this->thread_interrupt_requested = TRUE; throw = current != this && (this->state & ThreadState_WaitSleepJoin); - LeaveCriticalSection (this->synch_cs); + UNLOCK_THREAD (this); if (throw) { abort_thread_internal (this, TRUE, FALSE); @@ -2158,18 +2043,14 @@ void mono_thread_current_check_pending_interrupt () MonoInternalThread *thread = mono_thread_internal_current (); gboolean throw = FALSE; - mono_debugger_check_interruption (); - - ensure_synch_cs_set (thread); - - EnterCriticalSection (thread->synch_cs); + LOCK_THREAD (thread); if (thread->thread_interrupt_requested) { throw = TRUE; thread->thread_interrupt_requested = FALSE; } - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); if (throw) { mono_raise_exception (mono_get_exception_thread_interrupted ()); @@ -2251,21 +2132,19 @@ static void signal_thread_state_change (MonoInternalThread *thread) void ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state) { - ensure_synch_cs_set (thread); - - EnterCriticalSection (thread->synch_cs); + LOCK_THREAD (thread); if ((thread->state & ThreadState_AbortRequested) != 0 || (thread->state & ThreadState_StopRequested) != 0 || (thread->state & ThreadState_Stopped) != 0) { - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); return; } if ((thread->state & ThreadState_Unstarted) != 0) { thread->state |= ThreadState_Aborted; - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); return; } @@ -2288,7 +2167,7 @@ ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject * a problem. */ - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid)); @@ -2306,12 +2185,10 @@ ves_icall_System_Threading_Thread_ResetAbort (void) MonoInternalThread *thread = mono_thread_internal_current (); gboolean was_aborting; - ensure_synch_cs_set (thread); - - EnterCriticalSection (thread->synch_cs); + LOCK_THREAD (thread); was_aborting = thread->state & ThreadState_AbortRequested; thread->state &= ~ThreadState_AbortRequested; - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); if (!was_aborting) { const char *msg = "Unable to reset abort because no abort was requested"; @@ -2329,9 +2206,7 @@ ves_icall_System_Threading_Thread_ResetAbort (void) void mono_thread_internal_reset_abort (MonoInternalThread *thread) { - ensure_synch_cs_set (thread); - - EnterCriticalSection (thread->synch_cs); + LOCK_THREAD (thread); thread->state &= ~ThreadState_AbortRequested; @@ -2345,7 +2220,7 @@ mono_thread_internal_reset_abort (MonoInternalThread *thread) } } - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); } MonoObject* @@ -2380,15 +2255,13 @@ ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this) static gboolean mono_thread_suspend (MonoInternalThread *thread) { - ensure_synch_cs_set (thread); - - EnterCriticalSection (thread->synch_cs); + LOCK_THREAD (thread); if ((thread->state & ThreadState_Unstarted) != 0 || (thread->state & ThreadState_Aborted) != 0 || (thread->state & ThreadState_Stopped) != 0) { - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); return FALSE; } @@ -2396,13 +2269,13 @@ mono_thread_suspend (MonoInternalThread *thread) (thread->state & ThreadState_SuspendRequested) != 0 || (thread->state & ThreadState_StopRequested) != 0) { - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); return TRUE; } thread->state |= ThreadState_SuspendRequested; - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); suspend_thread_internal (thread, FALSE); return TRUE; @@ -2418,13 +2291,11 @@ ves_icall_System_Threading_Thread_Suspend (MonoInternalThread *thread) static gboolean mono_thread_resume (MonoInternalThread *thread) { - ensure_synch_cs_set (thread); - - EnterCriticalSection (thread->synch_cs); + LOCK_THREAD (thread); if ((thread->state & ThreadState_SuspendRequested) != 0) { thread->state &= ~ThreadState_SuspendRequested; - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); return TRUE; } @@ -2433,7 +2304,7 @@ mono_thread_resume (MonoInternalThread *thread) (thread->state & ThreadState_Aborted) != 0 || (thread->state & ThreadState_Stopped) != 0) { - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); return FALSE; } @@ -2482,14 +2353,12 @@ is_running_protected_wrapper (void) void mono_thread_internal_stop (MonoInternalThread *thread) { - ensure_synch_cs_set (thread); - - EnterCriticalSection (thread->synch_cs); + LOCK_THREAD (thread); if ((thread->state & ThreadState_StopRequested) != 0 || (thread->state & ThreadState_Stopped) != 0) { - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); return; } @@ -2499,7 +2368,7 @@ void mono_thread_internal_stop (MonoInternalThread *thread) thread->state |= ThreadState_StopRequested; thread->state &= ~ThreadState_AbortRequested; - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); abort_thread_internal (thread, TRUE, TRUE); } @@ -2512,108 +2381,262 @@ void mono_thread_stop (MonoThread *thread) gint8 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr) { - return *((volatile gint8 *) (ptr)); + gint8 tmp; + mono_atomic_load_acquire (tmp, gint8, (volatile gint8 *) ptr); + return tmp; } gint16 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr) { - return *((volatile gint16 *) (ptr)); + gint16 tmp; + mono_atomic_load_acquire (tmp, gint16, (volatile gint16 *) ptr); + return tmp; } gint32 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr) { - return *((volatile gint32 *) (ptr)); + gint32 tmp; + mono_atomic_load_acquire (tmp, gint32, (volatile gint32 *) ptr); + return tmp; } gint64 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr) { -#if SIZEOF_VOID_P == 8 - return *((volatile gint64 *) (ptr)); -#else - return InterlockedCompareExchange64 (ptr, 0, 0); /*Must ensure atomicity of the operation. */ -#endif + gint64 tmp; + mono_atomic_load_acquire (tmp, gint64, (volatile gint64 *) ptr); + return tmp; } void * ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr) { - return (void *) *((volatile void **) ptr); + volatile void *tmp; + mono_atomic_load_acquire (tmp, volatile void *, (volatile void **) ptr); + return (void *) tmp; +} + +void * +ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr) +{ + volatile MonoObject *tmp; + mono_atomic_load_acquire (tmp, volatile MonoObject *, (volatile MonoObject **) ptr); + return (MonoObject *) tmp; } double ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr) { - return *((volatile double *) (ptr)); + double tmp; + mono_atomic_load_acquire (tmp, double, (volatile double *) ptr); + return tmp; } float ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr) { - return *((volatile float *) (ptr)); + float tmp; + mono_atomic_load_acquire (tmp, float, (volatile float *) ptr); + return tmp; +} + +gint8 +ves_icall_System_Threading_Volatile_Read1 (void *ptr) +{ + return InterlockedRead8 (ptr); +} + +gint16 +ves_icall_System_Threading_Volatile_Read2 (void *ptr) +{ + return InterlockedRead16 (ptr); +} + +gint32 +ves_icall_System_Threading_Volatile_Read4 (void *ptr) +{ + return InterlockedRead (ptr); +} + +gint64 +ves_icall_System_Threading_Volatile_Read8 (void *ptr) +{ +#if SIZEOF_VOID_P == 4 + if (G_UNLIKELY ((size_t)ptr & 0x7)) { + gint64 val; + mono_interlocked_lock (); + val = *(gint64*)ptr; + mono_interlocked_unlock (); + return val; + } +#endif + return InterlockedRead64 (ptr); +} + +void * +ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr) +{ + return InterlockedReadPointer (ptr); +} + +double +ves_icall_System_Threading_Volatile_ReadDouble (void *ptr) +{ + LongDoubleUnion u; + +#if SIZEOF_VOID_P == 4 + if (G_UNLIKELY ((size_t)ptr & 0x7)) { + double val; + mono_interlocked_lock (); + val = *(double*)ptr; + mono_interlocked_unlock (); + return val; + } +#endif + + u.ival = InterlockedRead64 (ptr); + + return u.fval; +} + +float +ves_icall_System_Threading_Volatile_ReadFloat (void *ptr) +{ + IntFloatUnion u; + + u.ival = InterlockedRead (ptr); + + return u.fval; } MonoObject* ves_icall_System_Threading_Volatile_Read_T (void *ptr) { - return (MonoObject*)*((volatile MonoObject**)ptr); + return InterlockedReadPointer (ptr); } void ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value) { - *((volatile gint8 *) ptr) = value; + mono_atomic_store_release ((volatile gint8 *) ptr, value); } void ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value) { - *((volatile gint16 *) ptr) = value; + mono_atomic_store_release ((volatile gint16 *) ptr, value); } void ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value) { - *((volatile gint32 *) ptr) = value; + mono_atomic_store_release ((volatile gint32 *) ptr, value); } void ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value) { - *((volatile gint64 *) ptr) = value; + mono_atomic_store_release ((volatile gint64 *) ptr, value); } void ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value) { - *((volatile void **) ptr) = value; + mono_atomic_store_release ((volatile void **) ptr, value); } void -ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, void *value) +ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value) { - mono_gc_wbarrier_generic_store (ptr, value); + mono_gc_wbarrier_generic_store_atomic (ptr, value); } void ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value) { - *((volatile double *) ptr) = value; + mono_atomic_store_release ((volatile double *) ptr, value); } void ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value) { - *((volatile float *) ptr) = value; + mono_atomic_store_release ((volatile float *) ptr, value); +} + +void +ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value) +{ + InterlockedWrite8 (ptr, value); +} + +void +ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value) +{ + InterlockedWrite16 (ptr, value); +} + +void +ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value) +{ + InterlockedWrite (ptr, value); +} + +void +ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value) +{ +#if SIZEOF_VOID_P == 4 + if (G_UNLIKELY ((size_t)ptr & 0x7)) { + mono_interlocked_lock (); + *(gint64*)ptr = value; + mono_interlocked_unlock (); + return; + } +#endif + + InterlockedWrite64 (ptr, value); +} + +void +ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value) +{ + InterlockedWritePointer (ptr, value); +} + +void +ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value) +{ + LongDoubleUnion u; + +#if SIZEOF_VOID_P == 4 + if (G_UNLIKELY ((size_t)ptr & 0x7)) { + mono_interlocked_lock (); + *(double*)ptr = value; + mono_interlocked_unlock (); + return; + } +#endif + + u.fval = value; + + InterlockedWrite64 (ptr, u.ival); +} + +void +ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value) +{ + IntFloatUnion u; + + u.fval = value; + + InterlockedWrite (ptr, u.ival); } void ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value) { - *((volatile MonoObject **) ptr) = value; - mono_gc_wbarrier_generic_nostore (ptr); + mono_gc_wbarrier_generic_store_atomic (ptr, value); } void @@ -2915,16 +2938,16 @@ mono_threads_set_shutting_down (void) /* Make sure we're properly suspended/stopped */ - EnterCriticalSection (current_thread->synch_cs); + LOCK_THREAD (current_thread); if ((current_thread->state & ThreadState_SuspendRequested) || (current_thread->state & ThreadState_AbortRequested) || (current_thread->state & ThreadState_StopRequested)) { - LeaveCriticalSection (current_thread->synch_cs); + UNLOCK_THREAD (current_thread); mono_thread_execute_interruption (current_thread); } else { current_thread->state |= ThreadState_Stopped; - LeaveCriticalSection (current_thread->synch_cs); + UNLOCK_THREAD (current_thread); } /*since we're killing the thread, unset the current domain.*/ @@ -3135,15 +3158,13 @@ void mono_thread_suspend_all_other_threads (void) continue; } - ensure_synch_cs_set (thread); - - EnterCriticalSection (thread->synch_cs); + LOCK_THREAD (thread); if (thread->suspended_event == NULL) { thread->suspended_event = CreateEvent (NULL, TRUE, FALSE, NULL); if (thread->suspended_event == NULL) { /* Forget this one and go on to the next */ - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); continue; } } @@ -3151,7 +3172,7 @@ void mono_thread_suspend_all_other_threads (void) if ((thread->state & ThreadState_Suspended) != 0 || (thread->state & ThreadState_StopRequested) != 0 || (thread->state & ThreadState_Stopped) != 0) { - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); CloseHandle (wait->handles [i]); wait->threads [i] = NULL; /* ignore this thread in next loop */ continue; @@ -3168,7 +3189,7 @@ void mono_thread_suspend_all_other_threads (void) thread->state |= ThreadState_SuspendRequested; - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); /* Signal the thread to suspend */ if (mono_thread_info_new_interrupt_enabled ()) @@ -3186,14 +3207,12 @@ void mono_thread_suspend_all_other_threads (void) if (thread == NULL) continue; - ensure_synch_cs_set (thread); - - EnterCriticalSection (thread->synch_cs); + LOCK_THREAD (thread); if ((thread->state & ThreadState_Suspended) != 0) { CloseHandle (thread->suspended_event); thread->suspended_event = NULL; } - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); } } @@ -3247,7 +3266,7 @@ print_stack_frame_to_string (MonoStackFrameInfo *frame, MonoContext *ctx, gpoint GString *p = (GString*)data; MonoMethod *method = NULL; if (frame->ji) - method = frame->ji->method; + method = mono_jit_info_get_method (frame->ji); if (method) { gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain); @@ -3953,7 +3972,7 @@ free_thread_static_data_helper (gpointer key, gpointer value, gpointer user) if (!thread->static_data || !thread->static_data [idx]) return; ptr = ((char*) thread->static_data [idx]) + (data->offset & 0xffffff); - mono_gc_bzero (ptr, data->size); + mono_gc_bzero_atomic (ptr, data->size); } static void @@ -4165,9 +4184,7 @@ static guint32 dummy_apc (gpointer param) */ static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread) { - ensure_synch_cs_set (thread); - - EnterCriticalSection (thread->synch_cs); + LOCK_THREAD (thread); /* MonoThread::interruption_requested can only be changed with atomics */ if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) { @@ -4181,7 +4198,7 @@ static MonoException* mono_thread_execute_interruption (MonoInternalThread *thre } if ((thread->state & ThreadState_AbortRequested) != 0) { - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); if (thread->abort_exc == NULL) { /* * This might be racy, but it has to be called outside the lock @@ -4198,7 +4215,7 @@ static MonoException* mono_thread_execute_interruption (MonoInternalThread *thre else if ((thread->state & ThreadState_StopRequested) != 0) { /* FIXME: do this through the JIT? */ - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); mono_thread_exit (); return NULL; @@ -4208,17 +4225,17 @@ static MonoException* mono_thread_execute_interruption (MonoInternalThread *thre exc = thread->pending_exception; thread->pending_exception = NULL; - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); return exc; } else if (thread->thread_interrupt_requested) { thread->thread_interrupt_requested = FALSE; - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); return(mono_get_exception_thread_interrupted ()); } - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); return NULL; } @@ -4285,10 +4302,9 @@ mono_thread_resume_interruption (void) if (thread == NULL) return NULL; - ensure_synch_cs_set (thread); - EnterCriticalSection (thread->synch_cs); + LOCK_THREAD (thread); still_aborting = (thread->state & ThreadState_AbortRequested) != 0; - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); /*This can happen if the protected block called Thread::ResetAbort*/ if (!still_aborting) @@ -4323,8 +4339,6 @@ static void mono_thread_interruption_checkpoint_request (gboolean bypass_abort_p if (thread == NULL) return; - mono_debugger_check_interruption (); - if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) { MonoException* exc = mono_thread_execute_interruption (thread); if (exc) mono_raise_exception (exc); @@ -4445,21 +4459,17 @@ mono_thread_cleanup_apartment_state (void) void mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state) { - ensure_synch_cs_set (thread); - - EnterCriticalSection (thread->synch_cs); + LOCK_THREAD (thread); thread->state |= state; - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); } void mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state) { - ensure_synch_cs_set (thread); - - EnterCriticalSection (thread->synch_cs); + LOCK_THREAD (thread); thread->state &= ~state; - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); } gboolean @@ -4467,15 +4477,13 @@ mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test) { gboolean ret = FALSE; - ensure_synch_cs_set (thread); - - EnterCriticalSection (thread->synch_cs); + LOCK_THREAD (thread); if ((thread->state & test) != 0) { ret = TRUE; } - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); return ret; } @@ -4649,7 +4657,7 @@ abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, InterlockedIncrement (&thread_interruption_requested); ji = mono_thread_info_get_last_managed (info); - protected_wrapper = ji && mono_threads_is_critical_method (ji->method); + protected_wrapper = ji && mono_threads_is_critical_method (mono_jit_info_get_method (ji)); running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx)); if (!protected_wrapper && running_managed) { @@ -4690,7 +4698,7 @@ transition_to_suspended (MonoInternalThread *thread) thread->state |= ThreadState_Suspended; mono_thread_info_finish_suspend (); } - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); } static void @@ -4701,7 +4709,7 @@ suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt) return; } - EnterCriticalSection (thread->synch_cs); + LOCK_THREAD (thread); if (thread == mono_thread_internal_current ()) { transition_to_suspended (thread); mono_thread_info_self_suspend (); @@ -4713,12 +4721,12 @@ suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt) /*A null info usually means the thread is already dead. */ if (!(info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gsize)thread->tid, interrupt))) { - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); return; } ji = mono_thread_info_get_last_managed (info); - protected_wrapper = ji && mono_threads_is_critical_method (ji->method); + protected_wrapper = ji && mono_threads_is_critical_method (mono_jit_info_get_method (ji)); running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx)); if (running_managed && !protected_wrapper) { @@ -4737,7 +4745,7 @@ suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt) if (interrupt) wapi_finish_interrupt_thread (interrupt_handle); #endif - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); } } } @@ -4751,13 +4759,13 @@ self_suspend_internal (MonoInternalThread *thread) thread->state |= ThreadState_Suspended; thread->suspend_event = CreateEvent (NULL, TRUE, FALSE, NULL); if (thread->suspend_event == NULL) { - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); return; } if (thread->suspended_event) SetEvent (thread->suspended_event); - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); if (shutting_down) { /* After we left the lock, the runtime might shut down so everything becomes invalid */ @@ -4767,7 +4775,7 @@ self_suspend_internal (MonoInternalThread *thread) WaitForSingleObject (thread->suspend_event, INFINITE); - EnterCriticalSection (thread->synch_cs); + LOCK_THREAD (thread); CloseHandle (thread->suspend_event); thread->suspend_event = NULL; @@ -4778,7 +4786,7 @@ self_suspend_internal (MonoInternalThread *thread) */ SetEvent (thread->resume_event); - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); return; } @@ -4793,14 +4801,14 @@ resume_thread_internal (MonoInternalThread *thread) if (!mono_thread_info_new_interrupt_enabled ()) { thread->resume_event = CreateEvent (NULL, TRUE, FALSE, NULL); if (thread->resume_event == NULL) { - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); return FALSE; } /* Awake the thread */ SetEvent (thread->suspend_event); - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); /* Wait for the thread to awake */ WaitForSingleObject (thread->resume_event, INFINITE); @@ -4809,13 +4817,13 @@ resume_thread_internal (MonoInternalThread *thread) return TRUE; } - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); /* Awake the thread */ if (!mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid)) return FALSE; - EnterCriticalSection (thread->synch_cs); + LOCK_THREAD (thread); thread->state &= ~ThreadState_Suspended; - LeaveCriticalSection (thread->synch_cs); + UNLOCK_THREAD (thread); return TRUE; } |