StaticDataFreeList *freelist;
} StaticDataInfo;
-/* Number of cached culture objects in the MonoThread->cached_culture_info array
- * (per-type): we use the first NUM entries for CultureInfo and the last for
- * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
- */
-#define NUM_CACHED_CULTURES 4
-#define CULTURES_START_IDX 0
-#define UICULTURES_START_IDX NUM_CACHED_CULTURES
-
/* Controls access to the 'threads' hash table */
static void mono_threads_lock (void);
static void mono_threads_unlock (void);
return InterlockedIncrement (&managed_thread_id_counter);
}
+/*
+ * We separate interruptions/exceptions into either sync (they can be processed anytime,
+ * normally as soon as they are set, and are set by the same thread) and async (they can't
+ * be processed inside abort protected blocks and are normally set by other threads). We
+ * can have both a pending sync and async interruption. In this case, the sync exception is
+ * processed first. Since we clean sync flag first, mono_thread_execute_interruption must
+ * also handle all sync type exceptions before the async type exceptions.
+ */
enum {
- INTERRUPT_REQUESTED_BIT = 0x1,
- INTERRUPT_REQUEST_DEFERRED_BIT = 0x2,
+ INTERRUPT_SYNC_REQUESTED_BIT = 0x1,
+ INTERRUPT_ASYNC_REQUESTED_BIT = 0x2,
+ INTERRUPT_REQUESTED_MASK = 0x3,
ABORT_PROT_BLOCK_SHIFT = 2,
ABORT_PROT_BLOCK_BITS = 8,
ABORT_PROT_BLOCK_MASK = (((1 << ABORT_PROT_BLOCK_BITS) - 1) << ABORT_PROT_BLOCK_SHIFT)
return (state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT;
}
-static void
-verify_thread_state (gsize state)
-{
- //can't have both INTERRUPT_REQUESTED_BIT and INTERRUPT_REQUEST_DEFERRED_BIT set at the same time
- g_assert ((state & (INTERRUPT_REQUESTED_BIT | INTERRUPT_REQUEST_DEFERRED_BIT)) != (INTERRUPT_REQUESTED_BIT | INTERRUPT_REQUEST_DEFERRED_BIT));
-
- //XXX This would be nice to be true, but can happen due to self-aborts (and possibly set-pending-exception)
- //if prot_count > 0, INTERRUPT_REQUESTED_BIT must never be set
- // int prot_count = (state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT;
- // g_assert (!(prot_count > 0 && (state & INTERRUPT_REQUESTED_BIT)));
-}
-
void
mono_threads_begin_abort_protected_block (void)
{
MonoInternalThread *thread = mono_thread_internal_current ();
gsize old_state, new_state;
+ int new_val;
do {
old_state = thread->thread_state;
- verify_thread_state (old_state);
-
- int new_val = ((old_state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT) + 1;
-
- new_state = 0;
- if (old_state & (INTERRUPT_REQUESTED_BIT | INTERRUPT_REQUEST_DEFERRED_BIT)) {
- if (old_state & INTERRUPT_REQUESTED_BIT)
- printf ("begin prot happy as it demoted interrupt to deferred interrupt\n");
- new_state |= INTERRUPT_REQUEST_DEFERRED_BIT;
- }
+ new_val = ((old_state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT) + 1;
//bounds check abort_prot_count
g_assert (new_val > 0);
g_assert (new_val < (1 << ABORT_PROT_BLOCK_BITS));
- new_state |= new_val << ABORT_PROT_BLOCK_SHIFT;
+ new_state = old_state + (1 << ABORT_PROT_BLOCK_SHIFT);
} while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
}
-gboolean
-mono_threads_end_abort_protected_block (void)
+static gboolean
+mono_thread_state_has_interruption (gsize state)
{
- MonoInternalThread *thread = mono_thread_internal_current ();
- gsize old_state, new_state;
- do {
- old_state = thread->thread_state;
- verify_thread_state (old_state);
-
- int new_val = ((old_state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT) - 1;
- new_state = 0;
-
- if ((old_state & INTERRUPT_REQUEST_DEFERRED_BIT) && new_val == 0) {
- printf ("end abort on alert, promoted deferred to pront interrupt\n");
- new_state |= INTERRUPT_REQUESTED_BIT;
- }
+ /* pending exception, self abort */
+ if (state & INTERRUPT_SYNC_REQUESTED_BIT)
+ return TRUE;
- //bounds check abort_prot_count
- g_assert (new_val >= 0);
- g_assert (new_val < (1 << ABORT_PROT_BLOCK_BITS));
- new_state |= new_val << ABORT_PROT_BLOCK_SHIFT;
+ /* abort, interruption, suspend */
+ if ((state & INTERRUPT_ASYNC_REQUESTED_BIT) && !(state & ABORT_PROT_BLOCK_MASK))
+ return TRUE;
- } while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
- return (new_state & INTERRUPT_REQUESTED_BIT) == INTERRUPT_REQUESTED_BIT;
+ return FALSE;
}
-
-//Don't use this function, use inc/dec below
-static void
-mono_thread_abort_prot_block_count_add (MonoInternalThread *thread, int val)
+gboolean
+mono_threads_end_abort_protected_block (void)
{
+ MonoInternalThread *thread = mono_thread_internal_current ();
gsize old_state, new_state;
do {
old_state = thread->thread_state;
- verify_thread_state (old_state);
- int new_val = val + ((old_state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT);
//bounds check abort_prot_count
+ int new_val = ((old_state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT) - 1;
g_assert (new_val >= 0);
g_assert (new_val < (1 << ABORT_PROT_BLOCK_BITS));
- new_state = (old_state & ~ABORT_PROT_BLOCK_MASK) | (new_val << ABORT_PROT_BLOCK_SHIFT);
+ new_state = old_state - (1 << ABORT_PROT_BLOCK_SHIFT);
} while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
-}
-static void
-mono_thread_inc_abort_prot_block_count (MonoInternalThread *thread)
-{
- mono_thread_abort_prot_block_count_add (thread, 1);
-}
-
-static void
-mono_thread_dec_abort_prot_block_count (MonoInternalThread *thread)
-{
- mono_thread_abort_prot_block_count_add (thread, -1);
+ return mono_thread_state_has_interruption (new_state);
}
static gboolean
mono_thread_get_interruption_requested (MonoInternalThread *thread)
{
gsize state = thread->thread_state;
- return (state & INTERRUPT_REQUESTED_BIT) == INTERRUPT_REQUESTED_BIT;
+
+ return mono_thread_state_has_interruption (state);
}
-/* Returns TRUE is there was a state change */
+/*
+ * Returns TRUE is there was a state change
+ * We clear a single interruption request, sync has priority.
+ */
static gboolean
mono_thread_clear_interruption_requested (MonoInternalThread *thread)
{
gsize old_state, new_state;
do {
old_state = thread->thread_state;
- verify_thread_state (old_state);
- //Already cleared
- if (!(old_state & (INTERRUPT_REQUESTED_BIT | INTERRUPT_REQUEST_DEFERRED_BIT)))
+ // no interruption to process
+ if (!(old_state & INTERRUPT_SYNC_REQUESTED_BIT) &&
+ (!(old_state & INTERRUPT_ASYNC_REQUESTED_BIT) || (old_state & ABORT_PROT_BLOCK_MASK)))
return FALSE;
- new_state = old_state & ~(INTERRUPT_REQUESTED_BIT | INTERRUPT_REQUEST_DEFERRED_BIT);
+
+ if (old_state & INTERRUPT_SYNC_REQUESTED_BIT)
+ new_state = old_state & ~INTERRUPT_SYNC_REQUESTED_BIT;
+ else
+ new_state = old_state & ~INTERRUPT_ASYNC_REQUESTED_BIT;
} while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
+
+ InterlockedDecrement (&thread_interruption_requested);
+
return TRUE;
}
-/* Returns TRUE is there was a state change */
+/* Returns TRUE is there was a state change and the interruption can be processed */
static gboolean
mono_thread_set_interruption_requested (MonoInternalThread *thread)
{
//always force when the current thread is doing it to itself.
- gboolean force_interrupt = thread == mono_thread_internal_current ();
+ gboolean sync = thread == mono_thread_internal_current ();
gsize old_state, new_state;
do {
old_state = thread->thread_state;
- verify_thread_state (old_state);
- int prot_count = ((old_state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT);
//Already set
- if (old_state & (INTERRUPT_REQUESTED_BIT | INTERRUPT_REQUEST_DEFERRED_BIT))
+ if ((sync && (old_state & INTERRUPT_SYNC_REQUESTED_BIT)) ||
+ (!sync && (old_state & INTERRUPT_ASYNC_REQUESTED_BIT)))
return FALSE;
- //If there's an outstanding prot block, we queue it
- if (prot_count && !force_interrupt) {
- printf ("set interrupt unhappy, as it's only putting a deferred req %d\n", force_interrupt);
- new_state = old_state | INTERRUPT_REQUEST_DEFERRED_BIT;
- } else
- new_state = old_state | INTERRUPT_REQUESTED_BIT;
+ if (sync)
+ new_state = old_state | INTERRUPT_SYNC_REQUESTED_BIT;
+ else
+ new_state = old_state | INTERRUPT_ASYNC_REQUESTED_BIT;
} while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
- return (new_state & INTERRUPT_REQUESTED_BIT) == INTERRUPT_REQUESTED_BIT;
+ InterlockedIncrement (&thread_interruption_requested);
+
+ return sync || !(new_state & ABORT_PROT_BLOCK_MASK);
}
static inline MonoNativeThreadId
mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal);
static gboolean
-mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean force_domain, gsize *stack_ptr)
+mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean force_domain)
{
MonoThreadInfo *info;
MonoInternalThread *internal;
internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ());
internal->thread_info = info;
internal->small_id = info->small_id;
- internal->stack_ptr = stack_ptr;
THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), internal));
MonoObject *start_delegate_arg;
MonoThreadStart start_func;
gpointer start_func_arg;
+ gboolean force_attach;
gboolean failed;
MonoCoopSem registered;
} StartInfo;
THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, mono_native_thread_id_get ()));
- if (!mono_thread_attach_internal (thread, FALSE, FALSE, stack_ptr)) {
+ if (!mono_thread_attach_internal (thread, start_info->force_attach, FALSE)) {
start_info->failed = TRUE;
mono_coop_sem_post (&start_info->registered);
return(0);
}
-static gsize WINAPI start_wrapper(void *data)
+static gsize WINAPI
+start_wrapper (gpointer data)
{
- volatile gsize dummy;
+ StartInfo *start_info;
+ MonoThreadInfo *info;
+ gsize res;
- return start_wrapper_internal ((StartInfo*) data, (gsize*) &dummy);
+ start_info = (StartInfo*) data;
+ g_assert (start_info);
+
+ info = mono_thread_info_attach (&res);
+ info->runtime_thread = TRUE;
+
+ /* Run the actual main function of the thread */
+ res = start_wrapper_internal (start_info, &res);
+
+ mono_thread_info_exit (res);
+
+ g_assert_not_reached ();
}
/*
*/
static gboolean
create_thread (MonoThread *thread, MonoInternalThread *internal, MonoObject *start_delegate, MonoThreadStart start_func, gpointer start_func_arg,
- gboolean threadpool_thread, guint32 stack_size, MonoError *error)
+ MonoThreadCreateFlags flags, MonoError *error)
{
StartInfo *start_info = NULL;
- MonoThreadHandle *thread_handle;
MonoNativeThreadId tid;
gboolean ret;
gsize stack_set_size;
if (start_func)
g_assert (!start_delegate);
+ if (flags & MONO_THREAD_CREATE_FLAGS_THREADPOOL) {
+ g_assert (!(flags & MONO_THREAD_CREATE_FLAGS_DEBUGGER));
+ g_assert (!(flags & MONO_THREAD_CREATE_FLAGS_FORCE_CREATE));
+ }
+ if (flags & MONO_THREAD_CREATE_FLAGS_DEBUGGER) {
+ g_assert (!(flags & MONO_THREAD_CREATE_FLAGS_THREADPOOL));
+ g_assert (!(flags & MONO_THREAD_CREATE_FLAGS_FORCE_CREATE));
+ }
+
/*
* Join joinable threads to prevent running out of threads since the finalizer
* thread might be blocked/backlogged.
error_init (error);
mono_threads_lock ();
- if (shutting_down) {
+ if (shutting_down && !(flags & MONO_THREAD_CREATE_FLAGS_FORCE_CREATE)) {
mono_threads_unlock ();
return FALSE;
}
mono_g_hash_table_insert (threads_starting_up, thread, thread);
mono_threads_unlock ();
- internal->threadpool_thread = threadpool_thread;
- if (threadpool_thread)
+ internal->threadpool_thread = flags & MONO_THREAD_CREATE_FLAGS_THREADPOOL;
+ if (internal->threadpool_thread)
mono_thread_set_state (internal, ThreadState_Background);
+ internal->debugger_thread = flags & MONO_THREAD_CREATE_FLAGS_DEBUGGER;
+
start_info = g_new0 (StartInfo, 1);
start_info->ref = 2;
start_info->thread = thread;
start_info->start_delegate_arg = thread->start_obj;
start_info->start_func = start_func;
start_info->start_func_arg = start_func_arg;
+ start_info->force_attach = flags & MONO_THREAD_CREATE_FLAGS_FORCE_CREATE;
start_info->failed = FALSE;
mono_coop_sem_init (&start_info->registered, 0);
- if (stack_size == 0)
+ if (flags != MONO_THREAD_CREATE_FLAGS_SMALL_STACK)
stack_set_size = default_stacksize_for_thread (internal);
else
stack_set_size = 0;
- thread_handle = mono_threads_create_thread (start_wrapper, start_info, &stack_set_size, &tid);
-
- if (thread_handle == NULL) {
+ if (!mono_thread_platform_create_thread (start_wrapper, start_info, &stack_set_size, &tid)) {
/* The thread couldn't be created, so set an exception */
mono_threads_lock ();
mono_g_hash_table_remove (threads_starting_up, thread);
mono_coop_sem_wait (&start_info->registered, MONO_SEM_FLAGS_NONE);
- mono_threads_close_thread_handle (thread_handle);
-
THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
ret = !start_info->failed;
* ARG should not be a GC reference.
*/
MonoInternalThread*
-mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size, MonoError *error)
+mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, MonoThreadCreateFlags flags, MonoError *error)
{
MonoThread *thread;
MonoInternalThread *internal;
LOCK_THREAD (internal);
- res = create_thread (thread, internal, NULL, (MonoThreadStart) func, arg, threadpool_thread, stack_size, error);
- return_val_if_nok (error, NULL);
+ res = create_thread (thread, internal, NULL, (MonoThreadStart) func, arg, flags, error);
UNLOCK_THREAD (internal);
+ return_val_if_nok (error, NULL);
return internal;
}
gboolean
mono_thread_create_checked (MonoDomain *domain, gpointer func, gpointer arg, MonoError *error)
{
- return (NULL != mono_thread_create_internal (domain, func, arg, FALSE, 0, error));
+ return (NULL != mono_thread_create_internal (domain, func, arg, MONO_THREAD_CREATE_FLAGS_NONE, error));
}
MonoThread *
{
MonoInternalThread *internal;
MonoThread *thread;
+ MonoThreadInfo *info;
MonoNativeThreadId tid;
gsize stack_ptr;
return mono_thread_current ();
}
- if (!mono_gc_register_thread (&domain)) {
- g_error ("Thread %"G_GSIZE_FORMAT" calling into managed code is not registered with the GC. On UNIX, this can be fixed by #include-ing <gc.h> before <pthread.h> in the file containing the thread creation code.", mono_native_thread_id_get ());
- }
+ info = mono_thread_info_attach (&stack_ptr);
+ g_assert (info);
tid=mono_native_thread_id_get ();
thread = create_thread_object (domain, internal);
- if (!mono_thread_attach_internal (thread, force_attach, TRUE, &stack_ptr)) {
+ if (!mono_thread_attach_internal (thread, force_attach, TRUE)) {
/* Mono is shutting down, so just wait for the end */
for (;;)
mono_thread_info_sleep (10000, NULL);
thread->abort_exc = NULL;
thread->current_appcontext = NULL;
- /*
- * This is necessary because otherwise we might have
- * cross-domain references which will not get cleaned up when
- * the target domain is unloaded.
- */
- if (thread->cached_culture_info) {
- int i;
- for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
- mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
- }
-
/*
* thread->synch_cs can be NULL if this was called after
* ves_icall_System_Threading_InternalThread_Thread_free_internal.
Leaving the counter unbalanced will cause a performance degradation since all threads
will now keep checking their local flags all the time.
*/
- if (mono_thread_clear_interruption_requested (thread))
- InterlockedDecrement (&thread_interruption_requested);
+ mono_thread_clear_interruption_requested (thread);
mono_threads_lock ();
if (thread == mono_thread_internal_current ())
mono_thread_pop_appdomain_ref ();
- thread->cached_culture_info = NULL;
-
mono_free_static_data (thread->static_data);
thread->static_data = NULL;
ref_stack_destroy (thread->appdomain_refs);
return this_obj;
}
- res = create_thread (this_obj, internal, start, NULL, NULL, FALSE, 0, &error);
+ res = create_thread (this_obj, internal, start, NULL, NULL, MONO_THREAD_CREATE_FLAGS_NONE, &error);
if (!res) {
mono_error_cleanup (&error);
UNLOCK_THREAD (internal);
{
LOCK_THREAD (thread);
- if ((thread->state & ThreadState_AbortRequested) != 0 ||
- (thread->state & ThreadState_StopRequested) != 0 ||
- (thread->state & ThreadState_Stopped) != 0)
+ if (thread->state & (ThreadState_AbortRequested | ThreadState_Stopped))
{
UNLOCK_THREAD (thread);
return FALSE;
{
LOCK_THREAD (thread);
- if ((thread->state & ThreadState_Unstarted) != 0 ||
- (thread->state & ThreadState_Aborted) != 0 ||
- (thread->state & ThreadState_Stopped) != 0)
+ if (thread->state & (ThreadState_Unstarted | ThreadState_Aborted | ThreadState_Stopped))
{
UNLOCK_THREAD (thread);
return FALSE;
}
- if ((thread->state & ThreadState_Suspended) != 0 ||
- (thread->state & ThreadState_SuspendRequested) != 0 ||
- (thread->state & ThreadState_StopRequested) != 0)
+ if (thread->state & (ThreadState_Suspended | ThreadState_SuspendRequested | ThreadState_AbortRequested))
{
UNLOCK_THREAD (thread);
return TRUE;
{
MonoInternalThread *internal = thread->internal_thread;
- LOCK_THREAD (internal);
-
- if (internal->state & (ThreadState_StopRequested | ThreadState_Stopped))
- {
- UNLOCK_THREAD (internal);
+ if (!request_thread_abort (internal, NULL))
return;
- }
-
- /* Make sure the internal is awake */
- mono_thread_resume (internal);
-
- internal->state |= ThreadState_StopRequested;
- internal->state &= ~ThreadState_AbortRequested;
-
- UNLOCK_THREAD (internal);
if (internal == mono_thread_internal_current ()) {
MonoError error;
LOCK_THREAD (current_thread);
- if ((current_thread->state & ThreadState_SuspendRequested) ||
- (current_thread->state & ThreadState_AbortRequested) ||
- (current_thread->state & ThreadState_StopRequested)) {
+ if (current_thread->state & (ThreadState_SuspendRequested | ThreadState_AbortRequested)) {
UNLOCK_THREAD (current_thread);
mono_thread_execute_interruption ();
} else {
- current_thread->state |= ThreadState_Stopped;
UNLOCK_THREAD (current_thread);
}
LOCK_THREAD (thread);
- if ((thread->state & ThreadState_Suspended) != 0 ||
- (thread->state & ThreadState_StopRequested) != 0 ||
- (thread->state & ThreadState_Stopped) != 0) {
+ if (thread->state & (ThreadState_Suspended | ThreadState_Stopped)) {
UNLOCK_THREAD (thread);
mono_threads_close_thread_handle (wait->handles [i]);
wait->threads [i] = NULL;
return TRUE;
}
-static void
-clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
-{
- MonoInternalThread *thread = (MonoInternalThread*)value;
- MonoDomain *domain = (MonoDomain*)user_data;
- int i;
-
- /* No locking needed here */
- /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
-
- if (thread->cached_culture_info) {
- for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
- MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
- if (obj && obj->vtable->domain == domain)
- mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
- }
- }
-}
-
-/*
- * mono_threads_clear_cached_culture:
- *
- * Clear the cached_current_culture from all threads if it is in the
- * given appdomain.
- */
-void
-mono_threads_clear_cached_culture (MonoDomain *domain)
-{
- mono_threads_lock ();
- mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
- mono_threads_unlock ();
-}
-
/*
* mono_thread_get_undeniable_exception:
*
#ifdef HOST_WIN32
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_self_interrupt ();
}
UNLOCK_THREAD (thread);
return exc;
- } else if ((thread->state & ThreadState_AbortRequested) != 0) {
+ } else if (thread->state & (ThreadState_AbortRequested)) {
UNLOCK_THREAD (thread);
g_assert (sys_thread->pending_exception == NULL);
if (thread->abort_exc == NULL) {
MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
}
return thread->abort_exc;
- }
- else if ((thread->state & ThreadState_SuspendRequested) != 0) {
+ } else if (thread->state & (ThreadState_SuspendRequested)) {
/* calls UNLOCK_THREAD (thread) */
self_suspend_internal ();
return NULL;
- }
- else if ((thread->state & ThreadState_StopRequested) != 0) {
- /* FIXME: do this through the JIT? */
-
- UNLOCK_THREAD (thread);
-
- mono_thread_exit ();
- return NULL;
} else if (thread->thread_interrupt_requested) {
thread->thread_interrupt_requested = FALSE;
if (thread == NULL)
return NULL;
-#ifdef HOST_WIN32
- if (thread->interrupt_on_stop &&
- thread->state & ThreadState_StopRequested &&
- thread->state & ThreadState_Background)
- ExitThread (1);
-#endif
if (!mono_thread_set_interruption_requested (thread))
return NULL;
- InterlockedIncrement (&thread_interruption_requested);
if (!running_managed || is_running_protected_wrapper ()) {
/* Can't stop while in unmanaged code. Increase the global interruption
/*This function should be called by a thread after it has exited all of
* its handle blocks at interruption time.*/
MonoException*
-mono_thread_resume_interruption (void)
+mono_thread_resume_interruption (gboolean exec)
{
MonoInternalThread *thread = mono_thread_internal_current ();
gboolean still_aborting;
return NULL;
LOCK_THREAD (thread);
- still_aborting = (thread->state & (ThreadState_AbortRequested|ThreadState_StopRequested)) != 0;
+ still_aborting = (thread->state & (ThreadState_AbortRequested)) != 0;
UNLOCK_THREAD (thread);
/*This can happen if the protected block called Thread::ResetAbort*/
if (!still_aborting)
- return FALSE;
+ return NULL;
if (!mono_thread_set_interruption_requested (thread))
return NULL;
- InterlockedIncrement (&thread_interruption_requested);
mono_thread_info_self_interrupt ();
- return mono_thread_execute_interruption ();
+ if (exec)
+ return mono_thread_execute_interruption ();
+ else
+ return NULL;
}
gboolean mono_thread_interruption_requested ()
if (!mono_thread_set_interruption_requested (thread))
return MonoResumeThread;
- InterlockedIncrement (&thread_interruption_requested);
-
ji = mono_thread_info_get_last_managed (info);
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));
return KeepSuspended;
}
} else {
- if (mono_thread_set_interruption_requested (thread))
- InterlockedIncrement (&thread_interruption_requested);
+ mono_thread_set_interruption_requested (thread);
if (data->interrupt)
data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
#endif
}
-void
-mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
-{
- if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
- mono_thread_interruption_checkpoint ();
-}
-
void
mono_thread_internal_unhandled_exception (MonoObject* exc)
{
}
}
-MonoException*
-mono_thread_try_resume_interruption (void)
-{
- MonoInternalThread *thread;
-
- thread = mono_thread_internal_current ();
- if (!mono_get_eh_callbacks ()->mono_above_abort_threshold ())
- return NULL;
- if (mono_thread_get_abort_prot_block_count (thread) > 0 || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ())
- return NULL;
-
- return mono_thread_resume_interruption ();
-}
-
#if 0
/* Returns TRUE if the current thread is ready to be interrupted. */
gboolean
thread = mono_thread_internal_current ();
LOCK_THREAD (thread);
- if (thread->state & (MonoThreadState)(ThreadState_StopRequested | ThreadState_SuspendRequested | ThreadState_AbortRequested)) {
+ if (thread->state & (ThreadState_SuspendRequested | ThreadState_AbortRequested)) {
UNLOCK_THREAD (thread);
return FALSE;
}