MonoThread *obj;
MonoObject *delegate;
void *start_arg;
- MonoDomain *domain;
};
typedef union {
static StaticDataInfo thread_static_info;
static StaticDataInfo context_static_info;
-/* The hash of existing threads (key is thread ID) that need joining
- * before exit
+/* The hash of existing threads (key is thread ID, value is
+ * MonoInternalThread*) that need joining before exit
*/
static MonoGHashTable *threads=NULL;
* Protected by mono_threads_lock ().
*/
static MonoGHashTable *threads_starting_up = NULL;
+
+/* Maps a MonoThread to its start argument */
+/* Protected by mono_threads_lock () */
+static MonoGHashTable *thread_start_args = NULL;
/* The TLS key that holds the MonoObject assigned to each thread */
static guint32 current_object_key = -1;
/* we need to use both the Tls* functions and __thread because
* the gc needs to see all the threads
*/
-static __thread MonoThread * tls_current_object MONO_TLS_FAST;
+static __thread MonoInternalThread * tls_current_object MONO_TLS_FAST;
#define SET_CURRENT_OBJECT(x) do { \
tls_current_object = x; \
TlsSetValue (current_object_key, x); \
} while (FALSE)
#define GET_CURRENT_OBJECT() tls_current_object
#else
-#define SET_CURRENT_OBJECT(x) TlsSetValue (current_object_key, x);
-#define GET_CURRENT_OBJECT() (MonoThread*) TlsGetValue (current_object_key);
+#define SET_CURRENT_OBJECT(x) TlsSetValue (current_object_key, x)
+#define GET_CURRENT_OBJECT() (MonoThread*) TlsGetValue (current_object_key)
#endif
/* function called at thread start */
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 (MonoThread *thread);
+static void thread_adjust_static_data (MonoInternalThread *thread);
static void mono_init_static_data_info (StaticDataInfo *static_data);
static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
-static gboolean mono_thread_resume (MonoThread* thread);
+static gboolean mono_thread_resume (MonoInternalThread* thread);
static void mono_thread_start (MonoThread *thread);
-static void signal_thread_state_change (MonoThread *thread);
+static void signal_thread_state_change (MonoInternalThread *thread);
+
+static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread);
/* Spin lock for InterlockedXXX 64 bit functions */
#define mono_interlocked_lock() EnterCriticalSection (&interlocked_mutex)
static int small_id_table_size = 0;
static int small_id_next = 0;
static int highest_small_id = -1;
-static MonoThread **small_id_table = NULL;
+static MonoInternalThread **small_id_table = NULL;
/* The hazard table */
#define HAZARD_TABLE_MAX_SIZE 16384 /* There cannot be more threads than this number. */
if(threads==NULL) {
MONO_GC_REGISTER_ROOT (threads);
- threads=mono_g_hash_table_new(NULL, NULL);
+ threads=mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
}
/* 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)(thread->tid),
- thread);
+ 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(MonoThread *thread)
+static gboolean handle_remove(MonoInternalThread *thread)
{
gboolean ret;
gsize tid = thread->tid;
* domain_id_alloc() in domain.c and should be merged.
*/
static int
-small_id_alloc (MonoThread *thread)
+small_id_alloc (MonoInternalThread *thread)
{
int id = -1, i;
if (!small_id_table) {
small_id_table_size = 2;
- small_id_table = mono_gc_alloc_fixed (small_id_table_size * sizeof (MonoThread*), NULL);
+ small_id_table = mono_gc_alloc_fixed (small_id_table_size * sizeof (MonoInternalThread*), NULL);
}
for (i = small_id_next; i < small_id_table_size; ++i) {
if (!small_id_table [i]) {
}
}
if (id == -1) {
- MonoThread **new_table;
+ MonoInternalThread **new_table;
int new_size = small_id_table_size * 2;
if (new_size >= (1 << 16))
g_assert_not_reached ();
id = small_id_table_size;
- new_table = mono_gc_alloc_fixed (new_size * sizeof (MonoThread*), NULL);
+ new_table = mono_gc_alloc_fixed (new_size * sizeof (MonoInternalThread*), NULL);
memcpy (new_table, small_id_table, small_id_table_size * sizeof (void*));
mono_gc_free_fixed (small_id_table);
small_id_table = new_table;
MonoThreadHazardPointers*
mono_hazard_pointer_get (void)
{
- MonoThread *current_thread = mono_thread_current ();
+ MonoInternalThread *current_thread = mono_thread_internal_current ();
if (!(current_thread && current_thread->small_id >= 0)) {
static MonoThreadHazardPointers emerg_hazard_table;
try_free_delayed_free_item (i);
}
-static void ensure_synch_cs_set (MonoThread *thread)
+static void ensure_synch_cs_set (MonoInternalThread *thread)
{
CRITICAL_SECTION *synch_cs;
* make sure no code called from it will ever assume it is run on the thread that is
* getting cleaned up.
*/
-static void thread_cleanup (MonoThread *thread)
+static void thread_cleanup (MonoInternalThread *thread)
{
g_assert (thread != NULL);
+ if (thread->abort_state_handle) {
+ g_assert (thread->abort_exc);
+ mono_gchandle_free (thread->abort_state_handle);
+ thread->abort_state_handle = 0;
+ }
+ 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);
+ }
+
/* if the thread is not in the hash it has been removed already */
if (!handle_remove (thread))
return;
mono_profiler_thread_end (thread->tid);
- if (thread == mono_thread_current ())
+ if (thread == mono_thread_internal_current ())
mono_thread_pop_appdomain_ref ();
- if (thread->serialized_culture_info)
- g_free (thread->serialized_culture_info);
-
- g_free (thread->name);
-
thread->cached_culture_info = NULL;
mono_gc_free_fixed (thread->static_data);
thread->static_data = NULL;
if (mono_thread_cleanup_fn)
- mono_thread_cleanup_fn (thread);
+ mono_thread_cleanup_fn (thread->root_domain_thread);
small_id_free (thread->small_id);
thread->small_id = -2;
}
+static gpointer
+get_thread_static_data (MonoInternalThread *thread, guint32 offset)
+{
+ int idx;
+ g_assert ((offset & 0x80000000) == 0);
+ offset &= 0x7fffffff;
+ idx = (offset >> 24) - 1;
+ return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
+}
+
+static MonoThread**
+get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
+{
+ static MonoClassField *current_thread_field = NULL;
+
+ guint32 offset;
+
+ if (!current_thread_field) {
+ current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
+ g_assert (current_thread_field);
+ }
+
+ mono_class_vtable (domain, mono_defaults.thread_class);
+ mono_domain_lock (domain);
+ offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
+ mono_domain_unlock (domain);
+ g_assert (offset);
+
+ return get_thread_static_data (thread, offset);
+}
+
+static void
+set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
+{
+ MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
+
+ g_assert (current->obj.vtable->domain == domain);
+
+ g_assert (!*current_thread_ptr);
+ *current_thread_ptr = current;
+}
+
+static MonoThread*
+new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal)
+{
+ MonoThread *thread = (MonoThread*) mono_object_new (domain, mono_defaults.thread_class);
+ thread->internal_thread = internal;
+ return thread;
+}
+
+static void
+init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
+{
+ MonoDomain *domain = mono_get_root_domain ();
+
+ if (!candidate || candidate->obj.vtable->domain != domain)
+ candidate = new_thread_with_internal (domain, thread);
+ set_current_thread_for_domain (domain, thread, candidate);
+ g_assert (!thread->root_domain_thread);
+ thread->root_domain_thread = candidate;
+}
+
static guint32 WINAPI start_wrapper(void *data)
{
struct StartInfo *start_info=(struct StartInfo *)data;
void *start_arg;
gsize tid;
MonoThread *thread=start_info->obj;
+ MonoInternalThread *internal = thread->internal_thread;
MonoObject *start_delegate = start_info->delegate;
THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, GetCurrentThreadId ()));
* thread resumed
*/
- tid=thread->tid;
+ tid=internal->tid;
- SET_CURRENT_OBJECT (thread);
+ SET_CURRENT_OBJECT (internal);
mono_monitor_init_tls ();
/* Every thread references the appdomain which created it */
- mono_thread_push_appdomain_ref (start_info->domain);
+ mono_thread_push_appdomain_ref (thread->obj.vtable->domain);
- if (!mono_domain_set (start_info->domain, FALSE)) {
+ if (!mono_domain_set (thread->obj.vtable->domain, FALSE)) {
/* No point in raising an appdomain_unloaded exception here */
/* FIXME: Cleanup here */
mono_thread_pop_appdomain_ref ();
start_func = start_info->func;
start_arg = start_info->start_arg;
+ /* 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, thread);
+
/* 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);
- thread->stack_ptr = &tid;
+ internal->stack_ptr = &tid;
LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, GetCurrentThreadId (), getpid (), thread->stack_ptr));
/* On 2.0 profile (and higher), set explicitly since state might have been
Unknown */
if (mono_framework_version () != 1) {
- if (thread->apartment_state == ThreadApartmentState_Unknown)
- thread->apartment_state = ThreadApartmentState_MTA;
+ if (internal->apartment_state == ThreadApartmentState_Unknown)
+ internal->apartment_state = ThreadApartmentState_MTA;
}
mono_thread_init_apartment_state ();
- if(thread->start_notify!=NULL) {
+ if(internal->start_notify!=NULL) {
/* Let the thread that called Start() know we're
* ready
*/
- ReleaseSemaphore (thread->start_notify, 1, NULL);
+ ReleaseSemaphore (internal->start_notify, 1, NULL);
}
- MONO_GC_UNREGISTER_ROOT (start_info->start_arg);
- g_free (start_info);
+ mono_threads_lock ();
+ mono_g_hash_table_remove (thread_start_args, thread);
+ mono_threads_unlock ();
- thread_adjust_static_data (thread);
+ g_free (start_info);
#ifdef DEBUG
g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
thread->tid);
#endif
+ mono_thread_set_execution_context (thread->ec_to_set);
+ thread->ec_to_set = NULL;
+
/* start_func is set only for unmanaged start functions */
if (start_func) {
start_func (start_arg);
THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, GetCurrentThreadId ()));
- thread_cleanup (thread);
+ thread_cleanup (internal);
/* Do any cleanup needed for apartment state. This
* cannot be done in thread_cleanup since thread_cleanup could be
return default_stacksize;
}
-void mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread)
+/*
+ * mono_create_thread:
+ *
+ * This is a wrapper around CreateThread which handles differences in the type of
+ * the the 'tid' argument.
+ */
+gpointer mono_create_thread (WapiSecurityAttributes *security,
+ guint32 stacksize, WapiThreadStart start,
+ gpointer param, guint32 create, gsize *tid)
+{
+ gpointer res;
+
+#ifdef PLATFORM_WIN32
+ DWORD real_tid;
+
+ res = CreateThread (security, stacksize, start, param, create, &real_tid);
+ if (tid)
+ *tid = real_tid;
+#else
+ res = CreateThread (security, stacksize, start, param, create, tid);
+#endif
+
+ return res;
+}
+
+MonoInternalThread* mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread)
{
MonoThread *thread;
+ MonoInternalThread *internal;
HANDLE thread_handle;
struct StartInfo *start_info;
gsize tid;
thread=(MonoThread *)mono_object_new (domain,
mono_defaults.thread_class);
+ internal = (MonoInternalThread*)mono_object_new (mono_get_root_domain (),
+ mono_defaults.internal_thread_class);
+ thread->internal_thread = internal;
start_info=g_new0 (struct StartInfo, 1);
start_info->func = func;
start_info->obj = thread;
- start_info->domain = domain;
start_info->start_arg = arg;
- /*
- * The argument may be an object reference, and there is no ref to keep it alive
- * when the new thread is started but not yet registered with the collector.
- */
- MONO_GC_REGISTER_ROOT (start_info->start_arg);
-
mono_threads_lock ();
if (shutting_down) {
mono_threads_unlock ();
- return;
+ g_free (start_info);
+ return NULL;
}
if (threads_starting_up == NULL) {
MONO_GC_REGISTER_ROOT (threads_starting_up);
threads_starting_up = mono_g_hash_table_new (NULL, NULL);
}
- mono_g_hash_table_insert (threads_starting_up, thread, thread);
+ if (thread_start_args == NULL) {
+ MONO_GC_REGISTER_ROOT (thread_start_args);
+ thread_start_args = mono_g_hash_table_new (NULL, NULL);
+ }
+ mono_g_hash_table_insert (threads_starting_up, thread, thread);
+ /*
+ * The argument may be an object reference, and there is no ref to keep it alive
+ * when the new thread is started but not yet registered with the collector. So
+ * we store it in a GC tracked hash table.
+ */
+ mono_g_hash_table_insert (thread_start_args, thread, start_info->start_arg);
mono_threads_unlock ();
/* Create suspended, so we can do some housekeeping before the thread
* starts
*/
- thread_handle = CreateThread(NULL, default_stacksize_for_thread (thread), (LPTHREAD_START_ROUTINE)start_wrapper, start_info,
+ thread_handle = mono_create_thread (NULL, default_stacksize_for_thread (internal), (LPTHREAD_START_ROUTINE)start_wrapper, start_info,
CREATE_SUSPENDED, &tid);
THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
if (thread_handle == NULL) {
/* The thread couldn't be created, so throw an exception */
- MONO_GC_UNREGISTER_ROOT (start_info->start_arg);
mono_threads_lock ();
mono_g_hash_table_remove (threads_starting_up, thread);
mono_threads_unlock ();
g_free (start_info);
mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
- return;
+ return NULL;
}
- thread->handle=thread_handle;
- thread->tid=tid;
- thread->apartment_state=ThreadApartmentState_Unknown;
- small_id_alloc (thread);
+ internal->handle=thread_handle;
+ internal->tid=tid;
+ internal->apartment_state=ThreadApartmentState_Unknown;
+ small_id_alloc (internal);
- thread->synch_cs = g_new0 (CRITICAL_SECTION, 1);
- InitializeCriticalSection (thread->synch_cs);
+ internal->synch_cs = g_new0 (CRITICAL_SECTION, 1);
+ InitializeCriticalSection (internal->synch_cs);
- thread->threadpool_thread = threadpool_thread;
+ internal->threadpool_thread = threadpool_thread;
if (threadpool_thread)
- mono_thread_set_state (thread, ThreadState_Background);
+ mono_thread_set_state (internal, ThreadState_Background);
if (handle_store (thread))
ResumeThread (thread_handle);
+
+ return internal;
}
void
guint8 *current = (guint8*)&attr;
pthread_attr_init (&attr);
-#ifdef HAVE_PTHREAD_GETATTR_NP
+# ifdef HAVE_PTHREAD_GETATTR_NP
pthread_getattr_np (pthread_self(), &attr);
-#else
-#ifdef HAVE_PTHREAD_ATTR_GET_NP
+# else
+# ifdef HAVE_PTHREAD_ATTR_GET_NP
pthread_attr_get_np (pthread_self(), &attr);
-#elif defined(sun)
+# elif defined(sun)
*staddr = NULL;
pthread_attr_getstacksize (&attr, &stsize);
-#else
+# else
*staddr = NULL;
*stsize = 0;
return;
-#endif
-#endif
+# endif
+# endif
-#ifndef sun
+# ifndef sun
pthread_attr_getstack (&attr, (void**)staddr, stsize);
if (*staddr)
g_assert ((current > *staddr) && (current < *staddr + *stsize));
-#endif
+# endif
pthread_attr_destroy (&attr);
#endif
MonoThread *
mono_thread_attach (MonoDomain *domain)
{
- MonoThread *thread;
+ MonoInternalThread *thread;
+ MonoThread *current_thread;
HANDLE thread_handle;
gsize tid;
- if ((thread = mono_thread_current ())) {
+ if ((thread = mono_thread_internal_current ())) {
if (domain != mono_domain_get ())
mono_domain_set (domain, TRUE);
/* Already attached */
- return thread;
+ 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.", GetCurrentThreadId ());
}
- thread = (MonoThread *)mono_object_new (domain,
- mono_defaults.thread_class);
+ thread = (MonoInternalThread *)mono_object_new (domain, mono_defaults.internal_thread_class);
thread_handle = GetCurrentThread ();
g_assert (thread_handle);
THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
- if (!handle_store (thread)) {
+ current_thread = new_thread_with_internal (domain, thread);
+
+ if (!handle_store (current_thread)) {
/* Mono is shutting down, so just wait for the end */
for (;;)
Sleep (10000);
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);
+
+
if (mono_thread_attach_cb) {
guint8 *staddr;
size_t stsize;
mono_thread_attach_cb (tid, staddr + stsize);
}
- return(thread);
+ return current_thread;
}
void
THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
- thread_cleanup (thread);
+ thread_cleanup (thread->internal_thread);
SET_CURRENT_OBJECT (NULL);
void
mono_thread_exit ()
{
- MonoThread *thread = mono_thread_current ();
+ MonoInternalThread *thread = mono_thread_internal_current ();
THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
SET_CURRENT_OBJECT (NULL);
/* we could add a callback here for embedders to use. */
- if (thread == mono_thread_get_main ())
+ if (thread == mono_thread_get_main ()->internal_thread)
exit (mono_environment_exitcode_get ());
ExitThread (-1);
}
+void
+ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this)
+{
+ MonoInternalThread *internal = (MonoInternalThread*)mono_object_new (mono_get_root_domain (), mono_defaults.internal_thread_class);
+ internal->state = ThreadState_Unstarted;
+ internal->apartment_state = ThreadApartmentState_Unknown;
+
+ InterlockedCompareExchangePointer ((gpointer)&this->internal_thread, internal, NULL);
+}
+
HANDLE ves_icall_System_Threading_Thread_Thread_internal(MonoThread *this,
MonoObject *start)
{
struct StartInfo *start_info;
HANDLE thread;
gsize tid;
-
- MONO_ARCH_SAVE_REGS;
+ MonoInternalThread *internal;
THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this, start));
- ensure_synch_cs_set (this);
+ if (!this->internal_thread)
+ ves_icall_System_Threading_Thread_ConstructInternalThread (this);
+ internal = this->internal_thread;
- EnterCriticalSection (this->synch_cs);
+ ensure_synch_cs_set (internal);
- if ((this->state & ThreadState_Unstarted) == 0) {
- LeaveCriticalSection (this->synch_cs);
+ EnterCriticalSection (internal->synch_cs);
+
+ if ((internal->state & ThreadState_Unstarted) == 0) {
+ LeaveCriticalSection (internal->synch_cs);
mono_raise_exception (mono_get_exception_thread_state ("Thread has already been started."));
return NULL;
}
- this->small_id = -1;
+ internal->small_id = -1;
- if ((this->state & ThreadState_Aborted) != 0) {
- LeaveCriticalSection (this->synch_cs);
+ if ((internal->state & ThreadState_Aborted) != 0) {
+ LeaveCriticalSection (internal->synch_cs);
return this;
}
start_func = NULL;
start_info->start_arg = this->start_obj; /* FIXME: GC object stored in unmanaged memory */
start_info->delegate = start;
start_info->obj = this;
- start_info->domain = mono_domain_get ();
+ g_assert (this->obj.vtable->domain == mono_domain_get ());
- this->start_notify=CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
- if(this->start_notify==NULL) {
- LeaveCriticalSection (this->synch_cs);
+ internal->start_notify=CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
+ if (internal->start_notify==NULL) {
+ LeaveCriticalSection (internal->synch_cs);
g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
+ g_free (start_info);
return(NULL);
}
mono_g_hash_table_insert (threads_starting_up, this, this);
mono_threads_unlock ();
- thread=CreateThread(NULL, default_stacksize_for_thread (this), (LPTHREAD_START_ROUTINE)start_wrapper, start_info,
+ thread=mono_create_thread(NULL, default_stacksize_for_thread (internal), (LPTHREAD_START_ROUTINE)start_wrapper, start_info,
CREATE_SUSPENDED, &tid);
if(thread==NULL) {
- LeaveCriticalSection (this->synch_cs);
+ LeaveCriticalSection (internal->synch_cs);
mono_threads_lock ();
mono_g_hash_table_remove (threads_starting_up, this);
mono_threads_unlock ();
return(NULL);
}
- this->handle=thread;
- this->tid=tid;
- small_id_alloc (this);
+ internal->handle=thread;
+ internal->tid=tid;
+ small_id_alloc (internal);
/* Don't call handle_store() here, delay it to Start.
* We can't join a thread (trying to will just block
mono_thread_start (this);
- this->state &= ~ThreadState_Unstarted;
+ internal->state &= ~ThreadState_Unstarted;
THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
- LeaveCriticalSection (this->synch_cs);
+ LeaveCriticalSection (internal->synch_cs);
return(thread);
}
}
-void ves_icall_System_Threading_Thread_Thread_init (MonoThread *this)
+void ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this, HANDLE thread)
{
MONO_ARCH_SAVE_REGS;
- ensure_synch_cs_set (this);
-}
+ THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
-void ves_icall_System_Threading_Thread_Thread_free_internal (MonoThread *this,
- HANDLE thread)
-{
- MONO_ARCH_SAVE_REGS;
+ if (thread)
+ CloseHandle (thread);
- THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
+ if (this->synch_cs) {
+ DeleteCriticalSection (this->synch_cs);
+ g_free (this->synch_cs);
+ this->synch_cs = NULL;
+ }
- CloseHandle (thread);
+ g_assert (!this->abort_exc && !this->abort_state_handle);
- DeleteCriticalSection (this->synch_cs);
- g_free (this->synch_cs);
- this->synch_cs = NULL;
+ g_free (this->name);
}
static void mono_thread_start (MonoThread *thread)
{
- MONO_ARCH_SAVE_REGS;
+ MonoInternalThread *internal = thread->internal_thread;
THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
if (!handle_store (thread))
return;
- ResumeThread (thread->handle);
+ ResumeThread (internal->handle);
- if(thread->start_notify!=NULL) {
+ if(internal->start_notify!=NULL) {
/* 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
THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
- WaitForSingleObjectEx (thread->start_notify, INFINITE, FALSE);
- CloseHandle (thread->start_notify);
- thread->start_notify = NULL;
+ WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
+ CloseHandle (internal->start_notify);
+ internal->start_notify = NULL;
}
THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
void ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
{
- MonoThread *thread = mono_thread_current ();
-
- MONO_ARCH_SAVE_REGS;
+ guint32 res;
+ MonoInternalThread *thread = mono_thread_internal_current ();
THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
- SleepEx(ms,TRUE);
+ res = SleepEx(ms,TRUE);
mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
+
+ if (res == WAIT_IO_COMPLETION) { /* we might have been interrupted */
+ MonoException* exc = mono_thread_execute_interruption (thread);
+ if (exc) mono_raise_exception (exc);
+ }
}
void ves_icall_System_Threading_Thread_SpinWait_nop (void)
}
MonoString*
-ves_icall_System_Threading_Thread_GetName_internal (MonoThread *this_obj)
+ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
{
MonoString* str;
}
void
-ves_icall_System_Threading_Thread_SetName_internal (MonoThread *this_obj, MonoString *name)
+ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
{
ensure_synch_cs_set (this_obj);
}
static MonoObject*
-lookup_cached_culture (MonoThread *this, MonoDomain *domain, int start_idx)
+lookup_cached_culture (MonoInternalThread *this, MonoDomain *domain, int start_idx)
{
MonoObject *res;
int i;
return NULL;
}
-MonoObject*
-ves_icall_System_Threading_Thread_GetCachedCurrentCulture (MonoThread *this)
+/* If the array is already in the requested domain, we just return it,
+ otherwise we return a copy in that domain. */
+static MonoArray*
+byte_array_to_domain (MonoArray *arr, MonoDomain *domain)
{
- return lookup_cached_culture (this, mono_domain_get (), CULTURES_START_IDX);
+ MonoArray *copy;
+
+ if (!arr)
+ return NULL;
+
+ if (mono_object_domain (arr) == domain)
+ return arr;
+
+ copy = mono_array_new (domain, mono_defaults.byte_class, arr->max_length);
+ memcpy (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
+ return copy;
}
MonoArray*
-ves_icall_System_Threading_Thread_GetSerializedCurrentCulture (MonoThread *this)
+ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
{
- MonoArray *res;
-
- ensure_synch_cs_set (this);
-
- EnterCriticalSection (this->synch_cs);
-
- if (this->serialized_culture_info) {
- res = mono_array_new (mono_domain_get (), mono_defaults.byte_class, this->serialized_culture_info_len);
- memcpy (mono_array_addr (res, guint8, 0), this->serialized_culture_info, this->serialized_culture_info_len);
- } else {
- res = NULL;
- }
+ return byte_array_to_domain (arr, mono_get_root_domain ());
+}
- LeaveCriticalSection (this->synch_cs);
+MonoArray*
+ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
+{
+ return byte_array_to_domain (arr, mono_domain_get ());
+}
- return res;
+MonoObject*
+ves_icall_System_Threading_Thread_GetCachedCurrentCulture (MonoInternalThread *this)
+{
+ return lookup_cached_culture (this, mono_domain_get (), CULTURES_START_IDX);
}
static void
-cache_culture (MonoThread *this, MonoObject *culture, int start_idx)
+cache_culture (MonoInternalThread *this, MonoObject *culture, int start_idx)
{
int i;
MonoDomain *domain = mono_domain_get ();
EnterCriticalSection (this->synch_cs);
if (!this->cached_culture_info)
- MONO_OBJECT_SETREF (this, cached_culture_info, mono_array_new_cached (mono_object_domain (this), mono_defaults.object_class, NUM_CACHED_CULTURES * 2));
+ MONO_OBJECT_SETREF (this, cached_culture_info, mono_array_new_cached (mono_get_root_domain (), mono_defaults.object_class, NUM_CACHED_CULTURES * 2));
for (i = start_idx; i < start_idx + NUM_CACHED_CULTURES; ++i) {
obj = mono_array_get (this->cached_culture_info, MonoObject*, i);
void
ves_icall_System_Threading_Thread_SetCachedCurrentCulture (MonoThread *this, MonoObject *culture)
{
- cache_culture (this, culture, CULTURES_START_IDX);
-}
-
-void
-ves_icall_System_Threading_Thread_SetSerializedCurrentCulture (MonoThread *this, MonoArray *arr)
-{
- ensure_synch_cs_set (this);
-
- EnterCriticalSection (this->synch_cs);
-
- if (this->serialized_culture_info)
- g_free (this->serialized_culture_info);
- this->serialized_culture_info = g_new0 (guint8, mono_array_length (arr));
- this->serialized_culture_info_len = mono_array_length (arr);
- memcpy (this->serialized_culture_info, mono_array_addr (arr, guint8, 0), mono_array_length (arr));
-
- LeaveCriticalSection (this->synch_cs);
+ MonoDomain *domain = mono_object_get_domain (&this->obj);
+ g_assert (domain == mono_domain_get ());
+ cache_culture (this->internal_thread, culture, CULTURES_START_IDX);
}
-
MonoObject*
-ves_icall_System_Threading_Thread_GetCachedCurrentUICulture (MonoThread *this)
+ves_icall_System_Threading_Thread_GetCachedCurrentUICulture (MonoInternalThread *this)
{
return lookup_cached_culture (this, mono_domain_get (), UICULTURES_START_IDX);
}
-MonoArray*
-ves_icall_System_Threading_Thread_GetSerializedCurrentUICulture (MonoThread *this)
-{
- MonoArray *res;
-
- ensure_synch_cs_set (this);
-
- EnterCriticalSection (this->synch_cs);
-
- if (this->serialized_ui_culture_info) {
- res = mono_array_new (mono_domain_get (), mono_defaults.byte_class, this->serialized_ui_culture_info_len);
- memcpy (mono_array_addr (res, guint8, 0), this->serialized_ui_culture_info, this->serialized_ui_culture_info_len);
- } else {
- res = NULL;
- }
-
- LeaveCriticalSection (this->synch_cs);
-
- return res;
-}
-
void
ves_icall_System_Threading_Thread_SetCachedCurrentUICulture (MonoThread *this, MonoObject *culture)
{
- cache_culture (this, culture, UICULTURES_START_IDX);
+ MonoDomain *domain = mono_object_get_domain (&this->obj);
+ g_assert (domain == mono_domain_get ());
+ cache_culture (this->internal_thread, culture, UICULTURES_START_IDX);
}
-void
-ves_icall_System_Threading_Thread_SetSerializedCurrentUICulture (MonoThread *this, MonoArray *arr)
+MonoThread *
+mono_thread_current (void)
{
- ensure_synch_cs_set (this);
-
- EnterCriticalSection (this->synch_cs);
-
- if (this->serialized_ui_culture_info)
- g_free (this->serialized_ui_culture_info);
- this->serialized_ui_culture_info = g_new0 (guint8, mono_array_length (arr));
- this->serialized_ui_culture_info_len = mono_array_length (arr);
- memcpy (this->serialized_ui_culture_info, mono_array_addr (arr, guint8, 0), mono_array_length (arr));
+ MonoDomain *domain = mono_domain_get ();
+ MonoInternalThread *internal = mono_thread_internal_current ();
+ MonoThread **current_thread_ptr;
- LeaveCriticalSection (this->synch_cs);
+ g_assert (internal);
+ current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
+
+ if (!*current_thread_ptr) {
+ g_assert (domain != mono_get_root_domain ());
+ *current_thread_ptr = new_thread_with_internal (domain, internal);
+ }
+ return *current_thread_ptr;
}
-/* the jit may read the compiled code of this function */
-MonoThread *
-mono_thread_current (void)
+MonoInternalThread*
+mono_thread_internal_current (void)
{
- MonoThread *res = GET_CURRENT_OBJECT ()
+ MonoInternalThread *res = GET_CURRENT_OBJECT ();
THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
return res;
}
-gboolean ves_icall_System_Threading_Thread_Join_internal(MonoThread *this,
+gboolean ves_icall_System_Threading_Thread_Join_internal(MonoInternalThread *this,
int ms, HANDLE thread)
{
- MonoThread *cur_thread = mono_thread_current ();
+ MonoInternalThread *cur_thread = mono_thread_internal_current ();
gboolean ret;
-
- MONO_ARCH_SAVE_REGS;
-
+
mono_thread_current_check_pending_interrupt ();
ensure_synch_cs_set (this);
guint32 ret;
guint32 i;
MonoObject *waitHandle;
- MonoThread *thread = mono_thread_current ();
-
- MONO_ARCH_SAVE_REGS;
+ MonoInternalThread *thread = mono_thread_internal_current ();
/* Do this WaitSleepJoin check before creating objects */
mono_thread_current_check_pending_interrupt ();
guint32 ret;
guint32 i;
MonoObject *waitHandle;
- MonoThread *thread = mono_thread_current ();
-
- MONO_ARCH_SAVE_REGS;
+ MonoInternalThread *thread = mono_thread_internal_current ();
/* Do this WaitSleepJoin check before creating objects */
mono_thread_current_check_pending_interrupt ();
gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this, HANDLE handle, gint32 ms, gboolean exitContext)
{
guint32 ret;
- MonoThread *thread = mono_thread_current ();
-
- MONO_ARCH_SAVE_REGS;
+ MonoInternalThread *thread = mono_thread_internal_current ();
THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, GetCurrentThreadId (), handle, ms));
ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms, gboolean exitContext)
{
guint32 ret;
- MonoThread *thread = mono_thread_current ();
+ MonoInternalThread *thread = mono_thread_internal_current ();
MONO_ARCH_SAVE_REGS;
MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
{
- MONO_ARCH_SAVE_REGS;
+ MonoObject *res;
+ res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
+ mono_gc_wbarrier_generic_nostore (location);
+ return res;
+}
- return (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
+gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
+{
+ return InterlockedExchangePointer(location, value);
}
gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
{
- MONO_ARCH_SAVE_REGS;
+ MonoObject *res;
+ res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
+ mono_gc_wbarrier_generic_nostore (location);
+ return res;
+}
- return (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
+gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
+{
+ return InterlockedCompareExchangePointer(location, value, comparand);
}
gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
MonoObject*
ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
{
- MONO_ARCH_SAVE_REGS;
-
- return InterlockedCompareExchangePointer ((gpointer *)location, value, comparand);
+ MonoObject *res;
+ res = InterlockedCompareExchangePointer ((gpointer *)location, value, comparand);
+ mono_gc_wbarrier_generic_nostore (location);
+ return res;
}
MonoObject*
ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
{
- MONO_ARCH_SAVE_REGS;
-
- return InterlockedExchangePointer ((gpointer *)location, value);
+ MonoObject *res;
+ res = InterlockedExchangePointer ((gpointer *)location, value);
+ mono_gc_wbarrier_generic_nostore (location);
+ return res;
}
gint32
}
void
-ves_icall_System_Threading_Thread_ClrState (MonoThread* this, guint32 state)
+ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this, guint32 state)
{
mono_thread_clr_state (this, state);
}
void
-ves_icall_System_Threading_Thread_SetState (MonoThread* this, guint32 state)
+ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this, guint32 state)
{
mono_thread_set_state (this, state);
}
guint32
-ves_icall_System_Threading_Thread_GetState (MonoThread* this)
+ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this)
{
guint32 state;
return state;
}
-void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this)
+void ves_icall_System_Threading_Thread_Interrupt_internal (MonoInternalThread *this)
{
gboolean throw = FALSE;
ensure_synch_cs_set (this);
- if (this == mono_thread_current ())
+ if (this == mono_thread_internal_current ())
return;
EnterCriticalSection (this->synch_cs);
void mono_thread_current_check_pending_interrupt ()
{
- MonoThread *thread = mono_thread_current ();
+ MonoInternalThread *thread = mono_thread_internal_current ();
gboolean throw = FALSE;
mono_debugger_check_interruption ();
* Tells the thread that his state has changed and it has to enter the new
* state as soon as possible.
*/
-static void signal_thread_state_change (MonoThread *thread)
+static void signal_thread_state_change (MonoInternalThread *thread)
{
- if (thread == mono_thread_current ()) {
+ if (thread == mono_thread_internal_current ()) {
/* Do it synchronously */
MonoException *exc = mono_thread_request_interruption (FALSE);
if (exc)
}
void
-ves_icall_System_Threading_Thread_Abort (MonoThread *thread, MonoObject *state)
+ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
{
- MONO_ARCH_SAVE_REGS;
-
ensure_synch_cs_set (thread);
EnterCriticalSection (thread->synch_cs);
}
thread->state |= ThreadState_AbortRequested;
- MONO_OBJECT_SETREF (thread, abort_state, state);
+ if (thread->abort_state_handle)
+ mono_gchandle_free (thread->abort_state_handle);
+ if (state) {
+ thread->abort_state_handle = mono_gchandle_new (state, FALSE);
+ g_assert (thread->abort_state_handle);
+ } else {
+ thread->abort_state_handle = 0;
+ }
thread->abort_exc = NULL;
LeaveCriticalSection (thread->synch_cs);
void
ves_icall_System_Threading_Thread_ResetAbort (void)
{
- MonoThread *thread = mono_thread_current ();
-
- MONO_ARCH_SAVE_REGS;
+ MonoInternalThread *thread = mono_thread_internal_current ();
ensure_synch_cs_set (thread);
mono_raise_exception (mono_get_exception_thread_state (msg));
} else {
thread->abort_exc = NULL;
- thread->abort_state = NULL;
+ if (thread->abort_state_handle) {
+ mono_gchandle_free (thread->abort_state_handle);
+ /* This is actually not necessary - the handle
+ only counts if the exception is set */
+ thread->abort_state_handle = 0;
+ }
}
LeaveCriticalSection (thread->synch_cs);
}
-static gboolean
-mono_thread_suspend (MonoThread *thread)
+static MonoObject*
+serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
{
- MONO_ARCH_SAVE_REGS;
+ static MonoMethod *serialize_method;
+
+ void *params [1];
+ MonoObject *array;
+
+ if (!serialize_method) {
+ MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
+ serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
+ }
+
+ if (!serialize_method) {
+ *failure = TRUE;
+ return NULL;
+ }
+
+ g_assert (!obj->vtable->klass->marshalbyref);
+
+ params [0] = obj;
+ *exc = NULL;
+ array = mono_runtime_invoke (serialize_method, NULL, params, exc);
+ if (*exc)
+ *failure = TRUE;
+
+ return array;
+}
+
+static MonoObject*
+deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
+{
+ static MonoMethod *deserialize_method;
+ void *params [1];
+ MonoObject *result;
+
+ if (!deserialize_method) {
+ MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
+ deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
+ }
+ if (!deserialize_method) {
+ *failure = TRUE;
+ return NULL;
+ }
+
+ params [0] = obj;
+ *exc = NULL;
+ result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
+ if (*exc)
+ *failure = TRUE;
+
+ return result;
+}
+
+static MonoObject*
+make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
+{
+ static MonoMethod *get_proxy_method;
+
+ MonoDomain *domain = mono_domain_get ();
+ MonoRealProxy *real_proxy;
+ MonoReflectionType *reflection_type;
+ MonoTransparentProxy *transparent_proxy;
+
+ if (!get_proxy_method)
+ get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
+
+ g_assert (obj->vtable->klass->marshalbyref);
+
+ real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
+ reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
+
+ real_proxy->class_to_proxy = reflection_type;
+ real_proxy->unwrapped_server = obj;
+
+ *exc = NULL;
+ transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
+ if (*exc)
+ *failure = TRUE;
+
+ return (MonoObject*) transparent_proxy;
+}
+
+MonoObject*
+ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this)
+{
+ MonoInternalThread *thread = this->internal_thread;
+ MonoObject *state, *serialized, *deserialized = NULL, *exc;
+ MonoDomain *domain;
+ gboolean failure = FALSE;
+
+ if (!thread->abort_state_handle)
+ return NULL;
+
+ state = mono_gchandle_get_target (thread->abort_state_handle);
+ g_assert (state);
+
+ domain = mono_domain_get ();
+ if (state->vtable->domain == domain)
+ return state;
+
+ if (state->vtable->klass->marshalbyref) {
+ deserialized = make_transparent_proxy (state, &failure, &exc);
+ } else {
+ mono_domain_set_internal_with_options (state->vtable->domain, FALSE);
+ serialized = serialize_object (state, &failure, &exc);
+ mono_domain_set_internal_with_options (domain, FALSE);
+ if (!failure)
+ deserialized = deserialize_object (serialized, &failure, &exc);
+ }
+
+ if (failure) {
+ MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
+ if (exc)
+ MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
+ mono_raise_exception (invalid_op_exc);
+ }
+
+ return deserialized;
+}
+
+static gboolean
+mono_thread_suspend (MonoInternalThread *thread)
+{
ensure_synch_cs_set (thread);
EnterCriticalSection (thread->synch_cs);
}
void
-ves_icall_System_Threading_Thread_Suspend (MonoThread *thread)
+ves_icall_System_Threading_Thread_Suspend (MonoInternalThread *thread)
{
if (!mono_thread_suspend (thread))
mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
}
static gboolean
-mono_thread_resume (MonoThread *thread)
+mono_thread_resume (MonoInternalThread *thread)
{
- MONO_ARCH_SAVE_REGS;
-
ensure_synch_cs_set (thread);
EnterCriticalSection (thread->synch_cs);
void
ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
{
- if (!mono_thread_resume (thread))
+ if (!thread->internal_thread || !mono_thread_resume (thread->internal_thread))
mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
}
return found;
}
-void mono_thread_stop (MonoThread *thread)
+void mono_thread_internal_stop (MonoInternalThread *thread)
{
ensure_synch_cs_set (thread);
signal_thread_state_change (thread);
}
+void mono_thread_stop (MonoThread *thread)
+{
+ mono_thread_internal_stop (thread->internal_thread);
+}
+
gint8
ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
{
*((volatile void **) ptr) = value;
}
+void
+ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, void *value)
+{
+ mono_gc_wbarrier_generic_store (ptr, value);
+}
+
void mono_thread_init (MonoThreadStartCB start_cb,
MonoThreadAttachCB attach_cb)
{
void
mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
{
- thread->manage_callback = func;
+ thread->internal_thread->manage_callback = func;
}
void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func)
struct wait_data
{
HANDLE handles[MAXIMUM_WAIT_OBJECTS];
- MonoThread *threads[MAXIMUM_WAIT_OBJECTS];
+ MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
guint32 num;
};
if(wait->num<MAXIMUM_WAIT_OBJECTS) {
HANDLE handle;
- MonoThread *thread=(MonoThread *)value;
+ MonoInternalThread *thread=(MonoInternalThread *)value;
/* Ignore background threads, we abort them later */
/* Do not lock here since it is not needed and the caller holds threads_lock */
return; /* just leave, ignore */
}
- if (mono_gc_is_finalizer_thread (thread)) {
+ if (mono_gc_is_finalizer_internal_thread (thread)) {
THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
return;
}
- if (thread == mono_thread_current ()) {
+ if (thread == mono_thread_internal_current ()) {
THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
return;
}
- if (thread == mono_thread_get_main ()) {
+ if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
return;
}
}
THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
- if ((thread->manage_callback == NULL) || (thread->manage_callback (thread) == TRUE)) {
+ if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
wait->handles[wait->num]=handle;
wait->threads[wait->num]=thread;
wait->num++;
{
struct wait_data *wait=(struct wait_data *)user;
gsize self = GetCurrentThreadId ();
- MonoThread *thread = (MonoThread *) value;
+ MonoInternalThread *thread = value;
HANDLE handle;
if (wait->num >= MAXIMUM_WAIT_OBJECTS)
wait->num++;
THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
- mono_thread_stop (thread);
+ mono_thread_internal_stop (thread);
return TRUE;
}
- return (thread->tid != self && !mono_gc_is_finalizer_thread (thread));
+ return (thread->tid != self && !mono_gc_is_finalizer_internal_thread (thread));
}
-static MonoException* mono_thread_execute_interruption (MonoThread *thread);
-
/**
* mono_threads_set_shutting_down:
*
void
mono_threads_set_shutting_down (void)
{
- MonoThread *current_thread = mono_thread_current ();
+ MonoInternalThread *current_thread = mono_thread_internal_current ();
mono_threads_lock ();
if(threads==NULL) {
THREAD_DEBUG (g_message("%s: No threads", __func__));
mono_threads_unlock ();
+ g_free (wait);
return;
}
mono_threads_unlock ();
static void terminate_thread (gpointer key, gpointer value, gpointer user)
{
- MonoThread *thread=(MonoThread *)value;
+ MonoInternalThread *thread=(MonoInternalThread *)value;
if(thread->tid != (gsize)user) {
/*TerminateThread (thread->handle, -1);*/
static void
collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
{
- MonoThread *thread = (MonoThread*)value;
+ MonoInternalThread *thread = (MonoInternalThread*)value;
struct wait_data *wait = (struct wait_data*)user_data;
HANDLE handle;
eventidx = 0;
/* Get the suspended events that we'll be waiting for */
for (i = 0; i < wait->num; ++i) {
- MonoThread *thread = wait->threads [i];
+ MonoInternalThread *thread = wait->threads [i];
gboolean signal_suspend = FALSE;
- if ((thread->tid == self) || mono_gc_is_finalizer_thread (thread)) {
+ if ((thread->tid == self) || mono_gc_is_finalizer_internal_thread (thread)) {
//CloseHandle (wait->handles [i]);
wait->threads [i] = NULL; /* ignore this thread in next loop */
continue;
if (eventidx > 0) {
WaitForMultipleObjectsEx (eventidx, events, TRUE, 100, FALSE);
for (i = 0; i < wait->num; ++i) {
- MonoThread *thread = wait->threads [i];
+ MonoInternalThread *thread = wait->threads [i];
if (thread == NULL)
continue;
* FIXME: The finalizer thread can still create new threads.
*/
mono_threads_lock ();
- starting = mono_g_hash_table_size (threads_starting_up) > 0;
+ if (threads_starting_up)
+ starting = mono_g_hash_table_size (threads_starting_up) > 0;
+ else
+ starting = FALSE;
mono_threads_unlock ();
if (starting)
Sleep (100);
static void
collect_threads (gpointer key, gpointer value, gpointer user_data)
{
- MonoThread *thread = (MonoThread*)value;
+ MonoInternalThread *thread = (MonoInternalThread*)value;
struct wait_data *wait = (struct wait_data*)user_data;
HANDLE handle;
mono_threads_unlock ();
for (i = 0; i < wait->num; ++i) {
- MonoThread *thread = wait->threads [i];
+ MonoInternalThread *thread = wait->threads [i];
- if (!mono_gc_is_finalizer_thread (thread) && (thread != mono_thread_current ()) && !thread->thread_dump_requested) {
+ if (!mono_gc_is_finalizer_internal_thread (thread) &&
+ (thread != mono_thread_internal_current ()) &&
+ !thread->thread_dump_requested) {
thread->thread_dump_requested = TRUE;
signal_thread_state_change (thread);
void
mono_thread_push_appdomain_ref (MonoDomain *domain)
{
- MonoThread *thread = mono_thread_current ();
+ MonoInternalThread *thread = mono_thread_internal_current ();
if (thread) {
/* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
void
mono_thread_pop_appdomain_ref (void)
{
- MonoThread *thread = mono_thread_current ();
+ MonoInternalThread *thread = mono_thread_internal_current ();
if (thread) {
/* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
}
gboolean
-mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
+mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
{
gboolean res;
mono_threads_lock ();
return res;
}
+gboolean
+mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
+{
+ return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
+}
+
typedef struct abort_appdomain_data {
struct wait_data wait;
MonoDomain *domain;
static void
collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
{
- MonoThread *thread = (MonoThread*)value;
+ MonoInternalThread *thread = (MonoInternalThread*)value;
abort_appdomain_data *data = (abort_appdomain_data*)user_data;
MonoDomain *domain = data->domain;
- if (mono_thread_has_appdomain_ref (thread, domain)) {
+ if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
/* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
static void
clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
{
- MonoThread *thread = (MonoThread*)value;
+ MonoInternalThread *thread = (MonoInternalThread*)value;
MonoDomain *domain = (MonoDomain*)user_data;
int i;
MonoException*
mono_thread_get_undeniable_exception (void)
{
- MonoThread *thread = mono_thread_current ();
-
- MONO_ARCH_SAVE_REGS;
+ MonoInternalThread *thread = mono_thread_internal_current ();
if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
/*
* This function is called when a thread is created or on thread attach.
*/
static void
-thread_adjust_static_data (MonoThread *thread)
+thread_adjust_static_data (MonoInternalThread *thread)
{
guint32 offset;
static void
alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
{
- MonoThread *thread = value;
+ MonoInternalThread *thread = value;
guint32 offset = GPOINTER_TO_UINT (user);
-
+
mono_alloc_static_data (&(thread->static_data), offset);
}
offset &= 0x7fffffff;
idx = (offset >> 24) - 1;
- if (static_type == 0)
- {
- MonoThread *thread = mono_thread_current ();
- return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
- }
- else
- {
+ if (static_type == 0) {
+ return get_thread_static_data (mono_thread_internal_current (), offset);
+ } else {
/* Allocate static data block under demand, since we don't have a list
// of contexts
*/
static void
free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
{
- MonoThread *thread = value;
+ MonoInternalThread *thread = value;
TlsOffsetSize *data = user;
int idx = (data->offset >> 24) - 1;
char *ptr;
clear_local_slot (gpointer key, gpointer value, gpointer user_data)
{
LocalSlotID *sid = user_data;
- MonoThread *thread = (MonoThread*)value;
+ MonoInternalThread *thread = (MonoInternalThread*)value;
MonoArray *slots_array;
/*
* the static field is stored at: ((char*) thread->static_data [idx]) + (offset & 0xffffff);
* Performs the operation that the requested thread state requires (abort,
* suspend or stop)
*/
-static MonoException* mono_thread_execute_interruption (MonoThread *thread)
+static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread)
{
ensure_synch_cs_set (thread);
EnterCriticalSection (thread->synch_cs);
- if (thread->interruption_requested) {
+ /* MonoThread::interruption_requested can only be changed with atomics */
+ if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
/* this will consume pending APC calls */
WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
InterlockedDecrement (&thread_interruption_requested);
- thread->interruption_requested = FALSE;
#ifndef PLATFORM_WIN32
/* Clear the interrupted flag of the thread so it can wait again */
wapi_clear_interruption ();
}
if ((thread->state & ThreadState_AbortRequested) != 0) {
- if (thread->abort_exc == NULL)
- MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
LeaveCriticalSection (thread->synch_cs);
+ if (thread->abort_exc == NULL) {
+ /*
+ * This might be racy, but it has to be called outside the lock
+ * since it calls managed code.
+ */
+ MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
+ }
return thread->abort_exc;
}
else if ((thread->state & ThreadState_SuspendRequested) != 0) {
MonoException*
mono_thread_request_interruption (gboolean running_managed)
{
- MonoThread *thread = mono_thread_current ();
+ MonoInternalThread *thread = mono_thread_internal_current ();
/* The thread may already be stopping */
if (thread == NULL)
return NULL;
+
+#ifdef PLATFORM_WIN32
+ if (thread->interrupt_on_stop &&
+ thread->state & ThreadState_StopRequested &&
+ thread->state & ThreadState_Background)
+ ExitThread (1);
+#endif
if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
return NULL;
gboolean mono_thread_interruption_requested ()
{
if (thread_interruption_requested) {
- MonoThread *thread = mono_thread_current ();
+ MonoInternalThread *thread = mono_thread_internal_current ();
/* The thread may already be stopping */
if (thread != NULL)
return (thread->interruption_requested);
static void mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
{
- MonoThread *thread = mono_thread_current ();
+ MonoInternalThread *thread = mono_thread_internal_current ();
/* The thread may already be stopping */
if (thread == NULL)
MonoException*
mono_thread_get_and_clear_pending_exception (void)
{
- MonoThread *thread = mono_thread_current ();
+ MonoInternalThread *thread = mono_thread_internal_current ();
/* The thread may already be stopping */
if (thread == NULL)
void
mono_set_pending_exception (MonoException *exc)
{
- MonoThread *thread = mono_thread_current ();
+ MonoInternalThread *thread = mono_thread_internal_current ();
/* The thread may already be stopping */
if (thread == NULL)
void
mono_thread_init_apartment_state (void)
{
- MonoThread* thread;
- thread = mono_thread_current ();
-
#ifdef PLATFORM_WIN32
+ MonoInternalThread* thread = mono_thread_internal_current ();
+
/* Positive return value indicates success, either
* S_OK if this is first CoInitialize call, or
* S_FALSE if CoInitialize already called, but with same
mono_thread_cleanup_apartment_state (void)
{
#ifdef PLATFORM_WIN32
- MonoThread* thread;
- thread = mono_thread_current ();
+ MonoInternalThread* thread = mono_thread_internal_current ();
if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
CoUninitialize ();
}
void
-mono_thread_set_state (MonoThread *thread, MonoThreadState state)
+mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
{
ensure_synch_cs_set (thread);
}
void
-mono_thread_clr_state (MonoThread *thread, MonoThreadState state)
+mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
{
ensure_synch_cs_set (thread);
}
gboolean
-mono_thread_test_state (MonoThread *thread, MonoThreadState test)
+mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
{
gboolean ret = FALSE;
return ret;
}
+
+static MonoClassField *execution_context_field;
+
+static MonoObject**
+get_execution_context_addr (void)
+{
+ MonoDomain *domain = mono_domain_get ();
+ guint32 offset;
+
+ if (!execution_context_field) {
+ execution_context_field = mono_class_get_field_from_name (mono_defaults.thread_class,
+ "_ec");
+ g_assert (execution_context_field);
+ }
+
+ g_assert (mono_class_try_get_vtable (domain, mono_defaults.appdomain_class));
+
+ mono_domain_lock (domain);
+ offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, execution_context_field));
+ mono_domain_unlock (domain);
+ g_assert (offset);
+
+ return (MonoObject**) mono_get_special_static_data (offset);
+}
+
+MonoObject*
+mono_thread_get_execution_context (void)
+{
+ return *get_execution_context_addr ();
+}
+
+void
+mono_thread_set_execution_context (MonoObject *ec)
+{
+ *get_execution_context_addr () = ec;
+}
+
+static gboolean has_tls_get = FALSE;
+
+void
+mono_runtime_set_has_tls_get (gboolean val)
+{
+ has_tls_get = val;
+}
+
+gboolean
+mono_runtime_has_tls_get (void)
+{
+ return has_tls_get;
+}