#include <mono/utils/mono-coop-mutex.h>
#include <mono/utils/mono-coop-semaphore.h>
#include <mono/utils/mono-threads-coop.h>
+#include <mono/utils/mono-threads-debug.h>
+#include <mono/utils/os-event.h>
#include <errno.h>
static MonoSemType suspend_semaphore;
static size_t pending_suspends;
-static gboolean unified_suspend_enabled;
#define mono_thread_info_run_state(info) (((MonoThreadInfo*)info)->thread_state & THREAD_STATE_MASK)
//Thread initialization code
-static void mono_threads_unregister_current_thread (MonoThreadInfo *info);
-
static inline void
mono_hazard_pointer_clear_all (MonoThreadHazardPointers *hp, int retain)
{
mono_thread_info_set_tid (info, mono_native_thread_id_get ());
info->small_id = small_id;
+ info->handle = g_new0 (MonoThreadHandle, 1);
+ info->handle->ref = 1;
+ mono_os_event_init (&info->handle->event, TRUE, FALSE);
+
mono_os_sem_init (&info->resume_semaphore, 0);
/*set TLS early so SMR works */
info->stackdata = g_byte_array_new ();
- mono_threads_platform_register (info);
mono_threads_suspend_register (info);
/*
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);
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.
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.
*/
if (threads_callbacks.thread_unregister)
threads_callbacks.thread_unregister (info);
- mono_threads_unregister_current_thread (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 ();
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);
}
static void
#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)
{
#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);
mono_lls_init (&thread_list, NULL);
mono_thread_smr_init ();
- mono_threads_platform_init ();
mono_threads_suspend_init ();
+ mono_threads_suspend_init_signals ();
mono_threads_coop_init ();
- mono_threads_abort_syscall_init ();
#if defined(__MACH__)
mono_mach_init (thread_info_key);
void
mono_thread_info_begin_self_suspend (void)
{
+ g_assert (!mono_threads_is_coop_enabled ());
+
MonoThreadInfo *info = mono_thread_info_current_unchecked ();
if (!info)
return;
{
MonoThreadInfo *info;
+ g_assert (!mono_threads_is_coop_enabled ());
+
info = mono_thread_info_current ();
if (!info)
return;
if (stack_start < info->stack_start_limit || stack_start >= info->stack_end)
return TRUE;
+ 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));
+
ji = mono_jit_info_table_find (
(MonoDomain *) state->unwind_data [MONO_UNWIND_DATA_DOMAIN],
(char *) MONO_CONTEXT_GET_IP (&state->ctx));
}
break;
case AsyncSuspendBlocking:
- if (interrupt_kernel)
+ if (interrupt_kernel && mono_threads_suspend_needs_abort_syscall ())
mono_threads_suspend_abort_syscall (info);
break;
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);
mono_thread_info_suspend_unlock ();
}
-gboolean
-mono_thread_info_unified_management_enabled (void)
-{
- return unified_suspend_enabled;
-}
-
/*
* mono_thread_info_set_is_async_context:
*
gpointer start_routine_arg;
gint32 priority;
MonoCoopSem registered;
- gpointer handle;
+ MonoThreadHandle *handle;
} CreateThreadData;
static gsize WINAPI
MonoThreadInfo *info;
MonoThreadStart start_routine;
gpointer start_routine_arg;
- guint32 start_routine_res;
+ gsize start_routine_res;
gsize dummy;
thread_data = (CreateThreadData*) data;
info = mono_thread_info_attach (&dummy);
info->runtime_thread = TRUE;
- thread_data->handle = mono_thread_info_duplicate_handle (info);
+ thread_data->handle = mono_threads_open_thread_handle (info->handle);
mono_coop_sem_post (&thread_data->registered);
/* Run the actual main function of the thread */
start_routine_res = start_routine (start_routine_arg);
- mono_threads_platform_exit (start_routine_res);
+ mono_thread_info_exit (start_routine_res);
g_assert_not_reached ();
}
* 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, gsize stack_size, MonoNativeThreadId *out_tid)
+MonoThreadHandle*
+mono_threads_create_thread (MonoThreadStart start, gpointer arg, gsize * const stack_size, MonoNativeThreadId *out_tid)
{
CreateThreadData *thread_data;
gint res;
- gpointer ret;
+ MonoThreadHandle *ret;
thread_data = g_new0 (CreateThreadData, 1);
thread_data->ref = 2;
((MonoThreadInfo*)info)->tls [key] = value;
}
+#if defined(__native_client__)
+void nacl_shutdown_gc_thread(void);
+#endif
+
/*
* mono_thread_info_exit:
*
* This function doesn't return.
*/
void
-mono_thread_info_exit (void)
+mono_thread_info_exit (gsize exit_code)
{
+#if defined(__native_client__)
+ nacl_shutdown_gc_thread();
+#endif
+
+ 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_threads_platform_open_thread_handle (handle, tid);
+ guint32 oldref, newref;
+
+ g_assert (thread_handle);
+
+ do {
+ oldref = thread_handle->ref;
+ if (!(oldref >= 1))
+ g_error ("%s: thread_handle %p has ref %u, it should be >= 1", __func__, thread_handle, oldref);
+
+ newref = oldref + 1;
+ } while (InterlockedCompareExchange ((gint32*) &thread_handle->ref, newref, oldref) != oldref);
+
+ return thread_handle;
}
void
-mono_threads_close_thread_handle (HANDLE handle)
+mono_threads_close_thread_handle (MonoThreadHandle *thread_handle)
{
- return mono_threads_platform_close_thread_handle (handle);
+ guint32 oldref, newref;
+
+ g_assert (thread_handle);
+
+ do {
+ oldref = thread_handle->ref;
+ if (!(oldref >= 1))
+ g_error ("%s: thread_handle %p has ref %u, it should be >= 1", __func__, thread_handle, oldref);
+
+ newref = oldref - 1;
+ } while (InterlockedCompareExchange ((gint32*) &thread_handle->ref, newref, oldref) != oldref);
+
+ if (newref == 0) {
+ mono_os_event_destroy (&thread_handle->event);
+ g_free (thread_handle);
+ }
+}
+
+static void
+mono_threads_signal_thread_handle (MonoThreadHandle* thread_handle)
+{
+ mono_os_event_set (&thread_handle->event);
}
#define INTERRUPT_STATE ((MonoThreadInfoInterruptToken*) (size_t) -1)
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_duplicate_handle (MonoThreadInfo *info)
-{
- g_assert (mono_thread_info_is_current (info));
- return mono_threads_platform_duplicate_handle (info);
+ res = mono_os_event_wait_one (&thread_handle->event, timeout);
+ 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_own_mutex (MonoThreadInfo *info, gpointer mutex_handle)
+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_own_mutex (info, mutex_handle);
-}
+ MonoOSEventWaitRet res;
+ MonoOSEvent *thread_events [MONO_OS_EVENT_WAIT_MAXIMUM_OBJECTS];
+ gint i;
-void
-mono_thread_info_disown_mutex (MonoThreadInfo *info, gpointer mutex_handle)
-{
- mono_threads_platform_disown_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);
+
+ 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);
+ 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);
}