#include <mono/utils/mono-error-internals.h>
#include <mono/utils/os-event.h>
#include <mono/utils/mono-threads-debug.h>
+#include <mono/utils/unlocked.h>
#include <mono/metadata/w32handle.h>
#include <mono/metadata/w32event.h>
#include <mono/metadata/w32mutex.h>
#include <mono/metadata/abi-details.h>
#include <mono/metadata/w32error.h>
#include <mono/utils/w32api.h>
+#include <mono/utils/mono-os-wait.h>
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#include <objbase.h>
#endif
-#if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
+#if defined(HOST_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
#define USE_TKILL_ON_ANDROID 1
#endif
-#ifdef PLATFORM_ANDROID
+#ifdef HOST_ANDROID
#include <errno.h>
#ifdef USE_TKILL_ON_ANDROID
/* Contains tids */
/* Protected by the threads lock */
static GHashTable *joinable_threads;
-static int joinable_thread_count;
+static gint32 joinable_thread_count;
#define SET_CURRENT_OBJECT(x) mono_tls_set_thread (x)
#define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_tls_get_thread ()
static gint32 managed_thread_id_counter = 0;
-/* Class lazy loading functions */
-static GENERATE_GET_CLASS_WITH_CACHE (appdomain_unloaded_exception, "System", "AppDomainUnloadedException")
-
static void
mono_threads_lock (void)
{
#define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
#define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
-#define MAKE_SPECIAL_STATIC_OFFSET(index, offset, type) \
- ((SpecialStaticOffset) { .fields = { (index), (offset), (type) } }.raw)
+#define MAKE_SPECIAL_STATIC_OFFSET(idx, off, ty) \
+ ((SpecialStaticOffset) { .fields = { .index = (idx), .offset = (off), .type = (ty) } }.raw)
#define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
(((SpecialStaticOffset *) &(x))->fields.f)
mono_thread_detach_internal (internal);
- internal->tid = 0;
-
return(0);
}
}
gboolean
-ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
+ves_icall_System_Threading_Thread_Join_internal (MonoThread *this_obj, int ms)
{
MonoInternalThread *thread = this_obj->internal_thread;
MonoThreadHandle *handle = thread->handle;
return FALSE;
}
+ MonoNativeThreadId tid = thread_get_tid (thread);
+
UNLOCK_THREAD (thread);
- if(ms== -1) {
- ms=MONO_INFINITE_WAIT;
- }
+ if (ms == -1)
+ ms = MONO_INFINITE_WAIT;
THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
-
+
mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
- ret=mono_join_uninterrupted (handle, ms, &error);
+ ret = mono_join_uninterrupted (handle, ms, &error);
mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
mono_error_set_pending_exception (&error);
- if(ret==MONO_THREAD_INFO_WAIT_RET_SUCCESS_0) {
+ if (ret == MONO_THREAD_INFO_WAIT_RET_SUCCESS_0) {
THREAD_DEBUG (g_message ("%s: join successful", __func__));
- return(TRUE);
+#ifdef HOST_WIN32
+ /* TODO: Do this on Unix platforms as well. See PR #5454 for context. */
+ /* Wait for the thread to really exit */
+ MONO_ENTER_GC_SAFE;
+ /* This shouldn't block */
+ mono_threads_join_lock ();
+ mono_native_thread_join (tid);
+ mono_threads_join_unlock ();
+ MONO_EXIT_GC_SAFE;
+#endif
+
+ return TRUE;
}
THREAD_DEBUG (g_message ("%s: join failed", __func__));
- return(FALSE);
+ return FALSE;
}
#define MANAGED_WAIT_FAILED 0x7fffffff
MONO_ENTER_GC_SAFE;
#ifdef HOST_WIN32
if (numhandles != 1)
- ret = mono_w32handle_convert_wait_ret (WaitForMultipleObjectsEx (numhandles, handles, waitall, timeoutLeft, TRUE), numhandles);
+ ret = mono_w32handle_convert_wait_ret (mono_win32_wait_for_multiple_objects_ex(numhandles, handles, waitall, timeoutLeft, TRUE), numhandles);
else
- ret = mono_w32handle_convert_wait_ret (WaitForSingleObjectEx (handles [0], timeoutLeft, TRUE), 1);
+ ret = mono_w32handle_convert_wait_ret (mono_win32_wait_for_single_object_ex (handles [0], timeoutLeft, TRUE), 1);
#else
/* mono_w32handle_wait_multiple optimizes the case for numhandles == 1 */
ret = mono_w32handle_wait_multiple (handles, numhandles, waitall, timeoutLeft, TRUE);
MONO_ENTER_GC_SAFE;
#ifdef HOST_WIN32
- ret = mono_w32handle_convert_wait_ret (SignalObjectAndWait (toSignal, toWait, ms, TRUE), 1);
+ ret = mono_w32handle_convert_wait_ret (mono_win32_signal_object_and_wait (toSignal, toWait, ms, TRUE), 1);
#else
ret = mono_w32handle_signal_and_wait (toSignal, toWait, ms, TRUE);
#endif
}
static gboolean
-request_thread_abort (MonoInternalThread *thread, MonoObject *state)
+request_thread_abort (MonoInternalThread *thread, MonoObject *state, gboolean appdomain_unload)
{
LOCK_THREAD (thread);
}
thread->state |= ThreadState_AbortRequested;
+ if (appdomain_unload)
+ thread->flags |= MONO_THREAD_FLAG_APPDOMAIN_ABORT;
+ else
+ thread->flags &= ~MONO_THREAD_FLAG_APPDOMAIN_ABORT;
+
if (thread->abort_state_handle)
mono_gchandle_free (thread->abort_state_handle);
if (state) {
void
ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
{
- if (!request_thread_abort (thread, state))
+ if (!request_thread_abort (thread, state, FALSE))
return;
if (thread == mono_thread_internal_current ()) {
* \p thread MUST NOT be the current thread.
*/
void
-mono_thread_internal_abort (MonoInternalThread *thread)
+mono_thread_internal_abort (MonoInternalThread *thread, gboolean appdomain_unload)
{
g_assert (thread != mono_thread_internal_current ());
- if (!request_thread_abort (thread, NULL))
+ if (!request_thread_abort (thread, NULL, appdomain_unload))
return;
async_abort_internal (thread, TRUE);
}
ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
{
MonoInternalThread *thread = mono_thread_internal_current ();
- gboolean was_aborting;
+ gboolean was_aborting, is_domain_abort;
LOCK_THREAD (thread);
was_aborting = thread->state & ThreadState_AbortRequested;
- thread->state &= ~ThreadState_AbortRequested;
+ is_domain_abort = thread->flags & MONO_THREAD_FLAG_APPDOMAIN_ABORT;
+
+ if (was_aborting && !is_domain_abort)
+ thread->state &= ~ThreadState_AbortRequested;
UNLOCK_THREAD (thread);
if (!was_aborting) {
const char *msg = "Unable to reset abort because no abort was requested";
mono_set_pending_exception (mono_get_exception_thread_state (msg));
return;
+ } else if (is_domain_abort) {
+ /* Silently ignore abort resets in unloading appdomains */
+ return;
}
mono_get_eh_callbacks ()->mono_clear_abort_threshold ();
{
MonoInternalThread *internal = thread->internal_thread;
- if (!request_thread_abort (internal, NULL))
+ if (!request_thread_abort (internal, NULL, FALSE))
return;
if (internal == mono_thread_internal_current ()) {
void
mono_thread_cleanup (void)
{
+ mono_threads_join_threads ();
+
#if !defined(RUN_IN_SUBTHREAD) && !defined(HOST_WIN32)
/* The main thread must abandon any held mutexes (particularly
* important for named mutexes as they are shared across
wait->num++;
THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
- mono_thread_internal_abort (thread);
+ mono_thread_internal_abort (thread, FALSE);
}
return TRUE;
if (user_data.wait.num > 0) {
/* Abort the threads outside the threads lock */
for (i = 0; i < user_data.wait.num; ++i)
- mono_thread_internal_abort (user_data.wait.threads [i]);
+ mono_thread_internal_abort (user_data.wait.threads [i], TRUE);
/*
* We should wait for the threads either to abort, or to leave the
}
/* this will consume pending APC calls */
-#ifdef HOST_WIN32
- WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
+#ifdef USE_WINDOWS_BACKEND
+ mono_win32_wait_for_single_object_ex (GetCurrentThread (), 0, TRUE);
#endif
+
/* Clear the interrupted flag of the thread so it can wait again */
mono_thread_info_clear_self_interrupt ();
/* this will awake the thread if it is in WaitForSingleObject
or similar */
- /* Our implementation of this function ignores the func argument */
-#ifdef HOST_WIN32
- QueueUserAPC ((PAPCFUNC)dummy_apc, thread->native_handle, (ULONG_PTR)NULL);
+#ifdef USE_WINDOWS_BACKEND
+ mono_win32_interrupt_wait (thread->thread_info, thread->native_handle, (DWORD)thread->tid);
#else
mono_thread_info_self_interrupt ();
#endif
if (!joinable_threads)
joinable_threads = g_hash_table_new (NULL, NULL);
g_hash_table_insert (joinable_threads, tid, tid);
- joinable_thread_count ++;
+ UnlockedIncrement (&joinable_thread_count);
joinable_threads_unlock ();
mono_gc_finalize_notify ();
gboolean found;
/* Fastpath */
- if (!joinable_thread_count)
+ if (!UnlockedRead (&joinable_thread_count))
return;
while (TRUE) {
g_hash_table_iter_next (&iter, &key, (void**)&tid);
thread = (pthread_t)tid;
g_hash_table_remove (joinable_threads, key);
- joinable_thread_count --;
+ UnlockedDecrement (&joinable_thread_count);
found = TRUE;
}
joinable_threads_unlock ();
joinable_threads = g_hash_table_new (NULL, NULL);
if (g_hash_table_lookup (joinable_threads, tid)) {
g_hash_table_remove (joinable_threads, tid);
- joinable_thread_count --;
+ UnlockedDecrement (&joinable_thread_count);
found = TRUE;
}
joinable_threads_unlock ();