#include <mono/metadata/domain-internals.h>
#include <mono/metadata/profiler-private.h>
#include <mono/metadata/threads.h>
-#include <mono/metadata/threadpool.h>
#include <mono/metadata/threads-types.h>
#include <mono/metadata/exception.h>
#include <mono/metadata/environment.h>
* 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 MonoNativeTlsKey current_object_key;
static void self_suspend_internal (MonoInternalThread *thread);
static gboolean resume_thread_internal (MonoInternalThread *thread);
-static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread);
+static MonoException* mono_thread_execute_interruption ();
static void ref_stack_destroy (gpointer rs);
/* Spin lock for InterlockedXXX 64 bit functions */
static gint32 managed_thread_id_counter = 0;
-
static void
mono_threads_lock (void)
{
- MONO_TRY_BLOCKING
+ MONO_TRY_BLOCKING;
mono_locks_acquire (&threads_mutex, ThreadsLock);
- MONO_FINISH_TRY_BLOCKING
+ MONO_FINISH_TRY_BLOCKING;
}
static void
}
if(threads==NULL) {
- MONO_GC_REGISTER_ROOT_FIXED (threads);
- threads=mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
+ 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
g_assert (thread->synch_cs);
- MONO_TRY_BLOCKING
+ MONO_TRY_BLOCKING;
mono_mutex_lock (thread->synch_cs);
- MONO_FINISH_TRY_BLOCKING
+ MONO_FINISH_TRY_BLOCKING;
}
static inline void
}
/* This needs to be called even if handle_remove () fails */
if (mono_thread_cleanup_fn)
- mono_thread_cleanup_fn ((MonoNativeThreadId)thread->tid);
+ mono_thread_cleanup_fn (thread_get_tid (thread));
return;
}
mono_release_type_locks (thread);
thread->appdomain_refs = NULL;
if (mono_thread_cleanup_fn)
- mono_thread_cleanup_fn ((MonoNativeThreadId)thread->tid);
+ mono_thread_cleanup_fn (thread_get_tid (thread));
if (mono_gc_is_moving ()) {
MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
typedef union {
struct {
+#if G_BYTE_ORDER != G_LITTLE_ENDIAN
+ guint32 type : 1;
+ guint32 offset : 25;
+ guint32 index : 6;
+#else
guint32 index : 6;
guint32 offset : 25;
guint32 type : 1;
+#endif
} fields;
guint32 raw;
} SpecialStaticOffset;
thread->managed_id = get_next_managed_thread_id ();
if (mono_gc_is_moving ()) {
thread->thread_pinning_ref = thread;
- MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref);
+ MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref, MONO_ROOT_SOURCE_THREADING, "thread pinning reference");
}
return thread;
internal->thread_info = info;
internal->small_id = info->small_id;
- tid=internal->tid;
+ tid = internal->tid;
SET_CURRENT_OBJECT (internal);
}
start_func = start_info->func;
- start_arg = start_info->start_arg;
+ start_arg = start_info->obj->start_obj;
+ if (!start_arg)
+ 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. */
ReleaseSemaphore (internal->start_notify, 1, NULL);
}
- mono_threads_lock ();
- mono_g_hash_table_remove (thread_start_args, start_info->obj);
- mono_threads_unlock ();
-
- mono_thread_set_execution_context (start_info->obj->ec_to_set);
- start_info->obj->ec_to_set = NULL;
-
g_free (start_info);
THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
internal->tid));
mono_threads_unlock ();
return FALSE;
}
- /*
- * The thread start 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.
- */
- if (thread_start_args == NULL) {
- MONO_GC_REGISTER_ROOT_FIXED (thread_start_args);
- thread_start_args = mono_g_hash_table_new (NULL, NULL);
- }
- mono_g_hash_table_insert (thread_start_args, thread, start_info->start_arg);
if (threads_starting_up == NULL) {
- MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up);
- threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC);
+ 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 ();
*/
create_flags = CREATE_SUSPENDED;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)start_wrapper, start_info,
stack_size, create_flags, &tid);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if (thread_handle == NULL) {
/* The thread couldn't be created, so throw an exception */
if (!handle_store (thread, FALSE))
return FALSE;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
mono_thread_info_resume (tid);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if (internal->start_notify) {
/*
*/
THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
CloseHandle (internal->start_notify);
internal->start_notify = NULL;
/*
* mono_thread_create_internal:
- *
+ *
+ * ARG should not be a GC reference.
*/
MonoInternalThread*
mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size)
tid=GetCurrentThreadId ();
- thread->handle=thread_handle;
- thread->tid=tid;
+ thread->handle = thread_handle;
+ thread->tid = tid;
thread->stack_ptr = &tid;
THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
}
void
-ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this)
+ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
{
MonoInternalThread *internal = create_internal_thread ();
internal->state = ThreadState_Unstarted;
- InterlockedCompareExchangePointer ((gpointer)&this->internal_thread, internal, NULL);
+ InterlockedCompareExchangePointer ((gpointer)&this_obj->internal_thread, internal, NULL);
}
HANDLE
-ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this,
+ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
MonoObject *start)
{
StartInfo *start_info;
MonoInternalThread *internal;
gboolean res;
- THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this, start));
+ THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
- if (!this->internal_thread)
- ves_icall_System_Threading_Thread_ConstructInternalThread (this);
- internal = this->internal_thread;
+ if (!this_obj->internal_thread)
+ ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
+ internal = this_obj->internal_thread;
LOCK_THREAD (internal);
if ((internal->state & ThreadState_Aborted) != 0) {
UNLOCK_THREAD (internal);
- return this;
+ return this_obj;
}
/* This is freed in start_wrapper */
start_info = g_new0 (StartInfo, 1);
start_info->func = NULL;
- start_info->start_arg = this->start_obj; /* FIXME: GC object stored in unmanaged memory */
+ start_info->start_arg = NULL;
start_info->delegate = start;
- start_info->obj = this;
- g_assert (this->obj.vtable->domain == mono_domain_get ());
+ start_info->obj = this_obj;
+ g_assert (this_obj->obj.vtable->domain == mono_domain_get ());
- res = create_thread (this, internal, start_info, FALSE, 0, FALSE);
+ res = create_thread (this_obj, internal, start_info, FALSE, 0, FALSE);
if (!res) {
UNLOCK_THREAD (internal);
return NULL;
* This is called from the finalizer of the internal thread object.
*/
void
-ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this, HANDLE thread)
+ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj, HANDLE thread)
{
THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
if (thread)
CloseHandle (thread);
- if (this->synch_cs) {
- mono_mutex_t *synch_cs = this->synch_cs;
- this->synch_cs = NULL;
+ if (this_obj->synch_cs) {
+ mono_mutex_t *synch_cs = this_obj->synch_cs;
+ this_obj->synch_cs = NULL;
mono_mutex_destroy (synch_cs);
g_free (synch_cs);
}
- if (this->name) {
- void *name = this->name;
- this->name = NULL;
+ if (this_obj->name) {
+ void *name = this_obj->name;
+ this_obj->name = NULL;
g_free (name);
}
}
while (TRUE) {
mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
res = SleepEx(ms,TRUE);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
if (res == WAIT_IO_COMPLETION) { /* we might have been interrupted */
- MonoException* exc = mono_thread_execute_interruption (thread);
+ MonoException* exc = mono_thread_execute_interruption ();
if (exc) {
mono_raise_exception (exc);
} else {
}
int
-ves_icall_System_Threading_Thread_GetPriority (MonoInternalThread *thread)
+ves_icall_System_Threading_Thread_GetPriority (MonoThread *this)
{
return ThreadPriority_Lowest;
}
void
-ves_icall_System_Threading_Thread_SetPriority (MonoInternalThread *thread, int priority)
+ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
{
}
}
gboolean
-ves_icall_System_Threading_Thread_Join_internal(MonoInternalThread *this,
- int ms, HANDLE thread)
+ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
{
+ MonoInternalThread *thread = this_obj->internal_thread;
+ HANDLE handle = thread->handle;
MonoInternalThread *cur_thread = mono_thread_internal_current ();
gboolean ret;
mono_thread_current_check_pending_interrupt ();
- LOCK_THREAD (this);
+ LOCK_THREAD (thread);
- if ((this->state & ThreadState_Unstarted) != 0) {
- UNLOCK_THREAD (this);
+ if ((thread->state & ThreadState_Unstarted) != 0) {
+ UNLOCK_THREAD (thread);
mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
return FALSE;
}
- UNLOCK_THREAD (this);
+ UNLOCK_THREAD (thread);
if(ms== -1) {
ms=INFINITE;
}
- THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, thread, ms));
+ THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
- MONO_PREPARE_BLOCKING
- ret=WaitForSingleObjectEx (thread, ms, TRUE);
- MONO_FINISH_BLOCKING
+ MONO_PREPARE_BLOCKING;
+ ret=WaitForSingleObjectEx (handle, ms, TRUE);
+ MONO_FINISH_BLOCKING;
mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
start = (ms == -1) ? 0 : mono_100ns_ticks ();
do {
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
if (multiple)
ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
else
ret = WaitForSingleObjectEx (handles [0], ms, alertable);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if (ret != WAIT_IO_COMPLETION)
break;
- exc = mono_thread_execute_interruption (thread);
+ exc = mono_thread_execute_interruption ();
if (exc)
mono_raise_exception (exc);
}
/* FIXME: exitContext isnt documented */
-gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this, HANDLE handle, gint32 ms, gboolean exitContext)
+gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this_obj, HANDLE handle, gint32 ms, gboolean exitContext)
{
guint32 ret;
MonoInternalThread *thread = mono_thread_internal_current ();
mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
return state;
}
-void ves_icall_System_Threading_Thread_Interrupt_internal (MonoInternalThread *this)
+void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
{
MonoInternalThread *current;
gboolean throw;
+ MonoInternalThread *thread = this_obj->internal_thread;
- LOCK_THREAD (this);
+ LOCK_THREAD (thread);
current = mono_thread_internal_current ();
- this->thread_interrupt_requested = TRUE;
- throw = current != this && (this->state & ThreadState_WaitSleepJoin);
+ thread->thread_interrupt_requested = TRUE;
+ throw = current != thread && (thread->state & ThreadState_WaitSleepJoin);
- UNLOCK_THREAD (this);
+ UNLOCK_THREAD (thread);
if (throw) {
- abort_thread_internal (this, TRUE, FALSE);
+ abort_thread_internal (thread, TRUE, FALSE);
}
}
}
void
-ves_icall_System_Threading_Thread_ResetAbort (void)
+ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
{
MonoInternalThread *thread = mono_thread_internal_current ();
gboolean was_aborting;
}
MonoObject*
-ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this)
+ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
{
- MonoInternalThread *thread = this->internal_thread;
+ MonoInternalThread *thread = this_obj->internal_thread;
MonoObject *state, *deserialized = NULL, *exc;
MonoDomain *domain;
}
void
-ves_icall_System_Threading_Thread_Suspend (MonoInternalThread *thread)
+ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
{
- if (!mono_thread_suspend (thread)) {
+ if (!mono_thread_suspend (this_obj->internal_thread)) {
mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
return;
}
g_hash_table_insert (contexts, gch, gch);
mono_threads_unlock ();
+
+ mono_profiler_context_loaded (ctx);
+}
+
+void
+ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
+{
+ /*
+ * NOTE: Since finalizers are unreliable for the purposes of ensuring
+ * cleanup in exceptional circumstances, we don't actually do any
+ * cleanup work here. We instead do this when we iterate the `contexts`
+ * hash table. The only purpose of this finalizer, at the moment, is to
+ * notify the profiler.
+ */
+
+ //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
+
+ mono_profiler_context_unloaded (ctx);
}
void
THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if(ret==WAIT_FAILED) {
/* See the comment in build_wait_tids() */
count++;
}
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if(ret==WAIT_FAILED) {
/* See the comment in build_wait_tids() */
return;
}
- handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
+ handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
if (handle == NULL) {
THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
return;
if (thread->tid != self && (thread->state & ThreadState_Background) != 0 &&
!(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
- handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
+ handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
if (handle == NULL)
return FALSE;
(current_thread->state & ThreadState_AbortRequested) ||
(current_thread->state & ThreadState_StopRequested)) {
UNLOCK_THREAD (current_thread);
- mono_thread_execute_interruption (current_thread);
+ mono_thread_execute_interruption ();
} else {
current_thread->state |= ThreadState_Stopped;
UNLOCK_THREAD (current_thread);
if (!mono_runtime_try_shutdown ()) {
/*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
mono_thread_suspend (mono_thread_internal_current ());
- mono_thread_execute_interruption (mono_thread_internal_current ());
+ mono_thread_execute_interruption ();
}
/*
return;
if (wait->num<MAXIMUM_WAIT_OBJECTS) {
- handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
+ handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
if (handle == NULL)
return;
{
GString *p = (GString*)data;
MonoMethod *method = NULL;
- if (frame->ji)
+ if (frame->type == FRAME_TYPE_MANAGED)
method = mono_jit_info_get_method (frame->ji);
if (method) {
We probably should loop a bit around trying to get it to either managed code
or WSJ state.
*/
- mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, FALSE, print_thread_dump, thread);
+ mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, print_thread_dump, thread);
}
void
/* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
- HANDLE handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
+ HANDLE handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
if (handle == NULL)
return;
data->wait.handles [data->wait.num] = handle;
void **p = ptr + idx;
if (*p)
- mark_func (p, gc_data);
+ mark_func ((MonoObject**)p, gc_data);
});
}
}
gpointer* static_data = *static_data_ptr;
if (!static_data) {
- static void *tls_desc = NULL;
- static void *ctx_desc = NULL;
+ static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
+ static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
if (mono_gc_user_markers_supported ()) {
- if (!tls_desc)
+ if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
- if (!ctx_desc)
+ if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
}
- static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc);
+ static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
+ threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
+ threadlocal ? "managed thread-static variables" : "managed context-static variables");
*static_data_ptr = static_data;
static_data [0] = static_data;
}
if (mono_gc_user_markers_supported ())
static_data [i] = g_malloc0 (static_data_size [i]);
else
- static_data [i] = mono_gc_alloc_fixed (static_data_size [i], NULL);
+ static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
+ threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
+ threadlocal ? "managed thread-static variables" : "managed context-static variables");
}
}
mono_threads_unlock ();
}
+/*
+ * LOCKING: requires that threads_mutex is held
+ */
static void
context_adjust_static_data (MonoAppContext *ctx)
{
- mono_threads_lock ();
-
if (context_static_info.offset || context_static_info.idx > 0) {
guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
mono_alloc_static_data (&ctx->static_data, offset, FALSE);
}
-
- mono_threads_unlock ();
}
/*
/*
* LOCKING: requires that threads_mutex is held
*/
-static void
+static gboolean
alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
{
uint32_t gch = GPOINTER_TO_INT (key);
MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (gch);
if (!ctx) {
- g_hash_table_remove (contexts, key);
mono_gchandle_free (gch);
- return;
+ return TRUE; // Remove this key/value pair
}
guint32 offset = GPOINTER_TO_UINT (user);
mono_alloc_static_data (&ctx->static_data, offset, FALSE);
+
+ return FALSE; // Don't remove it
}
static StaticDataFreeList*
mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
} else {
if (contexts != NULL)
- g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
+ g_hash_table_foreach_remove (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
}
/*
* LOCKING: requires that threads_mutex is held
*/
-static void
+static gboolean
free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
{
uint32_t gch = GPOINTER_TO_INT (key);
MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (gch);
if (!ctx) {
- g_hash_table_remove (contexts, key);
mono_gchandle_free (gch);
- return;
+ return TRUE; // Remove this key/value pair
}
OffsetSize *data = user;
char *ptr;
if (!ctx->static_data || !ctx->static_data [idx])
- return;
+ return FALSE; // Don't remove this key/value pair
ptr = ((char*) ctx->static_data [idx]) + off;
mono_gc_bzero_atomic (ptr, data->size);
+
+ return FALSE; // Don't remove this key/value pair
}
static void
mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
} else {
if (contexts != NULL)
- g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
+ g_hash_table_foreach_remove (contexts, free_context_static_data_helper, &data);
}
if (!mono_runtime_is_shutting_down ()) {
mono_threads_unlock ();
}
-/*
- * allocates room in the thread local area for storing an instance of the struct type
- * the allocation is kept track of in domain->tlsrec_list.
- */
-uint32_t
-mono_thread_alloc_tls (MonoReflectionType *type)
-{
- MonoDomain *domain = mono_domain_get ();
- MonoClass *klass;
- MonoTlsDataRecord *tlsrec;
- int max_set = 0;
- gsize *bitmap;
- gsize default_bitmap [4] = {0};
- uint32_t tls_offset;
- guint32 size;
- gint32 align;
-
- klass = mono_class_from_mono_type (type->type);
- /* TlsDatum is a struct, so we subtract the object header size offset */
- bitmap = mono_class_compute_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
- size = mono_type_size (type->type, &align);
- tls_offset = mono_alloc_special_static_data (SPECIAL_STATIC_THREAD, size, align, (uintptr_t*)bitmap, max_set + 1);
- if (bitmap != default_bitmap)
- g_free (bitmap);
- tlsrec = g_new0 (MonoTlsDataRecord, 1);
- tlsrec->tls_offset = tls_offset;
- tlsrec->size = size;
- mono_domain_lock (domain);
- tlsrec->next = domain->tlsrec_list;
- domain->tlsrec_list = tlsrec;
- mono_domain_unlock (domain);
- return tls_offset;
-}
-
-static void
-destroy_tls (MonoDomain *domain, uint32_t tls_offset)
-{
- MonoTlsDataRecord *prev = NULL;
- MonoTlsDataRecord *cur;
- guint32 size = 0;
-
- mono_domain_lock (domain);
- cur = domain->tlsrec_list;
- while (cur) {
- if (cur->tls_offset == tls_offset) {
- if (prev)
- prev->next = cur->next;
- else
- domain->tlsrec_list = cur->next;
- size = cur->size;
- g_free (cur);
- break;
- }
- prev = cur;
- cur = cur->next;
- }
- mono_domain_unlock (domain);
- if (size)
- mono_special_static_data_free_slot (tls_offset, size);
-}
-
-void
-mono_thread_destroy_tls (uint32_t tls_offset)
-{
- destroy_tls (mono_domain_get (), tls_offset);
-}
-
-/*
- * This is just to ensure cleanup: the finalizers should have taken care, so this is not perf-critical.
- */
-void
-mono_thread_destroy_domain_tls (MonoDomain *domain)
-{
- while (domain->tlsrec_list)
- destroy_tls (domain, domain->tlsrec_list->tls_offset);
-}
-
-static MonoClassField *local_slots = NULL;
-
-typedef struct {
- /* local tls data to get locals_slot from a thread */
- guint32 offset;
- int idx;
- /* index in the locals_slot array */
- int slot;
-} LocalSlotID;
-
-static void
-clear_local_slot (gpointer key, gpointer value, gpointer user_data)
-{
- LocalSlotID *sid = user_data;
- MonoInternalThread *thread = (MonoInternalThread*)value;
- MonoArray *slots_array;
- /*
- * the static field is stored at: ((char*) thread->static_data [idx]) + (offset & 0xffffff);
- * it is for the right domain, so we need to check if it is allocated an initialized
- * for the current thread.
- */
- /*g_print ("handling thread %p\n", thread);*/
- if (!thread->static_data || !thread->static_data [sid->idx])
- return;
- slots_array = *(MonoArray **)(((char*) thread->static_data [sid->idx]) + (sid->offset & 0xffffff));
- if (!slots_array || sid->slot >= mono_array_length (slots_array))
- return;
- mono_array_set (slots_array, MonoObject*, sid->slot, NULL);
-}
-
-void
-mono_thread_free_local_slot_values (int slot, MonoBoolean thread_local)
-{
- MonoDomain *domain;
- LocalSlotID sid;
- sid.slot = slot;
- if (thread_local) {
- void *addr = NULL;
- if (!local_slots) {
- local_slots = mono_class_get_field_from_name (mono_defaults.thread_class, "local_slots");
- if (!local_slots) {
- g_warning ("local_slots field not found in Thread class");
- return;
- }
- }
- domain = mono_domain_get ();
- mono_domain_lock (domain);
- if (domain->special_static_fields)
- addr = g_hash_table_lookup (domain->special_static_fields, local_slots);
- mono_domain_unlock (domain);
- if (!addr)
- return;
- /*g_print ("freeing slot %d at %p\n", slot, addr);*/
- sid.offset = GPOINTER_TO_UINT (addr);
- sid.offset &= 0x7fffffff;
- sid.idx = (sid.offset >> 24) - 1;
- mono_threads_lock ();
- mono_g_hash_table_foreach (threads, clear_local_slot, &sid);
- mono_threads_unlock ();
- } else {
- /* FIXME: clear the slot for MonoAppContexts, too */
- }
-}
-
#ifdef HOST_WIN32
static void CALLBACK dummy_apc (ULONG_PTR param)
{
* suspend or stop)
*/
static MonoException*
-mono_thread_execute_interruption (MonoInternalThread *thread)
+mono_thread_execute_interruption (void)
{
+ MonoInternalThread *thread = mono_thread_internal_current ();
+
LOCK_THREAD (thread);
/* MonoThread::interruption_requested can only be changed with atomics */
WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
#endif
InterlockedDecrement (&thread_interruption_requested);
+
/* Clear the interrupted flag of the thread so it can wait again */
- mono_thread_info_clear_interruption ();
+ mono_thread_info_clear_self_interrupt ();
}
if ((thread->state & ThreadState_AbortRequested) != 0) {
return NULL;
}
else {
- return mono_thread_execute_interruption (thread);
+ return mono_thread_execute_interruption ();
}
}
mono_thread_info_self_interrupt ();
- return mono_thread_execute_interruption (thread);
+ return mono_thread_execute_interruption ();
}
gboolean mono_thread_interruption_requested ()
return NULL;
if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
- MonoException* exc = mono_thread_execute_interruption (thread);
+ MonoException* exc = mono_thread_execute_interruption ();
if (exc)
return exc;
}
return NULL;
if (thread->interruption_requested && !is_running_protected_wrapper ()) {
- return mono_thread_execute_interruption (thread);
+ return mono_thread_execute_interruption ();
}
if (thread->pending_exception) {
return ret;
}
-//static MonoClassField *execution_context_field;
-
-static MonoObject**
-get_execution_context_addr (void)
-{
- MonoDomain *domain = mono_domain_get ();
- guint32 offset = domain->execution_context_field_offset;
-
- if (!offset) {
- MonoClassField *field = mono_class_get_field_from_name (mono_defaults.thread_class, "_ec");
- g_assert (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, field));
- mono_domain_unlock (domain);
- g_assert (offset);
-
- domain->execution_context_field_offset = 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
self_interrupt_thread (void *_unused)
{
MonoThreadInfo *info = mono_thread_info_current ();
- MonoException *exc = mono_thread_execute_interruption (mono_thread_internal_current ());
+ MonoException *exc = mono_thread_execute_interruption ();
if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
mono_raise_exception_with_context (exc, &info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX].ctx); /* FIXME using thread_saved_state [ASYNC_SUSPEND_STATE_INDEX] can race with another suspend coming in. */
g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
typedef struct {
MonoInternalThread *thread;
gboolean install_async_abort;
- gpointer interrupt_handle;
+ MonoThreadInfoInterruptToken *interrupt_token;
} AbortThreadData;
static SuspendThreadResult
InterlockedIncrement (&thread_interruption_requested);
ji = mono_thread_info_get_last_managed (info);
- protected_wrapper = ji && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
+ protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
if (!protected_wrapper && running_managed) {
* functions in the io-layer until the signal handler calls QueueUserAPC which will
* make it return.
*/
- data->interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle);
+ data->interrupt_token = mono_thread_info_prepare_interrupt (info);
+
return MonoResumeThread;
}
}
MonoException *exc = mono_thread_request_interruption (can_raise_exception);
if (exc)
mono_raise_exception (exc);
- mono_thread_info_interrupt (thread->handle);
+
+ mono_thread_info_self_interrupt ();
+
return;
}
- mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, TRUE, abort_thread_critical, &data);
- if (data.interrupt_handle)
- mono_thread_info_finish_interrupt (data.interrupt_handle);
+ mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, abort_thread_critical, &data);
+ if (data.interrupt_token)
+ mono_thread_info_finish_interrupt (data.interrupt_token);
/*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
}
typedef struct{
MonoInternalThread *thread;
gboolean interrupt;
- gpointer interrupt_handle;
+ MonoThreadInfoInterruptToken *interrupt_token;
} SuspendThreadData;
static SuspendThreadResult
gboolean running_managed;
ji = mono_thread_info_get_last_managed (info);
- protected_wrapper = ji && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
+ protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
if (running_managed && !protected_wrapper) {
if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
InterlockedIncrement (&thread_interruption_requested);
if (data->interrupt)
- data->interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle);
+ data->interrupt_token = mono_thread_info_prepare_interrupt (thread->thread_info);
if (mono_thread_notify_pending_exc_fn && !running_managed)
/* The JIT will notify the thread about the interruption */
data.thread = thread;
data.interrupt = interrupt;
- mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, interrupt, suspend_thread_critical, &data);
- if (data.interrupt_handle)
- mono_thread_info_finish_interrupt (data.interrupt_handle);
+ mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, suspend_thread_critical, &data);
+ if (data.interrupt_token)
+ mono_thread_info_finish_interrupt (data.interrupt_token);
UNLOCK_THREAD (thread);
}
}
{
UNLOCK_THREAD (thread);
/* Awake the thread */
- if (!mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid))
+ if (!mono_thread_info_resume (thread_get_tid (thread)))
return FALSE;
LOCK_THREAD (thread);
thread->state &= ~ThreadState_Suspended;
pthread_join (thread, NULL);
#endif
}
+
+void
+mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
+{
+ if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
+ mono_thread_interruption_checkpoint ();
+}
+
+static inline gboolean
+is_appdomainunloaded_exception (MonoClass *klass)
+{
+ static MonoClass *app_domain_unloaded_exception_klass = NULL;
+
+ if (!app_domain_unloaded_exception_klass)
+ app_domain_unloaded_exception_klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainUnloadedException");
+ g_assert (app_domain_unloaded_exception_klass);
+
+ return klass == app_domain_unloaded_exception_klass;
+}
+
+static inline gboolean
+is_threadabort_exception (MonoClass *klass)
+{
+ return klass == mono_defaults.threadabortexception_class;
+}
+
+void
+mono_thread_internal_unhandled_exception (MonoObject* exc)
+{
+ if (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
+ MonoClass *klass = exc->vtable->klass;
+ if (is_threadabort_exception (klass)) {
+ mono_thread_internal_reset_abort (mono_thread_internal_current ());
+ } else if (!is_appdomainunloaded_exception (klass)) {
+ mono_unhandled_exception (exc);
+ if (mono_environment_exitcode_get () == 1)
+ exit (255);
+ }
+ }
+}