/* * 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, gsize * const stack_size, MonoNativeThreadId *out_tid) { CreateThreadData *thread_data; gint res; gpointer ret; thread_data = g_new0 (CreateThreadData, 1); thread_data->ref = 2; thread_data->start_routine = start; thread_data->start_routine_arg = arg; mono_coop_sem_init (&thread_data->registered, 0); res = mono_threads_platform_create_thread (inner_start_thread, (gpointer) thread_data, stack_size, out_tid); if (res != 0) { /* ref is not going to be decremented in inner_start_thread */ InterlockedDecrement (&thread_data->ref); ret = NULL; goto done; } res = mono_coop_sem_wait (&thread_data->registered, MONO_SEM_FLAGS_NONE); g_assert (res == 0); ret = thread_data->handle; g_assert (ret); done: if (InterlockedDecrement (&thread_data->ref) == 0) { mono_coop_sem_destroy (&thread_data->registered); g_free (thread_data); } return ret; }
static void create_thread_data_destroy (gpointer data) { CreateThreadData *thread_data; thread_data = (CreateThreadData*) data; mono_coop_sem_destroy (&thread_data->registered); g_free (thread_data); }
static gsize WINAPI inner_start_thread (gpointer data) { CreateThreadData *thread_data; MonoThreadInfo *info; MonoThreadStart start_routine; gpointer start_routine_arg; guint32 start_routine_res; gint32 priority; gsize dummy; thread_data = (CreateThreadData*) data; g_assert (thread_data); start_routine = thread_data->start_routine; start_routine_arg = thread_data->start_routine_arg; priority = thread_data->priority; info = mono_thread_info_attach (&dummy); info->runtime_thread = TRUE; mono_threads_platform_set_priority (info, priority); thread_data->handle = mono_thread_info_duplicate_handle (info); mono_coop_sem_post (&thread_data->registered); if (InterlockedDecrement (&thread_data->ref) == 0) { mono_coop_sem_destroy (&thread_data->registered); g_free (thread_data); } /* thread_data is not valid anymore */ thread_data = NULL; /* Run the actual main function of the thread */ start_routine_res = start_routine (start_routine_arg); mono_threads_platform_exit (start_routine_res); g_assert_not_reached (); }
HANDLE mono_threads_core_create_thread (LPTHREAD_START_ROUTINE start_routine, gpointer arg, MonoThreadParm *tp, MonoNativeThreadId *out_tid) { ThreadStartInfo *start_info; HANDLE result; DWORD thread_id; guint32 creation_flags = tp->creation_flags; int res; start_info = g_malloc0 (sizeof (ThreadStartInfo)); if (!start_info) return NULL; mono_coop_sem_init (&(start_info->registered), 0); start_info->arg = arg; start_info->start_routine = start_routine; start_info->suspend = creation_flags & CREATE_SUSPENDED; creation_flags &= ~CREATE_SUSPENDED; if (start_info->suspend) { start_info->suspend_event = CreateEvent (NULL, TRUE, FALSE, NULL); if (!start_info->suspend_event) return NULL; } result = CreateThread (NULL, tp->stack_size, inner_start_thread, start_info, creation_flags, &thread_id); if (result) { res = mono_coop_sem_wait (&(start_info->registered), MONO_SEM_FLAGS_NONE); g_assert (res != -1); if (start_info->suspend) { g_assert (SuspendThread (result) != (DWORD)-1); SetEvent (start_info->suspend_event); } } else if (start_info->suspend) { CloseHandle (start_info->suspend_event); } if (out_tid) *out_tid = thread_id; mono_coop_sem_destroy (&(start_info->registered)); g_free (start_info); return result; }
gboolean mono_domain_finalize (MonoDomain *domain, guint32 timeout) { DomainFinalizationReq *req; MonoInternalThread *thread = mono_thread_internal_current (); gint res; gboolean ret; gint64 start; #if defined(__native_client__) return FALSE; #endif if (mono_thread_internal_current () == gc_thread) /* We are called from inside a finalizer, not much we can do here */ return FALSE; /* * No need to create another thread 'cause the finalizer thread * is still working and will take care of running the finalizers */ if (gc_disabled) return TRUE; /* We don't support domain finalization without a GC */ if (mono_gc_is_null ()) return FALSE; mono_gc_collect (mono_gc_max_generation ()); req = g_new0 (DomainFinalizationReq, 1); req->ref = 2; req->domain = domain; mono_coop_sem_init (&req->done, 0); if (domain == mono_get_root_domain ()) finalizing_root_domain = TRUE; mono_finalizer_lock (); domains_to_finalize = g_slist_append (domains_to_finalize, req); mono_finalizer_unlock (); /* Tell the finalizer thread to finalize this appdomain */ mono_gc_finalize_notify (); if (timeout == -1) timeout = INFINITE; if (timeout != INFINITE) start = mono_msec_ticks (); ret = TRUE; for (;;) { if (timeout == INFINITE) { res = mono_coop_sem_wait (&req->done, MONO_SEM_FLAGS_ALERTABLE); } else { gint64 elapsed = mono_msec_ticks () - start; if (elapsed >= timeout) { ret = FALSE; break; } res = mono_coop_sem_timedwait (&req->done, timeout - elapsed, MONO_SEM_FLAGS_ALERTABLE); } if (res == MONO_SEM_TIMEDWAIT_RET_SUCCESS) { break; } else if (res == MONO_SEM_TIMEDWAIT_RET_ALERTED) { if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0) { ret = FALSE; break; } } else if (res == MONO_SEM_TIMEDWAIT_RET_TIMEDOUT) { ret = FALSE; break; } else { g_error ("%s: unknown result %d", __func__, res); } } if (!ret) { /* Try removing the req from domains_to_finalize: * - if it's not found: the domain is being finalized, * so we the ref count is already decremented * - if it's found: the domain is not yet being finalized, * so we can safely decrement the ref */ gboolean found; mono_finalizer_lock (); found = g_slist_index (domains_to_finalize, req) != -1; if (found) domains_to_finalize = g_slist_remove (domains_to_finalize, req); mono_finalizer_unlock (); if (found) { /* We have to decrement it wherever we * remove it from domains_to_finalize */ if (InterlockedDecrement (&req->ref) != 1) g_error ("%s: req->ref should be 1, as we are the first one to decrement it", __func__); } goto done; } if (domain == mono_get_root_domain ()) { mono_threadpool_ms_cleanup (); mono_gc_finalize_threadpool_threads (); } done: if (InterlockedDecrement (&req->ref) == 0) { mono_coop_sem_destroy (&req->done); g_free (req); } return ret; }