From 668ee608ebba8031ea189dc050470e49499bbc63 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Thu, 8 Sep 2016 17:17:28 +0200 Subject: [PATCH] [threads] Factor common attach code in mono_thread_attach_internal (#3530) * [threads] Allocate StartInfo in create_thread * [threads] Put start_notify semaphore in StartInfo * [threads] Factor common attach code in mono_thread_attach_internal * [threads] Use same registered mechanism as mono-threads --- mcs/class/corlib/System.Threading/Thread.cs | 4 +- mcs/class/corlib/System/Environment.cs | 2 +- mono/metadata/appdomain.c | 2 +- mono/metadata/object-internals.h | 6 +- mono/metadata/threads.c | 471 +++++++++----------- 5 files changed, 212 insertions(+), 273 deletions(-) diff --git a/mcs/class/corlib/System.Threading/Thread.cs b/mcs/class/corlib/System.Threading/Thread.cs index f1924b22e07..f3bec17722a 100644 --- a/mcs/class/corlib/System.Threading/Thread.cs +++ b/mcs/class/corlib/System.Threading/Thread.cs @@ -65,7 +65,6 @@ namespace System.Threading { /* start_notify is used by the runtime to signal that Start() * is ok to return */ - private IntPtr start_notify; private IntPtr stack_ptr; private UIntPtr static_data; /* GC-tracked */ private IntPtr runtime_thread_info; @@ -90,11 +89,12 @@ namespace System.Threading { private IntPtr interrupt_on_stop; private IntPtr flags; private IntPtr thread_pinning_ref; - private IntPtr start_notify_refcount; + private IntPtr abort_protected_block_count; /* * These fields are used to avoid having to increment corlib versions * when a new field is added to the unmanaged MonoThread structure. */ + private IntPtr unused1; private IntPtr unused2; #endregion #pragma warning restore 169, 414, 649 diff --git a/mcs/class/corlib/System/Environment.cs b/mcs/class/corlib/System/Environment.cs index 36ae8687aae..bbe43954a3b 100644 --- a/mcs/class/corlib/System/Environment.cs +++ b/mcs/class/corlib/System/Environment.cs @@ -57,7 +57,7 @@ namespace System { * of icalls, do not require an increment. */ #pragma warning disable 169 - private const int mono_corlib_version = 153; + private const int mono_corlib_version = 154; #pragma warning restore 169 [ComVisible (true)] diff --git a/mono/metadata/appdomain.c b/mono/metadata/appdomain.c index 38f4569430b..79c8406d46f 100644 --- a/mono/metadata/appdomain.c +++ b/mono/metadata/appdomain.c @@ -83,7 +83,7 @@ * Changes which are already detected at runtime, like the addition * of icalls, do not require an increment. */ -#define MONO_CORLIB_VERSION 153 +#define MONO_CORLIB_VERSION 154 typedef struct { diff --git a/mono/metadata/object-internals.h b/mono/metadata/object-internals.h index 9d128319a76..06d558d60db 100644 --- a/mono/metadata/object-internals.h +++ b/mono/metadata/object-internals.h @@ -357,7 +357,6 @@ struct _MonoInternalThread { MonoException *abort_exc; int abort_state_handle; guint64 tid; /* This is accessed as a gsize in the code (so it can hold a 64bit pointer on systems that need it), but needs to reserve 64 bits of space on all machines as it corresponds to a field in managed code */ - MonoCoopSem *start_notify; gpointer stack_ptr; gpointer *static_data; void *thread_info; /*This is MonoThreadInfo*, but to simplify dependencies, let's make it a void* here. */ @@ -380,14 +379,15 @@ struct _MonoInternalThread { gpointer interrupt_on_stop; gsize flags; gpointer thread_pinning_ref; + gsize abort_protected_block_count; /* * These fields are used to avoid having to increment corlib versions * when a new field is added to this structure. * Please synchronize any changes with InternalThread in Thread.cs, i.e. add the * same field there. */ - gsize start_notify_refcount; - gsize abort_protected_block_count; + gsize unused1; + gsize unused2; }; struct _MonoThread { diff --git a/mono/metadata/threads.c b/mono/metadata/threads.c index 239d6ffb899..4c3ca385941 100644 --- a/mono/metadata/threads.c +++ b/mono/metadata/threads.c @@ -83,15 +83,6 @@ extern int tkill (pid_t tid, int signal); #define LOCK_THREAD(thread) lock_thread((thread)) #define UNLOCK_THREAD(thread) unlock_thread((thread)) -typedef struct -{ - guint32 (*func)(void *); - MonoThread *obj; - MonoObject *delegate; - void *start_arg; - MonoCoopSem registered; -} StartInfo; - typedef union { gint32 ival; gfloat fval; @@ -152,7 +143,7 @@ static MonoReferenceQueue *context_queue; /* * Threads which are starting up and they are not in the 'threads' hash yet. - * When handle_store is called for a thread, it will be removed from this hash table. + * When mono_thread_attach_internal is called for a thread, it will be removed from this hash table. * Protected by mono_threads_lock (). */ static MonoGHashTable *threads_starting_up = NULL; @@ -193,7 +184,6 @@ static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL; static guint32 default_stacksize = 0; #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize) -static void thread_adjust_static_data (MonoInternalThread *thread); static void context_adjust_static_data (MonoAppContext *ctx); static void mono_free_static_data (gpointer* static_data); static void mono_init_static_data_info (StaticDataInfo *static_data); @@ -271,87 +261,6 @@ thread_get_tid (MonoInternalThread *thread) return MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid); } -/* handle_store() and handle_remove() manage the array of threads that - * still need to be waited for when the main thread exits. - * - * If handle_store() returns FALSE the thread must not be started - * because Mono is shutting down. - */ -static gboolean handle_store(MonoThread *thread, gboolean force_attach) -{ - mono_threads_lock (); - - THREAD_DEBUG (g_message ("%s: thread %p ID %"G_GSIZE_FORMAT, __func__, thread, (gsize)thread->internal_thread->tid)); - - if (threads_starting_up) - mono_g_hash_table_remove (threads_starting_up, thread); - - if (shutting_down && !force_attach) { - mono_threads_unlock (); - return FALSE; - } - - if(threads==NULL) { - 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"); - } - - /* We don't need to duplicate thread->handle, because it is - * only closed when the thread object is finalized by the GC. - */ - g_assert (thread->internal_thread); - mono_g_hash_table_insert(threads, (gpointer)(gsize)(thread->internal_thread->tid), - thread->internal_thread); - - mono_threads_unlock (); - - return TRUE; -} - -static gboolean handle_remove(MonoInternalThread *thread) -{ - gboolean ret; - gsize tid = thread->tid; - - THREAD_DEBUG (g_message ("%s: thread ID %"G_GSIZE_FORMAT, __func__, tid)); - - mono_threads_lock (); - - if (threads) { - /* We have to check whether the thread object for the - * tid is still the same in the table because the - * thread might have been destroyed and the tid reused - * in the meantime, in which case the tid would be in - * the table, but with another thread object. - */ - if (mono_g_hash_table_lookup (threads, (gpointer)tid) == thread) { - mono_g_hash_table_remove (threads, (gpointer)tid); - ret = TRUE; - } else { - ret = FALSE; - } - } - else - ret = FALSE; - - mono_threads_unlock (); - - /* Don't close the handle here, wait for the object finalizer - * to do it. Otherwise, the following race condition applies: - * - * 1) Thread exits (and handle_remove() closes the handle) - * - * 2) Some other handle is reassigned the same slot - * - * 3) Another thread tries to join the first thread, and - * blocks waiting for the reassigned handle to be signalled - * (which might never happen). This is possible, because the - * thread calling Join() still has a reference to the first - * thread's object. - */ - return ret; -} - static void ensure_synch_cs_set (MonoInternalThread *thread) { MonoCoopMutex *synch_cs; @@ -407,6 +316,8 @@ is_threadabort_exception (MonoClass *klass) */ static void thread_cleanup (MonoInternalThread *thread) { + gboolean ret; + g_assert (thread != NULL); if (thread->abort_state_handle) { @@ -455,13 +366,45 @@ static void thread_cleanup (MonoInternalThread *thread) if (InterlockedExchange (&thread->interruption_requested, 0)) InterlockedDecrement (&thread_interruption_requested); + mono_threads_lock (); + + if (!threads) { + ret = FALSE; + } else if (mono_g_hash_table_lookup (threads, (gpointer)thread->tid) != thread) { + /* We have to check whether the thread object for the + * tid is still the same in the table because the + * thread might have been destroyed and the tid reused + * in the meantime, in which case the tid would be in + * the table, but with another thread object. + */ + ret = FALSE; + } else { + mono_g_hash_table_remove (threads, (gpointer)thread->tid); + ret = TRUE; + } + + mono_threads_unlock (); + + /* Don't close the handle here, wait for the object finalizer + * to do it. Otherwise, the following race condition applies: + * + * 1) Thread exits (and thread_cleanup() closes the handle) + * + * 2) Some other handle is reassigned the same slot + * + * 3) Another thread tries to join the first thread, and + * blocks waiting for the reassigned handle to be signalled + * (which might never happen). This is possible, because the + * thread calling Join() still has a reference to the first + * thread's object. + */ + /* if the thread is not in the hash it has been removed already */ - if (!handle_remove (thread)) { + if (!ret) { if (thread == mono_thread_internal_current ()) { mono_domain_unset (); mono_memory_barrier (); } - /* This needs to be called even if handle_remove () fails */ if (mono_thread_cleanup_fn) mono_thread_cleanup_fn (thread_get_tid (thread)); return; @@ -637,91 +580,146 @@ create_internal_thread (void) return thread; } +static void +mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal); + static gboolean -init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate) +mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean force_domain, gsize *stack_ptr) { - MonoDomain *domain = mono_get_root_domain (); + MonoThreadInfo *info; + MonoInternalThread *internal; + MonoDomain *domain, *root_domain; + + g_assert (thread); + + info = mono_thread_info_current (); + + internal = thread->internal_thread; + internal->handle = mono_thread_info_get_handle (info); + 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)); + + SET_CURRENT_OBJECT (internal); + + domain = mono_object_domain (thread); + + mono_thread_push_appdomain_ref (domain); + if (!mono_domain_set (domain, force_domain)) { + mono_thread_pop_appdomain_ref (); + return FALSE; + } + + mono_threads_lock (); - if (!candidate || candidate->obj.vtable->domain != domain) { - candidate = new_thread_with_internal (domain, thread); + if (threads_starting_up) + mono_g_hash_table_remove (threads_starting_up, thread); + + if (shutting_down && !force_attach) { + mono_threads_unlock (); + 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"); + } + + /* We don't need to duplicate thread->handle, because it is + * only closed when the thread object is finalized by the GC. */ + mono_g_hash_table_insert (threads, (gpointer)(gsize)(internal->tid), internal); + + /* We have to do this here because mono_thread_start_cb + * requires that root_domain_thread is set up. */ + if (thread_static_info.offset || thread_static_info.idx > 0) { + /* get the current allocated size */ + guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0); + mono_alloc_static_data (&internal->static_data, offset, TRUE); } - set_current_thread_for_domain (domain, thread, candidate); - g_assert (!thread->root_domain_thread); - MONO_OBJECT_SETREF (thread, root_domain_thread, candidate); + + mono_threads_unlock (); + + root_domain = mono_get_root_domain (); + + g_assert (!internal->root_domain_thread); + if (domain != root_domain) + MONO_OBJECT_SETREF (internal, root_domain_thread, new_thread_with_internal (root_domain, internal)); + else + MONO_OBJECT_SETREF (internal, root_domain_thread, thread); + + if (domain != root_domain) + set_current_thread_for_domain (root_domain, internal, internal->root_domain_thread); + + set_current_thread_for_domain (domain, internal, thread); + + THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, internal->tid, internal->handle)); + return TRUE; } -static guint32 WINAPI start_wrapper_internal(void *data) +typedef struct { + gint32 ref; + MonoThread *thread; + MonoObject *start_delegate; + MonoObject *start_delegate_arg; + MonoThreadStart start_func; + gpointer start_func_arg; + gboolean failed; + MonoCoopSem registered; +} StartInfo; + +static guint32 WINAPI start_wrapper_internal(StartInfo *start_info, gsize *stack_ptr) { MonoError error; - MonoThreadInfo *info; - StartInfo *start_info = (StartInfo *)data; - guint32 (*start_func)(void *); - void *start_arg; + MonoThreadStart start_func; + void *start_func_arg; gsize tid; /* - * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a + * We don't create a local to hold start_info->thread, so hopefully it won't get pinned during a * GC stack walk. */ + MonoThread *thread; MonoInternalThread *internal; MonoObject *start_delegate; + MonoObject *start_delegate_arg; MonoDomain *domain; - mono_coop_sem_wait (&start_info->registered, MONO_SEM_FLAGS_NONE); - - internal = start_info->obj->internal_thread; - start_delegate = start_info->delegate; - domain = start_info->obj->obj.vtable->domain; + thread = start_info->thread; + internal = thread->internal_thread; + domain = mono_object_domain (start_info->thread); THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, mono_native_thread_id_get ())); - /* We can be sure start_info->obj->tid and - * start_info->obj->handle have been set, because the thread - * was created suspended, and these values were set before the - * thread resumed - */ + if (!mono_thread_attach_internal (thread, FALSE, FALSE, stack_ptr)) { + start_info->failed = TRUE; - info = mono_thread_info_current (); - g_assert (info); - internal->thread_info = info; - internal->small_id = info->small_id; - - tid = internal->tid; + mono_coop_sem_post (&start_info->registered); - SET_CURRENT_OBJECT (internal); + if (InterlockedDecrement (&start_info->ref) == 0) { + mono_coop_sem_destroy (&start_info->registered); + g_free (start_info); + } - /* Every thread references the appdomain which created it */ - mono_thread_push_appdomain_ref (domain); - - if (!mono_domain_set (domain, FALSE)) { - /* No point in raising an appdomain_unloaded exception here */ - /* FIXME: Cleanup here */ - mono_thread_pop_appdomain_ref (); return 0; } - start_func = start_info->func; - start_arg = start_info->obj->start_obj; - if (!start_arg) - start_arg = start_info->start_arg; + tid = internal->tid; - /* We have to do this here because mono_thread_new_init() - requires that root_domain_thread is set up. */ - thread_adjust_static_data (internal); - init_root_domain_thread (internal, start_info->obj); + start_delegate = start_info->start_delegate; + start_delegate_arg = start_info->start_delegate_arg; + start_func = start_info->start_func; + start_func_arg = start_info->start_func_arg; /* This MUST be called before any managed code can be * executed, as it calls the callback function that (for the * jit) sets the lmf marker. */ - mono_thread_new_init (tid, &tid, start_func); - internal->stack_ptr = &tid; - if (domain != mono_get_root_domain ()) - set_current_thread_for_domain (domain, internal, start_info->obj); - LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, mono_native_thread_id_get (), getpid (), thread->stack_ptr)); - - THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), internal)); + if (mono_thread_start_cb) + mono_thread_start_cb (tid, stack_ptr, start_func); /* On 2.0 profile (and higher), set explicitly since state might have been Unknown */ @@ -730,21 +728,16 @@ static guint32 WINAPI start_wrapper_internal(void *data) mono_thread_init_apartment_state (); - if (internal->start_notify) - /* Let the thread that called Start() know we're - * ready - */ - mono_coop_sem_post (internal->start_notify); + /* Let the thread that called Start() know we're ready */ + mono_coop_sem_post (&start_info->registered); - if (InterlockedDecrement ((gint32*)&internal->start_notify_refcount) == 0) { - mono_coop_sem_destroy (internal->start_notify); - g_free (internal->start_notify); - internal->start_notify = NULL; + if (InterlockedDecrement (&start_info->ref) == 0) { + mono_coop_sem_destroy (&start_info->registered); + g_free (start_info); } - g_free (start_info); - THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__, - internal->tid)); + /* start_info is not valid anymore */ + start_info = NULL; /* * Call this after calling start_notify, since the profiler callback might want @@ -763,12 +756,14 @@ static guint32 WINAPI start_wrapper_internal(void *data) /* start_func is set only for unmanaged start functions */ if (start_func) { - start_func (start_arg); + start_func (start_func_arg); } else { void *args [1]; + g_assert (start_delegate != NULL); - args [0] = start_arg; + /* we may want to handle the exception here. See comment below on unhandled exceptions */ + args [0] = (gpointer) start_delegate_arg; mono_runtime_delegate_invoke_checked (start_delegate, args, &error); if (!mono_error_ok (&error)) { @@ -820,12 +815,12 @@ static guint32 WINAPI start_wrapper_internal(void *data) static gsize WINAPI start_wrapper(void *data) { - volatile int dummy; + volatile gsize dummy; /* Avoid scanning the frames above this frame during a GC */ mono_gc_set_stack_end ((void*)&dummy); - return start_wrapper_internal (data); + return start_wrapper_internal ((StartInfo*) data, (gsize*) &dummy); } /* @@ -835,12 +830,19 @@ static gsize WINAPI start_wrapper(void *data) * LOCKING: Acquires the threads lock. */ static gboolean -create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *start_info, gboolean threadpool_thread, guint32 stack_size, - MonoError *error) +create_thread (MonoThread *thread, MonoInternalThread *internal, MonoObject *start_delegate, MonoThreadStart start_func, gpointer start_func_arg, + gboolean threadpool_thread, guint32 stack_size, MonoError *error) { + StartInfo *start_info = NULL; HANDLE thread_handle; MonoNativeThreadId tid; MonoThreadParm tp; + gboolean ret; + + if (start_delegate) + g_assert (!start_func && !start_func_arg); + if (start_func) + g_assert (!start_delegate); /* * Join joinable threads to prevent running out of threads since the finalizer @@ -852,7 +854,6 @@ create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *star mono_threads_lock (); if (shutting_down) { - g_free (start_info); mono_threads_unlock (); return FALSE; } @@ -863,18 +864,23 @@ create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *star mono_g_hash_table_insert (threads_starting_up, thread, thread); mono_threads_unlock (); - internal->start_notify = g_new0 (MonoCoopSem, 1); - mono_coop_sem_init (internal->start_notify, 0); - internal->start_notify_refcount = 2; + internal->threadpool_thread = threadpool_thread; + if (threadpool_thread) + mono_thread_set_state (internal, ThreadState_Background); + start_info = g_new0 (StartInfo, 1); + start_info->ref = 2; + start_info->thread = thread; + start_info->start_delegate = start_delegate; + start_info->start_delegate_arg = thread->start_obj; + start_info->start_func = start_func; + start_info->start_func_arg = start_func_arg; + start_info->failed = FALSE; mono_coop_sem_init (&start_info->registered, 0); if (stack_size == 0) stack_size = default_stacksize_for_thread (internal); - /* Create suspended, so we can do some housekeeping before the thread - * starts - */ tp.priority = thread->priority; tp.stack_size = stack_size; tp.creation_flags = 0; @@ -886,51 +892,35 @@ create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *star mono_threads_lock (); mono_g_hash_table_remove (threads_starting_up, thread); mono_threads_unlock (); - mono_coop_sem_destroy (&start_info->registered); - g_free (start_info); mono_error_set_execution_engine (error, "Couldn't create thread. Error 0x%x", GetLastError()); - return FALSE; + /* ref is not going to be decremented in start_wrapper_internal */ + InterlockedDecrement (&start_info->ref); + ret = FALSE; + goto done; } - THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle)); - - 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); THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), 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)) { - mono_coop_sem_destroy (&start_info->registered); - return FALSE; - } - - mono_coop_sem_post (&start_info->registered); - /* * 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__, mono_native_thread_id_get (), internal, (gsize)internal->tid)); - mono_coop_sem_wait (internal->start_notify, MONO_SEM_FLAGS_NONE); - if (InterlockedDecrement ((gint32*)&internal->start_notify_refcount) == 0) { - mono_coop_sem_destroy (internal->start_notify); - g_free (internal->start_notify); - internal->start_notify = NULL; - } + mono_coop_sem_wait (&start_info->registered, MONO_SEM_FLAGS_NONE); 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)); - return TRUE; + ret = !start_info->failed; + +done: + if (InterlockedDecrement (&start_info->ref) == 0) { + mono_coop_sem_destroy (&start_info->registered); + g_free (start_info); + } + + return ret; } void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func) @@ -960,7 +950,6 @@ mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gb { MonoThread *thread; MonoInternalThread *internal; - StartInfo *start_info; gboolean res; mono_error_init (error); @@ -972,18 +961,13 @@ mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gb MONO_OBJECT_SETREF (thread, internal_thread, internal); - start_info = g_new0 (StartInfo, 1); - start_info->func = (guint32 (*)(void *))func; - start_info->obj = thread; - start_info->start_arg = arg; - - res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, error); + res = create_thread (thread, internal, NULL, (MonoThreadStart) func, arg, threadpool_thread, stack_size, error); return_val_if_nok (error, NULL); /* Check that the managed and unmanaged layout of MonoInternalThread matches */ #ifndef MONO_CROSS_COMPILE if (mono_check_corlib_version () == NULL) - g_assert (((char*)&internal->abort_protected_block_count - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset); + g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset); #endif return internal; @@ -1014,12 +998,12 @@ mono_thread_attach (MonoDomain *domain) MonoThread * mono_thread_attach_full (MonoDomain *domain, gboolean force_attach) { - MonoThreadInfo *info; - MonoInternalThread *thread; - MonoThread *current_thread; + MonoInternalThread *internal; + MonoThread *thread; MonoNativeThreadId tid; + gsize stack_ptr; - if ((thread = mono_thread_internal_current ())) { + if ((internal = mono_thread_internal_current ())) { if (domain != mono_domain_get ()) mono_domain_set (domain, TRUE); /* Already attached */ @@ -1030,40 +1014,19 @@ 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 before in the file containing the thread creation code.", mono_native_thread_id_get ()); } - info = mono_thread_info_current (); - tid=mono_native_thread_id_get (); - thread = create_internal_thread (); - thread->handle = mono_thread_info_get_handle (info); - thread->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid); - thread->stack_ptr = &tid; - - THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread->handle)); - - thread->thread_info = info; - thread->small_id = info->small_id; + internal = create_internal_thread (); - current_thread = new_thread_with_internal (domain, thread); + thread = new_thread_with_internal (domain, internal); - if (!handle_store (current_thread, force_attach)) { + if (!mono_thread_attach_internal (thread, force_attach, TRUE, &stack_ptr)) { /* Mono is shutting down, so just wait for the end */ for (;;) mono_thread_info_sleep (10000, NULL); } - THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), thread)); - - SET_CURRENT_OBJECT (thread); - mono_domain_set (domain, TRUE); - - thread_adjust_static_data (thread); - - init_root_domain_thread (thread, current_thread); - - if (domain != mono_get_root_domain ()) - set_current_thread_for_domain (domain, thread, current_thread); - + THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, internal->handle)); if (mono_thread_attach_cb) { guint8 *staddr; @@ -1072,17 +1035,17 @@ mono_thread_attach_full (MonoDomain *domain, gboolean force_attach) mono_thread_info_get_stack_bounds (&staddr, &stsize); if (staddr == NULL) - mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), &tid); + mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), &stack_ptr); else mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), staddr + stsize); } /* Can happen when we attach the profiler helper thread in order to heapshot. */ - if (!info->tools_thread) + if (!mono_thread_info_current ()->tools_thread) // FIXME: Need a separate callback mono_profiler_thread_start (MONO_NATIVE_THREAD_ID_TO_UINT (tid)); - return current_thread; + return thread; } void @@ -1167,7 +1130,6 @@ ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj, MonoObject *start) { MonoError error; - StartInfo *start_info; MonoInternalThread *internal; gboolean res; @@ -1189,15 +1151,8 @@ ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj, UNLOCK_THREAD (internal); return this_obj; } - /* This is freed in start_wrapper */ - start_info = g_new0 (StartInfo, 1); - start_info->func = NULL; - start_info->start_arg = NULL; - start_info->delegate = start; - start_info->obj = this_obj; - g_assert (this_obj->obj.vtable->domain == mono_domain_get ()); - res = create_thread (this_obj, internal, start_info, FALSE, 0, &error); + res = create_thread (this_obj, internal, start, NULL, NULL, FALSE, 0, &error); if (!res) { mono_error_cleanup (&error); UNLOCK_THREAD (internal); @@ -4146,22 +4101,6 @@ mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 return offset; } -/* - * ensure thread static fields already allocated are valid for thread - * This function is called when a thread is created or on thread attach. - */ -static void -thread_adjust_static_data (MonoInternalThread *thread) -{ - mono_threads_lock (); - if (thread_static_info.offset || thread_static_info.idx > 0) { - /* get the current allocated size */ - guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0); - mono_alloc_static_data (&thread->static_data, offset, TRUE); - } - mono_threads_unlock (); -} - /* * LOCKING: requires that threads_mutex is held */ -- 2.25.1