X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Futils%2Fmono-threads.c;h=e26ca1760c6fb49214c735925a064146b8005ec7;hb=746d97a043149d1204e10a3a1944cfe40fa60051;hp=980522621b264ca3709ab733d6e76928853a1fb4;hpb=e25f0dd1e77d37a45428ecc07800d09d38d8266c;p=mono.git diff --git a/mono/utils/mono-threads.c b/mono/utils/mono-threads.c index 980522621b2..e26ca1760c6 100644 --- a/mono/utils/mono-threads.c +++ b/mono/utils/mono-threads.c @@ -1,5 +1,6 @@ -/* - * mono-threads.c: Low-level threading +/** + * \file + * Low-level threading * * Author: * Rodrigo Kumpera (kumpera@gmail.com) @@ -29,6 +30,9 @@ #include #include #include +#include +#include +#include #include @@ -62,7 +66,7 @@ static MonoThreadInfoCallbacks threads_callbacks; static MonoThreadInfoRuntimeCallbacks runtime_callbacks; static MonoNativeTlsKey thread_info_key, thread_exited_key; #ifdef HAVE_KW_THREAD -static __thread guint32 tls_small_id MONO_TLS_FAST; +static __thread gint32 tls_small_id = -1; #else static MonoNativeTlsKey small_id_key; #endif @@ -71,7 +75,8 @@ static gboolean mono_threads_inited = FALSE; static MonoSemType suspend_semaphore; static size_t pending_suspends; -static gboolean unified_suspend_enabled; + +static mono_mutex_t join_mutex; #define mono_thread_info_run_state(info) (((MonoThreadInfo*)info)->thread_state & THREAD_STATE_MASK) @@ -260,8 +265,6 @@ mono_threads_wait_pending_operations (void) //Thread initialization code -static void mono_threads_unregister_current_thread (MonoThreadInfo *info); - static inline void mono_hazard_pointer_clear_all (MonoThreadHazardPointers *hp, int retain) { @@ -279,7 +282,7 @@ If return non null Hazard Pointer 1 holds the return value. MonoThreadInfo* mono_thread_info_lookup (MonoNativeThreadId id) { - MonoThreadHazardPointers *hp = mono_hazard_pointer_get (); + MonoThreadHazardPointers *hp = mono_hazard_pointer_get (); if (!mono_lls_find (&thread_list, hp, (uintptr_t)id)) { mono_hazard_pointer_clear_all (hp, -1); @@ -327,10 +330,23 @@ free_thread_info (gpointer mem) g_free (info); } +/* + * mono_thread_info_register_small_id + * + * Registers a small ID for the current thread. This is a 16-bit value uniquely + * identifying the current thread. If the current thread already has a small ID + * assigned, that small ID will be returned; otherwise, the newly assigned small + * ID is returned. + */ int mono_thread_info_register_small_id (void) { - int small_id = mono_thread_small_id_alloc (); + int small_id = mono_thread_info_get_small_id (); + + if (small_id != -1) + return small_id; + + small_id = mono_thread_small_id_alloc (); #ifdef HAVE_KW_THREAD tls_small_id = small_id; #else @@ -339,32 +355,36 @@ mono_thread_info_register_small_id (void) return small_id; } -static void* -register_thread (MonoThreadInfo *info, gpointer baseptr) +static void +thread_handle_destroy (gpointer data) +{ + MonoThreadHandle *thread_handle; + + thread_handle = (MonoThreadHandle*) data; + + mono_os_event_destroy (&thread_handle->event); + g_free (thread_handle); +} + +static gboolean +register_thread (MonoThreadInfo *info) { size_t stsize = 0; guint8 *staddr = NULL; - int small_id = mono_thread_info_register_small_id (); gboolean result; + + info->small_id = mono_thread_info_register_small_id (); mono_thread_info_set_tid (info, mono_native_thread_id_get ()); - info->small_id = small_id; + + info->handle = g_new0 (MonoThreadHandle, 1); + mono_refcount_init (info->handle, thread_handle_destroy); + mono_os_event_init (&info->handle->event, FALSE); mono_os_sem_init (&info->resume_semaphore, 0); /*set TLS early so SMR works */ mono_native_tls_set_value (thread_info_key, info); - THREADS_DEBUG ("registering info %p tid %p small id %x\n", info, mono_thread_info_get_tid (info), info->small_id); - - if (threads_callbacks.thread_register) { - if (threads_callbacks.thread_register (info, baseptr) == NULL) { - // g_warning ("thread registation failed\n"); - mono_native_tls_set_value (thread_info_key, NULL); - g_free (info); - return NULL; - } - } - mono_thread_info_get_stack_bounds (&staddr, &stsize); g_assert (staddr); g_assert (stsize); @@ -373,9 +393,22 @@ register_thread (MonoThreadInfo *info, gpointer baseptr) info->stackdata = g_byte_array_new (); - mono_threads_platform_register (info); + info->internal_thread_gchandle = G_MAXUINT32; + + info->profiler_signal_ack = 1; + mono_threads_suspend_register (info); + THREADS_DEBUG ("registering info %p tid %p small id %x\n", info, mono_thread_info_get_tid (info), info->small_id); + + if (threads_callbacks.thread_attach) { + if (!threads_callbacks.thread_attach (info)) { + // g_warning ("thread registation failed\n"); + mono_native_tls_set_value (thread_info_key, NULL); + return FALSE; + } + } + /* Transition it before taking any locks or publishing itself to reduce the chance of others witnessing a detached thread. @@ -388,24 +421,33 @@ register_thread (MonoThreadInfo *info, gpointer baseptr) result = mono_thread_info_insert (info); g_assert (result); mono_thread_info_suspend_unlock (); - return info; + + return TRUE; } static void mono_thread_info_suspend_lock_with_info (MonoThreadInfo *info); +static void +mono_threads_signal_thread_handle (MonoThreadHandle* thread_handle); + static void unregister_thread (void *arg) { gpointer gc_unsafe_stackdata; MonoThreadInfo *info; int small_id; + gboolean result; + gpointer handle; info = (MonoThreadInfo *) arg; g_assert (info); g_assert (mono_thread_info_is_current (info)); g_assert (mono_thread_info_is_live (info)); + /* Pump the HP queue while the thread is alive.*/ + mono_thread_hazardous_try_free_some (); + small_id = info->small_id; /* We only enter the GC unsafe region, as when exiting this function, the thread @@ -416,8 +458,6 @@ unregister_thread (void *arg) mono_native_tls_set_value (thread_exited_key, GUINT_TO_POINTER (1)); - mono_threads_platform_unregister (info); - /* * TLS destruction order is not reliable so small_id might be cleaned up * before us. @@ -426,6 +466,10 @@ unregister_thread (void *arg) mono_native_tls_set_value (small_id_key, GUINT_TO_POINTER (info->small_id + 1)); #endif + /* we need to duplicate it, as the info->handle is going + * to be closed when unregistering from the platform */ + handle = mono_threads_open_thread_handle (info->handle); + /* First perform the callback that requires no locks. This callback has the potential of taking other locks, so we do it before. @@ -442,9 +486,15 @@ unregister_thread (void *arg) be done while holding the suspend lock to give no other thread chance to suspend it. */ - if (threads_callbacks.thread_unregister) - threads_callbacks.thread_unregister (info); - mono_threads_unregister_current_thread (info); + if (threads_callbacks.thread_detach_with_lock) + threads_callbacks.thread_detach_with_lock (info); + + /* The thread is no longer active, so unref its handle */ + mono_threads_close_thread_handle (info->handle); + info->handle = NULL; + + result = mono_thread_info_remove (info); + g_assert (result); mono_threads_transition_detach (info); mono_thread_info_suspend_unlock (); @@ -453,10 +503,14 @@ unregister_thread (void *arg) /*now it's safe to free the thread info.*/ mono_thread_hazardous_try_free (info, free_thread_info); - /* Pump the HP queue */ - mono_thread_hazardous_try_free_some (); mono_thread_small_id_free (small_id); + + mono_threads_signal_thread_handle (handle); + + mono_threads_close_thread_handle (handle); + + mono_native_tls_set_value (thread_info_key, NULL); } static void @@ -480,20 +534,6 @@ thread_exited_dtor (void *arg) #endif } -/** - * Removes the current thread from the thread list. - * This must be called from the thread unregister callback and nowhere else. - * The current thread must be passed as TLS might have already been cleaned up. -*/ -static void -mono_threads_unregister_current_thread (MonoThreadInfo *info) -{ - gboolean result; - g_assert (mono_thread_info_get_tid (info) == mono_native_thread_id_get ()); - result = mono_thread_info_remove (info); - g_assert (result); -} - MonoThreadInfo* mono_thread_info_current_unchecked (void) { @@ -528,6 +568,16 @@ mono_thread_info_current (void) return info; } +/* + * mono_thread_info_get_small_id + * + * Retrieve the small ID for the current thread. This is a 16-bit value uniquely + * identifying the current thread. Returns -1 if the current thread doesn't have + * a small ID assigned. + * + * To ensure that the calling thread has a small ID assigned, call either + * mono_thread_info_attach or mono_thread_info_register_small_id. + */ int mono_thread_info_get_small_id (void) { @@ -562,7 +612,6 @@ mono_thread_info_list_head (void) void mono_threads_attach_tools_thread (void) { - int dummy = 0; MonoThreadInfo *info; /* Must only be called once */ @@ -572,36 +621,39 @@ mono_threads_attach_tools_thread (void) mono_thread_info_usleep (10); } - info = mono_thread_info_attach (&dummy); + info = mono_thread_info_attach (); g_assert (info); info->tools_thread = TRUE; } MonoThreadInfo* -mono_thread_info_attach (void *baseptr) +mono_thread_info_attach (void) { MonoThreadInfo *info; + +#ifdef HOST_WIN32 if (!mono_threads_inited) { -#ifdef HOST_WIN32 /* This can happen from DllMain(DLL_THREAD_ATTACH) on Windows, if a * thread is created before an embedding API user initialized Mono. */ - THREADS_DEBUG ("mono_thread_info_attach called before mono_threads_init\n"); + THREADS_DEBUG ("mono_thread_info_attach called before mono_thread_info_init\n"); return NULL; -#else - g_assert (mono_threads_inited); -#endif } +#endif + + g_assert (mono_threads_inited); + info = (MonoThreadInfo *) mono_native_tls_get_value (thread_info_key); if (!info) { info = (MonoThreadInfo *) g_malloc0 (thread_info_size); THREADS_DEBUG ("attaching %p\n", info); - if (!register_thread (info, baseptr)) + if (!register_thread (info)) { + g_free (info); return NULL; - } else if (threads_callbacks.thread_attach) { - threads_callbacks.thread_attach (info); + } } + return info; } @@ -609,21 +661,53 @@ void mono_thread_info_detach (void) { MonoThreadInfo *info; + +#ifdef HOST_WIN32 if (!mono_threads_inited) { /* This can happen from DllMain(THREAD_DETACH) on Windows, if a thread * is created before an embedding API user initialized Mono. */ - THREADS_DEBUG ("mono_thread_info_detach called before mono_threads_init\n"); + THREADS_DEBUG ("mono_thread_info_detach called before mono_thread_info_init\n"); return; } +#endif + + g_assert (mono_threads_inited); + info = (MonoThreadInfo *) mono_native_tls_get_value (thread_info_key); if (info) { THREADS_DEBUG ("detaching %p\n", info); unregister_thread (info); - mono_native_tls_set_value (thread_info_key, NULL); } } +gboolean +mono_thread_info_try_get_internal_thread_gchandle (MonoThreadInfo *info, guint32 *gchandle) +{ + g_assert (info); + + if (info->internal_thread_gchandle == G_MAXUINT32) + return FALSE; + + *gchandle = info->internal_thread_gchandle; + return TRUE; +} + +void +mono_thread_info_set_internal_thread_gchandle (MonoThreadInfo *info, guint32 gchandle) +{ + g_assert (info); + g_assert (gchandle != G_MAXUINT32); + info->internal_thread_gchandle = gchandle; +} + +void +mono_thread_info_unset_internal_thread_gchandle (THREAD_INFO_TYPE *info) +{ + g_assert (info); + info->internal_thread_gchandle = G_MAXUINT32; +} + /* * mono_thread_info_is_exiting: * @@ -655,12 +739,11 @@ thread_info_key_dtor (void *arg) #endif void -mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t info_size) +mono_thread_info_init (size_t info_size) { gboolean res; - threads_callbacks = *callbacks; thread_info_size = info_size; - const char *sleepLimit; + char *sleepLimit; #ifdef HOST_WIN32 res = mono_native_tls_alloc (&thread_info_key, NULL); res = mono_native_tls_alloc (&thread_exited_key, NULL); @@ -676,8 +759,6 @@ mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t info_size) #endif g_assert (res); - unified_suspend_enabled = g_getenv ("MONO_ENABLE_UNIFIED_SUSPEND") != NULL || mono_threads_is_coop_enabled (); - if ((sleepLimit = g_getenv ("MONO_SLEEP_ABORT_LIMIT")) != NULL) { errno = 0; long threshold = strtol(sleepLimit, NULL, 10); @@ -686,17 +767,18 @@ mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t info_size) sleepWarnDuration = threshold / 20; } else g_warning("MONO_SLEEP_ABORT_LIMIT must be a number >= 40"); + g_free (sleepLimit); } mono_os_sem_init (&global_suspend_semaphore, 1); mono_os_sem_init (&suspend_semaphore, 0); + mono_os_mutex_init (&join_mutex); mono_lls_init (&thread_list, NULL); mono_thread_smr_init (); - mono_threads_platform_init (); mono_threads_suspend_init (); mono_threads_coop_init (); - mono_threads_abort_syscall_init (); + mono_threads_platform_init (); #if defined(__MACH__) mono_mach_init (thread_info_key); @@ -708,71 +790,33 @@ mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t info_size) } void -mono_threads_runtime_init (MonoThreadInfoRuntimeCallbacks *callbacks) +mono_thread_info_callbacks_init (MonoThreadInfoCallbacks *callbacks) { - runtime_callbacks = *callbacks; + threads_callbacks = *callbacks; } -MonoThreadInfoRuntimeCallbacks * -mono_threads_get_runtime_callbacks (void) +void +mono_thread_info_signals_init (void) { - return &runtime_callbacks; + mono_threads_suspend_init_signals (); } -/* -Signal that the current thread wants to be suspended. -This function can be called without holding the suspend lock held. -To finish suspending, call mono_suspend_check. -*/ void -mono_thread_info_begin_self_suspend (void) +mono_thread_info_runtime_init (MonoThreadInfoRuntimeCallbacks *callbacks) { - MonoThreadInfo *info = mono_thread_info_current_unchecked (); - if (!info) - return; - - THREADS_SUSPEND_DEBUG ("BEGIN SELF SUSPEND OF %p\n", info); - mono_threads_transition_request_self_suspension (info); + runtime_callbacks = *callbacks; } -void -mono_thread_info_end_self_suspend (void) +MonoThreadInfoRuntimeCallbacks * +mono_threads_get_runtime_callbacks (void) { - MonoThreadInfo *info; - - info = mono_thread_info_current (); - if (!info) - return; - THREADS_SUSPEND_DEBUG ("FINISH SELF SUSPEND OF %p\n", info); - - mono_threads_get_runtime_callbacks ()->thread_state_init (&info->thread_saved_state [SELF_SUSPEND_STATE_INDEX]); - - /* commit the saved state and notify others if needed */ - switch (mono_threads_transition_state_poll (info)) { - case SelfSuspendResumed: - return; - case SelfSuspendWait: - mono_thread_info_wait_for_resume (info); - break; - case SelfSuspendNotifyAndWait: - mono_threads_notify_initiator_of_suspend (info); - mono_thread_info_wait_for_resume (info); - mono_threads_notify_initiator_of_resume (info); - break; - } + return &runtime_callbacks; } static gboolean mono_thread_info_core_resume (MonoThreadInfo *info) { gboolean res = FALSE; - if (info->create_suspended) { - MonoNativeThreadId tid = mono_thread_info_get_tid (info); - /* Have to special case this, as the normal suspend/resume pair are racy, they don't work if he resume is received before the suspend */ - info->create_suspended = FALSE; - mono_threads_platform_resume_created (info, tid); - return TRUE; - } switch (mono_threads_transition_request_resume (info)) { case ResumeError: @@ -856,17 +900,18 @@ WB trampoline. Another option is to encode wb ranges in MonoJitInfo, but that is static gboolean is_thread_in_critical_region (MonoThreadInfo *info) { - MonoMethod *method; - MonoJitInfo *ji; gpointer stack_start; MonoThreadUnwindState *state; + if (mono_threads_platform_in_critical_region (mono_thread_info_get_tid (info))) + return TRUE; + /* Are we inside a system critical region? */ if (info->inside_critical_region) return TRUE; /* Are we inside a GC critical region? */ - if (threads_callbacks.mono_thread_in_critical_region && threads_callbacks.mono_thread_in_critical_region (info)) { + if (threads_callbacks.thread_in_critical_region && threads_callbacks.thread_in_critical_region (info)) { return TRUE; } @@ -880,16 +925,10 @@ is_thread_in_critical_region (MonoThreadInfo *info) if (stack_start < info->stack_start_limit || stack_start >= info->stack_end) return TRUE; - ji = mono_jit_info_table_find ( - (MonoDomain *) state->unwind_data [MONO_UNWIND_DATA_DOMAIN], - (char *) MONO_CONTEXT_GET_IP (&state->ctx)); - - if (!ji) - return FALSE; - - method = mono_jit_info_get_method (ji); + if (threads_callbacks.ip_in_critical_region) + return threads_callbacks.ip_in_critical_region ((MonoDomain *) state->unwind_data [MONO_UNWIND_DATA_DOMAIN], (char *) MONO_CONTEXT_GET_IP (&state->ctx)); - return threads_callbacks.mono_method_is_critical (method); + return FALSE; } gboolean @@ -926,7 +965,7 @@ suspend_sync (MonoNativeThreadId tid, gboolean interrupt_kernel) if (interrupt_kernel) mono_threads_suspend_abort_syscall (info); - break; + return info; default: g_assert_not_reached (); } @@ -1003,6 +1042,7 @@ mono_thread_info_safe_suspend_and_run (MonoNativeThreadId id, gboolean interrupt mono_threads_wait_pending_operations (); break; case KeepSuspended: + g_assert (!mono_threads_is_coop_enabled ()); break; default: g_error ("Invalid suspend_and_run callback return value %d", result); @@ -1024,8 +1064,12 @@ currently used only to deliver exceptions. void mono_thread_info_setup_async_call (MonoThreadInfo *info, void (*target_func)(void*), void *user_data) { - /* An async call can only be setup on an async suspended thread */ - g_assert (mono_thread_info_run_state (info) == STATE_ASYNC_SUSPENDED); + if (!mono_threads_is_coop_enabled ()) { + /* In non-coop mode, an async call can only be setup on an async suspended thread, but in coop mode, a thread + * may be in blocking state, and will execute the async call when leaving the safepoint, leaving a gc safe + * region or entering a gc unsafe region */ + g_assert (mono_thread_info_run_state (info) == STATE_ASYNC_SUSPENDED); + } /*FIXME this is a bad assert, we probably should do proper locking and fail if one is already set*/ g_assert (!info->async_target); info->async_target = target_func; @@ -1057,7 +1101,20 @@ mono_thread_info_suspend_lock_with_info (MonoThreadInfo *info) void mono_thread_info_suspend_lock (void) { - mono_thread_info_suspend_lock_with_info (mono_thread_info_current_unchecked ()); + MonoThreadInfo *info; + gint res; + + info = mono_thread_info_current_unchecked (); + if (info && mono_thread_info_is_live (info)) { + mono_thread_info_suspend_lock_with_info (info); + return; + } + + /* mono_thread_info_suspend_lock () can be called from boehm-gc.c on_gc_notification before the new thread's + * start_wrapper calls mono_thread_info_attach but after pthread_create calls the start wrapper. */ + + res = mono_os_sem_wait (&global_suspend_semaphore, MONO_SEM_FLAGS_NONE); + g_assert (res != -1); } void @@ -1082,7 +1139,7 @@ mono_thread_info_abort_socket_syscall_for_close (MonoNativeThreadId tid) MonoThreadHazardPointers *hp; MonoThreadInfo *info; - if (tid == mono_native_thread_id_get () || !mono_threads_suspend_needs_abort_syscall ()) + if (tid == mono_native_thread_id_get ()) return; hp = mono_hazard_pointer_get (); @@ -1107,12 +1164,6 @@ mono_thread_info_abort_socket_syscall_for_close (MonoNativeThreadId tid) mono_thread_info_suspend_unlock (); } -gboolean -mono_thread_info_unified_management_enabled (void) -{ - return unified_suspend_enabled; -} - /* * mono_thread_info_set_is_async_context: * @@ -1139,18 +1190,6 @@ mono_thread_info_is_async_context (void) return FALSE; } -/* - * mono_threads_create_thread: - * - * Create a new thread executing START with argument ARG. Store its id into OUT_TID. - * Returns: a windows or io-layer handle for the thread. - */ -HANDLE -mono_threads_create_thread (MonoThreadStart start, gpointer arg, MonoThreadParm *tp, MonoNativeThreadId *out_tid) -{ - return mono_threads_platform_create_thread (start, arg, tp, out_tid); -} - /* * mono_thread_info_get_stack_bounds: * @@ -1177,6 +1216,7 @@ mono_thread_info_yield (void) { return mono_threads_platform_yield (); } + static mono_lazy_init_t sleep_init = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED; static MonoCoopMutex sleep_mutex; static MonoCoopCond sleep_cond; @@ -1201,22 +1241,22 @@ sleep_interruptable (guint32 ms, gboolean *alerted) { gint64 now, end; - g_assert (INFINITE == G_MAXUINT32); + g_assert (MONO_INFINITE_WAIT == G_MAXUINT32); g_assert (alerted); *alerted = FALSE; - if (ms != INFINITE) - end = mono_100ns_ticks () + (ms * 1000 * 10); + if (ms != MONO_INFINITE_WAIT) + end = mono_msec_ticks() + ms; mono_lazy_initialize (&sleep_init, sleep_initialize); mono_coop_mutex_lock (&sleep_mutex); for (;;) { - if (ms != INFINITE) { - now = mono_100ns_ticks (); - if (now > end) + if (ms != MONO_INFINITE_WAIT) { + now = mono_msec_ticks(); + if (now >= end) break; } @@ -1226,8 +1266,8 @@ sleep_interruptable (guint32 ms, gboolean *alerted) return WAIT_IO_COMPLETION; } - if (ms != INFINITE) - mono_coop_cond_timedwait (&sleep_cond, &sleep_mutex, (end - now) / 10 / 1000); + if (ms != MONO_INFINITE_WAIT) + mono_coop_cond_timedwait (&sleep_cond, &sleep_mutex, end - now); else mono_coop_cond_wait (&sleep_cond, &sleep_mutex); @@ -1263,7 +1303,7 @@ mono_thread_info_sleep (guint32 ms, gboolean *alerted) MONO_ENTER_GC_SAFE; - if (ms == INFINITE) { + if (ms == MONO_INFINITE_WAIT) { do { #ifdef HOST_WIN32 Sleep (G_MAXUINT32); @@ -1347,22 +1387,35 @@ mono_thread_info_tls_set (THREAD_INFO_TYPE *info, MonoTlsKey key, gpointer value * This function doesn't return. */ void -mono_thread_info_exit (void) +mono_thread_info_exit (gsize exit_code) { + mono_thread_info_detach (); + mono_threads_platform_exit (0); } /* * mono_threads_open_thread_handle: * - * Return a io-layer/win32 handle for the thread identified by HANDLE/TID. - * The handle need to be closed by calling CloseHandle () when it is no - * longer needed. + * Duplicate the handle. The handle needs to be closed by calling + * mono_threads_close_thread_handle () when it is no longer needed. */ -HANDLE -mono_threads_open_thread_handle (HANDLE handle, MonoNativeThreadId tid) +MonoThreadHandle* +mono_threads_open_thread_handle (MonoThreadHandle *thread_handle) +{ + return mono_refcount_inc (thread_handle); +} + +void +mono_threads_close_thread_handle (MonoThreadHandle *thread_handle) +{ + mono_refcount_dec (thread_handle); +} + +static void +mono_threads_signal_thread_handle (MonoThreadHandle* thread_handle) { - return mono_threads_platform_open_thread_handle (handle, tid); + mono_os_event_set (&thread_handle->event); } #define INTERRUPT_STATE ((MonoThreadInfoInterruptToken*) (size_t) -1) @@ -1571,46 +1624,69 @@ mono_thread_info_is_current (MonoThreadInfo *info) return mono_thread_info_get_tid (info) == mono_native_thread_id_get (); } -void -mono_thread_info_set_exited (THREAD_INFO_TYPE *info) +MonoThreadInfoWaitRet +mono_thread_info_wait_one_handle (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable) { - g_assert (mono_thread_info_is_current (info)); - mono_threads_platform_set_exited (info); -} + MonoOSEventWaitRet res; -gpointer -mono_thread_info_get_handle (THREAD_INFO_TYPE *info) -{ - g_assert (info->handle); - return info->handle; + res = mono_os_event_wait_one (&thread_handle->event, timeout, alertable); + if (res == MONO_OS_EVENT_WAIT_RET_SUCCESS_0) + return MONO_THREAD_INFO_WAIT_RET_SUCCESS_0; + else if (res == MONO_OS_EVENT_WAIT_RET_ALERTED) + return MONO_THREAD_INFO_WAIT_RET_ALERTED; + else if (res == MONO_OS_EVENT_WAIT_RET_TIMEOUT) + return MONO_THREAD_INFO_WAIT_RET_TIMEOUT; + else + g_error ("%s: unknown res value %d", __func__, res); } -void -mono_thread_info_describe (MonoThreadInfo *info, GString *text) +MonoThreadInfoWaitRet +mono_thread_info_wait_multiple_handle (MonoThreadHandle **thread_handles, gsize nhandles, MonoOSEvent *background_change_event, gboolean waitall, guint32 timeout, gboolean alertable) { - mono_threads_platform_describe (info, text); -} + MonoOSEventWaitRet res; + MonoOSEvent *thread_events [MONO_OS_EVENT_WAIT_MAXIMUM_OBJECTS]; + gint i; -void -mono_thread_info_own_mutex (MonoThreadInfo *info, gpointer mutex_handle) -{ - mono_threads_platform_own_mutex (info, mutex_handle); -} + g_assert (nhandles <= MONO_OS_EVENT_WAIT_MAXIMUM_OBJECTS); + if (background_change_event) + g_assert (nhandles <= MONO_OS_EVENT_WAIT_MAXIMUM_OBJECTS - 1); -void -mono_thread_info_disown_mutex (MonoThreadInfo *info, gpointer mutex_handle) -{ - mono_threads_platform_disown_mutex (info, mutex_handle); + for (i = 0; i < nhandles; ++i) + thread_events [i] = &thread_handles [i]->event; + + if (background_change_event) + thread_events [nhandles ++] = background_change_event; + + res = mono_os_event_wait_multiple (thread_events, nhandles, waitall, timeout, alertable); + if (res >= MONO_OS_EVENT_WAIT_RET_SUCCESS_0 && res <= MONO_OS_EVENT_WAIT_RET_SUCCESS_0 + nhandles - 1) + return MONO_THREAD_INFO_WAIT_RET_SUCCESS_0 + (res - MONO_OS_EVENT_WAIT_RET_SUCCESS_0); + else if (res == MONO_OS_EVENT_WAIT_RET_ALERTED) + return MONO_THREAD_INFO_WAIT_RET_ALERTED; + else if (res == MONO_OS_EVENT_WAIT_RET_TIMEOUT) + return MONO_THREAD_INFO_WAIT_RET_TIMEOUT; + else + g_error ("%s: unknown res value %d", __func__, res); } -MonoThreadPriority -mono_thread_info_get_priority (MonoThreadInfo *info) +/* + * mono_threads_join_mutex: + * + * This mutex is used to avoid races between pthread_create () and pthread_join () on osx, see + * https://bugzilla.xamarin.com/show_bug.cgi?id=50529 + * The code inside the lock should not block. + */ +void +mono_threads_join_lock (void) { - return mono_threads_platform_get_priority (info); +#ifdef TARGET_OSX + mono_os_mutex_lock (&join_mutex); +#endif } -gboolean -mono_thread_info_set_priority (MonoThreadInfo *info, MonoThreadPriority priority) +void +mono_threads_join_unlock (void) { - return mono_threads_platform_set_priority (info, priority); +#ifdef TARGET_OSX + mono_os_mutex_unlock (&join_mutex); +#endif }