#include <mono/metadata/marshal.h>
#include <mono/metadata/runtime.h>
#include <mono/metadata/object-internals.h>
-#include <mono/metadata/mono-debug-debugger.h>
+#include <mono/metadata/debug-internals.h>
#include <mono/utils/monobitset.h>
#include <mono/utils/mono-compiler.h>
#include <mono/utils/mono-mmap.h>
StaticDataFreeList *freelist;
} StaticDataInfo;
-/* Number of cached culture objects in the MonoThread->cached_culture_info array
- * (per-type): we use the first NUM entries for CultureInfo and the last for
- * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
- */
-#define NUM_CACHED_CULTURES 4
-#define CULTURES_START_IDX 0
-#define UICULTURES_START_IDX NUM_CACHED_CULTURES
-
/* Controls access to the 'threads' hash table */
static void mono_threads_lock (void);
static void mono_threads_unlock (void);
mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal);
static gboolean
-mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean force_domain, gsize *stack_ptr)
+mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean force_domain)
{
MonoThreadInfo *info;
MonoInternalThread *internal;
internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ());
internal->thread_info = info;
internal->small_id = info->small_id;
- internal->stack_ptr = stack_ptr;
THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), internal));
if (shutting_down && !force_attach) {
mono_threads_unlock ();
+ mono_thread_pop_appdomain_ref ();
return FALSE;
}
if (!threads) {
- MONO_GC_REGISTER_ROOT_FIXED (threads, MONO_ROOT_SOURCE_THREADING, "threads table");
threads = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "threads table");
}
MonoObject *start_delegate_arg;
MonoThreadStart start_func;
gpointer start_func_arg;
+ gboolean force_attach;
gboolean failed;
MonoCoopSem registered;
} StartInfo;
THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, mono_native_thread_id_get ()));
- if (!mono_thread_attach_internal (thread, FALSE, FALSE, stack_ptr)) {
+ if (!mono_thread_attach_internal (thread, start_info->force_attach, FALSE)) {
start_info->failed = TRUE;
mono_coop_sem_post (&start_info->registered);
return(0);
}
-static gsize WINAPI start_wrapper(void *data)
+static gsize WINAPI
+start_wrapper (gpointer data)
{
- volatile gsize dummy;
+ StartInfo *start_info;
+ MonoThreadInfo *info;
+ gsize res;
+
+ start_info = (StartInfo*) data;
+ g_assert (start_info);
+
+ info = mono_thread_info_attach (&res);
+ info->runtime_thread = TRUE;
+
+ /* Run the actual main function of the thread */
+ res = start_wrapper_internal (start_info, &res);
+
+ mono_thread_info_exit (res);
- return start_wrapper_internal ((StartInfo*) data, (gsize*) &dummy);
+ g_assert_not_reached ();
}
/*
*/
static gboolean
create_thread (MonoThread *thread, MonoInternalThread *internal, MonoObject *start_delegate, MonoThreadStart start_func, gpointer start_func_arg,
- gboolean threadpool_thread, guint32 stack_size, MonoError *error)
+ MonoThreadCreateFlags flags, MonoError *error)
{
StartInfo *start_info = NULL;
- MonoThreadHandle *thread_handle;
MonoNativeThreadId tid;
gboolean ret;
gsize stack_set_size;
if (start_func)
g_assert (!start_delegate);
+ if (flags & MONO_THREAD_CREATE_FLAGS_THREADPOOL) {
+ g_assert (!(flags & MONO_THREAD_CREATE_FLAGS_DEBUGGER));
+ g_assert (!(flags & MONO_THREAD_CREATE_FLAGS_FORCE_CREATE));
+ }
+ if (flags & MONO_THREAD_CREATE_FLAGS_DEBUGGER) {
+ g_assert (!(flags & MONO_THREAD_CREATE_FLAGS_THREADPOOL));
+ g_assert (!(flags & MONO_THREAD_CREATE_FLAGS_FORCE_CREATE));
+ }
+
/*
* Join joinable threads to prevent running out of threads since the finalizer
* thread might be blocked/backlogged.
*/
mono_threads_join_threads ();
- mono_error_init (error);
+ error_init (error);
mono_threads_lock ();
- if (shutting_down) {
+ if (shutting_down && !(flags & MONO_THREAD_CREATE_FLAGS_FORCE_CREATE)) {
mono_threads_unlock ();
return FALSE;
}
if (threads_starting_up == NULL) {
- MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up, MONO_ROOT_SOURCE_THREADING, "starting threads table");
threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
}
mono_g_hash_table_insert (threads_starting_up, thread, thread);
mono_threads_unlock ();
- internal->threadpool_thread = threadpool_thread;
- if (threadpool_thread)
+ internal->threadpool_thread = flags & MONO_THREAD_CREATE_FLAGS_THREADPOOL;
+ if (internal->threadpool_thread)
mono_thread_set_state (internal, ThreadState_Background);
+ internal->debugger_thread = flags & MONO_THREAD_CREATE_FLAGS_DEBUGGER;
+
start_info = g_new0 (StartInfo, 1);
start_info->ref = 2;
start_info->thread = thread;
start_info->start_delegate_arg = thread->start_obj;
start_info->start_func = start_func;
start_info->start_func_arg = start_func_arg;
+ start_info->force_attach = flags & MONO_THREAD_CREATE_FLAGS_FORCE_CREATE;
start_info->failed = FALSE;
mono_coop_sem_init (&start_info->registered, 0);
- if (stack_size == 0)
+ if (flags != MONO_THREAD_CREATE_FLAGS_SMALL_STACK)
stack_set_size = default_stacksize_for_thread (internal);
else
stack_set_size = 0;
- thread_handle = mono_threads_create_thread (start_wrapper, start_info, &stack_set_size, &tid);
-
- if (thread_handle == NULL) {
+ if (!mono_thread_platform_create_thread (start_wrapper, start_info, &stack_set_size, &tid)) {
/* The thread couldn't be created, so set an exception */
mono_threads_lock ();
mono_g_hash_table_remove (threads_starting_up, thread);
mono_coop_sem_wait (&start_info->registered, MONO_SEM_FLAGS_NONE);
- mono_threads_close_thread_handle (thread_handle);
-
THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
ret = !start_info->failed;
* ARG should not be a GC reference.
*/
MonoInternalThread*
-mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size, MonoError *error)
+mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, MonoThreadCreateFlags flags, MonoError *error)
{
MonoThread *thread;
MonoInternalThread *internal;
gboolean res;
- mono_error_init (error);
+ error_init (error);
internal = create_internal_thread_object ();
LOCK_THREAD (internal);
- res = create_thread (thread, internal, NULL, (MonoThreadStart) func, arg, threadpool_thread, stack_size, error);
- return_val_if_nok (error, NULL);
+ res = create_thread (thread, internal, NULL, (MonoThreadStart) func, arg, flags, error);
UNLOCK_THREAD (internal);
+ return_val_if_nok (error, NULL);
return internal;
}
gboolean
mono_thread_create_checked (MonoDomain *domain, gpointer func, gpointer arg, MonoError *error)
{
- return (NULL != mono_thread_create_internal (domain, func, arg, FALSE, 0, error));
+ return (NULL != mono_thread_create_internal (domain, func, arg, MONO_THREAD_CREATE_FLAGS_NONE, error));
}
MonoThread *
{
MonoInternalThread *internal;
MonoThread *thread;
+ MonoThreadInfo *info;
MonoNativeThreadId tid;
gsize stack_ptr;
return mono_thread_current ();
}
- if (!mono_gc_register_thread (&domain)) {
- 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.", mono_native_thread_id_get ());
- }
+ info = mono_thread_info_attach (&stack_ptr);
+ g_assert (info);
tid=mono_native_thread_id_get ();
thread = create_thread_object (domain, internal);
- if (!mono_thread_attach_internal (thread, force_attach, TRUE, &stack_ptr)) {
+ if (!mono_thread_attach_internal (thread, force_attach, TRUE)) {
/* Mono is shutting down, so just wait for the end */
for (;;)
mono_thread_info_sleep (10000, NULL);
thread->abort_exc = NULL;
thread->current_appcontext = NULL;
- /*
- * This is necessary because otherwise we might have
- * cross-domain references which will not get cleaned up when
- * the target domain is unloaded.
- */
- if (thread->cached_culture_info) {
- int i;
- for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
- mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
- }
-
/*
* thread->synch_cs can be NULL if this was called after
* ves_icall_System_Threading_InternalThread_Thread_free_internal.
if (thread == mono_thread_internal_current ())
mono_thread_pop_appdomain_ref ();
- thread->cached_culture_info = NULL;
-
mono_free_static_data (thread->static_data);
thread->static_data = NULL;
ref_stack_destroy (thread->appdomain_refs);
return this_obj;
}
- res = create_thread (this_obj, internal, start, NULL, NULL, FALSE, 0, &error);
+ res = create_thread (this_obj, internal, start, NULL, NULL, MONO_THREAD_CREATE_FLAGS_NONE, &error);
if (!res) {
mono_error_cleanup (&error);
UNLOCK_THREAD (internal);
MonoError error;
MonoString* str;
- mono_error_init (&error);
+ error_init (&error);
LOCK_THREAD (this_obj);
}
void
-mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean permanent, MonoError *error)
+mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean permanent, gboolean reset, MonoError *error)
{
LOCK_THREAD (this_obj);
- mono_error_init (error);
+ error_init (error);
- if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET)) {
+ if (reset) {
+ this_obj->flags &= ~MONO_THREAD_FLAG_NAME_SET;
+ } else if (this_obj->flags & MONO_THREAD_FLAG_NAME_SET) {
UNLOCK_THREAD (this_obj);
mono_error_set_invalid_operation (error, "Thread.Name can only be set once.");
this_obj->name_len = 0;
}
if (name) {
- this_obj->name = g_new (gunichar2, mono_string_length (name));
- memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
+ this_obj->name = g_memdup (mono_string_chars (name), mono_string_length (name) * sizeof (gunichar2));
this_obj->name_len = mono_string_length (name);
if (permanent)
ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
{
MonoError error;
- mono_thread_set_name_internal (this_obj, name, TRUE, &error);
+ mono_thread_set_name_internal (this_obj, name, TRUE, FALSE, &error);
mono_error_set_pending_exception (&error);
}
{
MonoArray *copy;
- mono_error_init (error);
+ error_init (error);
if (!arr)
return NULL;
gint32 diff_ms;
gint32 wait = ms;
- mono_error_init (error);
+ error_init (error);
start = (ms == -1) ? 0 : mono_msec_ticks ();
for (;;) {
gint32 diff_ms;
gint32 wait = ms;
- mono_error_init (error);
+ error_init (error);
start = (ms == -1) ? 0 : mono_100ns_ticks ();
do {
{
LOCK_THREAD (thread);
- if ((thread->state & ThreadState_AbortRequested) != 0 ||
- (thread->state & ThreadState_StopRequested) != 0 ||
- (thread->state & ThreadState_Stopped) != 0)
+ if (thread->state & (ThreadState_AbortRequested | ThreadState_Stopped))
{
UNLOCK_THREAD (thread);
return FALSE;
{
LOCK_THREAD (thread);
- if ((thread->state & ThreadState_Unstarted) != 0 ||
- (thread->state & ThreadState_Aborted) != 0 ||
- (thread->state & ThreadState_Stopped) != 0)
+ if (thread->state & (ThreadState_Unstarted | ThreadState_Aborted | ThreadState_Stopped))
{
UNLOCK_THREAD (thread);
return FALSE;
}
- if ((thread->state & ThreadState_Suspended) != 0 ||
- (thread->state & ThreadState_SuspendRequested) != 0 ||
- (thread->state & ThreadState_StopRequested) != 0)
+ if (thread->state & (ThreadState_Suspended | ThreadState_SuspendRequested | ThreadState_AbortRequested))
{
UNLOCK_THREAD (thread);
return TRUE;
return found;
}
-static gboolean
-request_thread_stop (MonoInternalThread *thread)
-{
- LOCK_THREAD (thread);
-
- if ((thread->state & ThreadState_StopRequested) != 0 ||
- (thread->state & ThreadState_Stopped) != 0)
- {
- UNLOCK_THREAD (thread);
- return FALSE;
- }
-
- /* Make sure the thread is awake */
- mono_thread_resume (thread);
-
- thread->state |= ThreadState_StopRequested;
- thread->state &= ~ThreadState_AbortRequested;
-
- UNLOCK_THREAD (thread);
- return TRUE;
-}
-
-/**
- * mono_thread_internal_stop:
- *
- * Request thread @thread to stop.
- *
- * @thread MUST NOT be the current thread.
- */
void
-mono_thread_internal_stop (MonoInternalThread *thread)
-{
- g_assert (thread != mono_thread_internal_current ());
-
- if (!request_thread_stop (thread))
- return;
-
- async_abort_internal (thread, TRUE);
-}
-
-void mono_thread_stop (MonoThread *thread)
+mono_thread_stop (MonoThread *thread)
{
MonoInternalThread *internal = thread->internal_thread;
- if (!request_thread_stop (internal))
+ if (!request_thread_abort (internal, NULL))
return;
-
+
if (internal == mono_thread_internal_current ()) {
MonoError error;
self_abort_internal (&error);
if (wait->num >= MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
return FALSE;
- /* The finalizer thread is not a background thread */
- if (!mono_native_thread_id_equals (thread_get_tid (thread), self)
- && (thread->state & ThreadState_Background) != 0
- && (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) == 0
- ) {
+ if (mono_native_thread_id_equals (thread_get_tid (thread), self))
+ return FALSE;
+ if (mono_gc_is_finalizer_internal_thread (thread))
+ return FALSE;
+
+ if ((thread->state & ThreadState_Background) && !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
wait->handles[wait->num] = mono_threads_open_thread_handle (thread->handle);
wait->threads[wait->num] = thread;
wait->num++;
THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
mono_thread_internal_abort (thread);
- return TRUE;
}
- return !mono_native_thread_id_equals (thread_get_tid (thread), self)
- && !mono_gc_is_finalizer_internal_thread (thread);
+ return TRUE;
}
/**
LOCK_THREAD (current_thread);
- if ((current_thread->state & ThreadState_SuspendRequested) ||
- (current_thread->state & ThreadState_AbortRequested) ||
- (current_thread->state & ThreadState_StopRequested)) {
+ if (current_thread->state & (ThreadState_SuspendRequested | ThreadState_AbortRequested)) {
UNLOCK_THREAD (current_thread);
mono_thread_execute_interruption ();
} else {
- current_thread->state |= ThreadState_Stopped;
UNLOCK_THREAD (current_thread);
}
LOCK_THREAD (thread);
- if ((thread->state & ThreadState_Suspended) != 0 ||
- (thread->state & ThreadState_StopRequested) != 0 ||
- (thread->state & ThreadState_Stopped) != 0) {
+ if (thread->state & (ThreadState_Suspended | ThreadState_Stopped)) {
UNLOCK_THREAD (thread);
mono_threads_close_thread_handle (wait->handles [i]);
wait->threads [i] = NULL;
MonoDebugSourceLocation *location;
int tindex, nthreads;
- mono_error_init (error);
+ error_init (error);
*out_threads = NULL;
*out_stack_frames = NULL;
return TRUE;
}
-static void
-clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
-{
- MonoInternalThread *thread = (MonoInternalThread*)value;
- MonoDomain *domain = (MonoDomain*)user_data;
- int i;
-
- /* No locking needed here */
- /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
-
- if (thread->cached_culture_info) {
- for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
- MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
- if (obj && obj->vtable->domain == domain)
- mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
- }
- }
-}
-
-/*
- * mono_threads_clear_cached_culture:
- *
- * Clear the cached_current_culture from all threads if it is in the
- * given appdomain.
- */
-void
-mono_threads_clear_cached_culture (MonoDomain *domain)
-{
- mono_threads_lock ();
- mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
- mono_threads_unlock ();
-}
-
/*
* mono_thread_get_undeniable_exception:
*
UNLOCK_THREAD (thread);
return exc;
- } else if ((thread->state & ThreadState_AbortRequested) != 0) {
+ } else if (thread->state & (ThreadState_AbortRequested)) {
UNLOCK_THREAD (thread);
g_assert (sys_thread->pending_exception == NULL);
if (thread->abort_exc == NULL) {
MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
}
return thread->abort_exc;
- }
- else if ((thread->state & ThreadState_SuspendRequested) != 0) {
+ } else if (thread->state & (ThreadState_SuspendRequested)) {
/* calls UNLOCK_THREAD (thread) */
self_suspend_internal ();
return NULL;
- }
- else if ((thread->state & ThreadState_StopRequested) != 0) {
- /* FIXME: do this through the JIT? */
-
- UNLOCK_THREAD (thread);
-
- mono_thread_exit ();
- return NULL;
} else if (thread->thread_interrupt_requested) {
thread->thread_interrupt_requested = FALSE;
if (thread == NULL)
return NULL;
-#ifdef HOST_WIN32
- if (thread->interrupt_on_stop &&
- thread->state & ThreadState_StopRequested &&
- thread->state & ThreadState_Background)
- ExitThread (1);
-#endif
if (!mono_thread_set_interruption_requested (thread))
return NULL;
InterlockedIncrement (&thread_interruption_requested);
return NULL;
LOCK_THREAD (thread);
- still_aborting = (thread->state & (ThreadState_AbortRequested|ThreadState_StopRequested)) != 0;
+ still_aborting = (thread->state & (ThreadState_AbortRequested)) != 0;
UNLOCK_THREAD (thread);
/*This can happen if the protected block called Thread::ResetAbort*/
if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
return MonoResumeThread;
- /*
- The target thread is running at least one protected block, which must not be interrupted, so we give up.
- The protected block code will give them a chance when appropriate.
- */
- if (mono_thread_get_abort_prot_block_count (thread) > 0)
- return MonoResumeThread;
-
/*someone is already interrupting it*/
if (!mono_thread_set_interruption_requested (thread))
return MonoResumeThread;
{
MonoException *exc;
- mono_error_init (error);
+ error_init (error);
/* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
* since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
event = thread->suspended;
MONO_ENTER_GC_SAFE;
- res = mono_os_event_wait_one (event, MONO_INFINITE_WAIT);
+ res = mono_os_event_wait_one (event, MONO_INFINITE_WAIT, TRUE);
g_assert (res == MONO_OS_EVENT_WAIT_RET_SUCCESS_0 || res == MONO_OS_EVENT_WAIT_RET_ALERTED);
MONO_EXIT_GC_SAFE;
}
+static void
+suspend_for_shutdown_async_call (gpointer unused)
+{
+ for (;;)
+ mono_thread_info_yield ();
+}
+
+static SuspendThreadResult
+suspend_for_shutdown_critical (MonoThreadInfo *info, gpointer unused)
+{
+ mono_thread_info_setup_async_call (info, suspend_for_shutdown_async_call, NULL);
+ return MonoResumeThread;
+}
+
+void
+mono_thread_internal_suspend_for_shutdown (MonoInternalThread *thread)
+{
+ g_assert (thread != mono_thread_internal_current ());
+
+ mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, suspend_for_shutdown_critical, NULL);
+}
+
/*
* mono_thread_is_foreign:
* @thread: the thread to query
if (thread != pthread_self ()) {
MONO_ENTER_GC_SAFE;
/* This shouldn't block */
+ mono_threads_join_lock ();
mono_native_thread_join (thread);
+ mono_threads_join_unlock ();
MONO_EXIT_GC_SAFE;
}
} else {
#endif
}
-void
-mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
-{
- if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
- mono_thread_interruption_checkpoint ();
-}
-
void
mono_thread_internal_unhandled_exception (MonoObject* exc)
{
thread = mono_thread_internal_current ();
LOCK_THREAD (thread);
- if (thread->state & (MonoThreadState)(ThreadState_StopRequested | ThreadState_SuspendRequested | ThreadState_AbortRequested)) {
+ if (thread->state & (ThreadState_SuspendRequested | ThreadState_AbortRequested)) {
UNLOCK_THREAD (thread);
return FALSE;
}