#include <mono/metadata/exception.h>
#include <mono/metadata/environment.h>
#include <mono/metadata/monitor.h>
-#include <mono/metadata/gc-internal.h>
+#include <mono/metadata/gc-internals.h>
#include <mono/metadata/marshal.h>
#include <mono/metadata/runtime.h>
#include <mono/io-layer/io-layer.h>
#include <mono/utils/atomic.h>
#include <mono/utils/mono-memory-model.h>
-#include <mono/metadata/gc-internal.h>
+#include <mono/metadata/gc-internals.h>
#ifdef HAVE_SIGNAL_H
#include <signal.h>
/* Controls access to the 'threads' hash table */
static void mono_threads_lock (void);
static void mono_threads_unlock (void);
-static mono_mutex_t threads_mutex;
+static MonoCoopMutex threads_mutex;
/* Controls access to the 'joinable_threads' hash table */
-#define joinable_threads_lock() mono_mutex_lock (&joinable_threads_mutex)
-#define joinable_threads_unlock() mono_mutex_unlock (&joinable_threads_mutex)
+#define joinable_threads_lock() mono_os_mutex_lock (&joinable_threads_mutex)
+#define joinable_threads_unlock() mono_os_mutex_unlock (&joinable_threads_mutex)
static mono_mutex_t joinable_threads_mutex;
/* Holds current status of static data heap */
static void abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort);
static void suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt);
static void self_suspend_internal (MonoInternalThread *thread);
-static gboolean resume_thread_internal (MonoInternalThread *thread);
static MonoException* mono_thread_execute_interruption ();
static void ref_stack_destroy (gpointer rs);
/* Spin lock for InterlockedXXX 64 bit functions */
-#define mono_interlocked_lock() mono_mutex_lock (&interlocked_mutex)
-#define mono_interlocked_unlock() mono_mutex_unlock (&interlocked_mutex)
+#define mono_interlocked_lock() mono_os_mutex_lock (&interlocked_mutex)
+#define mono_interlocked_unlock() mono_os_mutex_unlock (&interlocked_mutex)
static mono_mutex_t interlocked_mutex;
/* global count of thread interruptions requested */
static void
mono_threads_lock (void)
{
- MONO_TRY_BLOCKING;
- mono_locks_acquire (&threads_mutex, ThreadsLock);
- MONO_FINISH_TRY_BLOCKING;
+ mono_locks_coop_acquire (&threads_mutex, ThreadsLock);
}
static void
mono_threads_unlock (void)
{
- mono_locks_release (&threads_mutex, ThreadsLock);
+ mono_locks_coop_release (&threads_mutex, ThreadsLock);
}
static void ensure_synch_cs_set (MonoInternalThread *thread)
{
- mono_mutex_t *synch_cs;
+ MonoCoopMutex *synch_cs;
if (thread->synch_cs != NULL) {
return;
}
- synch_cs = g_new0 (mono_mutex_t, 1);
- mono_mutex_init_recursive (synch_cs);
+ synch_cs = g_new0 (MonoCoopMutex, 1);
+ mono_coop_mutex_init_recursive (synch_cs);
if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
synch_cs, NULL) != NULL) {
/* Another thread must have installed this CS */
- mono_mutex_destroy (synch_cs);
+ mono_coop_mutex_destroy (synch_cs);
g_free (synch_cs);
}
}
g_assert (thread->synch_cs);
- MONO_TRY_BLOCKING;
- mono_mutex_lock (thread->synch_cs);
- MONO_FINISH_TRY_BLOCKING;
+ mono_coop_mutex_lock (thread->synch_cs);
}
static inline void
unlock_thread (MonoInternalThread *thread)
{
- mono_mutex_unlock (thread->synch_cs);
+ mono_coop_mutex_unlock (thread->synch_cs);
}
/*
MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
thread->thread_pinning_ref = NULL;
}
+
}
/*
mono_domain_unlock (domain);
g_assert (offset);
- return get_thread_static_data (thread, offset);
+ return (MonoThread **)get_thread_static_data (thread, offset);
}
static void
vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
thread = (MonoInternalThread*)mono_gc_alloc_mature (vt);
- thread->synch_cs = g_new0 (mono_mutex_t, 1);
- mono_mutex_init_recursive (thread->synch_cs);
+ thread->synch_cs = g_new0 (MonoCoopMutex, 1);
+ mono_coop_mutex_init_recursive (thread->synch_cs);
thread->apartment_state = ThreadApartmentState_Unknown;
thread->managed_id = get_next_managed_thread_id ();
MonoObject *start_delegate = start_info->delegate;
MonoDomain *domain = start_info->obj->obj.vtable->domain;
- THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, GetCurrentThreadId ()));
+ THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, mono_native_thread_id_get ()));
/* We can be sure start_info->obj->tid and
* start_info->obj->handle have been set, because the thread
*/
mono_thread_new_init (tid, &tid, start_func);
internal->stack_ptr = &tid;
+ if (domain != mono_get_root_domain ())
+ set_current_thread_for_domain (domain, internal, start_info->obj);
- LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, GetCurrentThreadId (), getpid (), thread->stack_ptr));
+ LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, mono_native_thread_id_get (), getpid (), thread->stack_ptr));
- THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), internal));
+ THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), internal));
/* On 2.0 profile (and higher), set explicitly since state might have been
Unknown */
* call thread_cleanup() on this thread's behalf.
*/
- THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, GetCurrentThreadId ()));
+ THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, mono_native_thread_id_get ()));
/* Do any cleanup needed for apartment state. This
* cannot be done in thread_cleanup since thread_cleanup could be
*/
create_flags = CREATE_SUSPENDED;
- MONO_PREPARE_BLOCKING;
thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)start_wrapper, start_info,
stack_size, create_flags, &tid);
- MONO_FINISH_BLOCKING;
if (thread_handle == NULL) {
/* The thread couldn't be created, so throw an exception */
if (threadpool_thread)
mono_thread_set_state (internal, ThreadState_Background);
- THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
+ THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
/* Only store the handle when the thread is about to be
* launched, to avoid the main thread deadlocking while trying
if (!handle_store (thread, FALSE))
return FALSE;
- MONO_PREPARE_BLOCKING;
mono_thread_info_resume (tid);
- MONO_FINISH_BLOCKING;
if (internal->start_notify) {
/*
* to look up the data believing the thread has
* started
*/
- THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
+ THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
MONO_PREPARE_BLOCKING;
WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
internal->start_notify = NULL;
}
- THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
+ THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
return TRUE;
}
MONO_OBJECT_SETREF (thread, internal_thread, internal);
start_info = g_new0 (StartInfo, 1);
- start_info->func = func;
+ start_info->func = (guint32 (*)(void *))func;
start_info->obj = thread;
start_info->start_arg = arg;
return NULL;
/* Check that the managed and unmanaged layout of MonoInternalThread matches */
+#ifndef MONO_CROSS_COMPILE
if (mono_check_corlib_version () == NULL)
g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
+#endif
return internal;
}
MonoInternalThread *thread;
MonoThread *current_thread;
HANDLE thread_handle;
- gsize tid;
+ MonoNativeThreadId tid;
if ((thread = mono_thread_internal_current ())) {
if (domain != mono_domain_get ())
}
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 ());
+ 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 ());
}
thread = create_internal_thread ();
thread_handle = mono_thread_info_open_handle ();
g_assert (thread_handle);
- tid=GetCurrentThreadId ();
+ tid=mono_native_thread_id_get ();
thread->handle = thread_handle;
- thread->tid = tid;
+ thread->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
thread->stack_ptr = &tid;
THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
if (!handle_store (current_thread, force_attach)) {
/* Mono is shutting down, so just wait for the end */
for (;;)
- Sleep (10000);
+ mono_thread_info_sleep (10000, NULL);
}
- THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), thread));
+ THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), thread));
SET_CURRENT_OBJECT (thread);
mono_domain_set (domain, TRUE);
mono_thread_info_get_stack_bounds (&staddr, &stsize);
if (staddr == NULL)
- mono_thread_attach_cb (tid, &tid);
+ mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), &tid);
else
- mono_thread_attach_cb (tid, staddr + stsize);
+ mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), staddr + stsize);
}
// FIXME: Need a separate callback
- mono_profiler_thread_start (tid);
+ mono_profiler_thread_start (MONO_NATIVE_THREAD_ID_TO_UINT (tid));
return current_thread;
}
internal->state = ThreadState_Unstarted;
- InterlockedCompareExchangePointer ((gpointer)&this_obj->internal_thread, internal, NULL);
+ InterlockedCompareExchangePointer ((volatile gpointer *)&this_obj->internal_thread, internal, NULL);
}
HANDLE
CloseHandle (thread);
if (this_obj->synch_cs) {
- mono_mutex_t *synch_cs = this_obj->synch_cs;
+ MonoCoopMutex *synch_cs = this_obj->synch_cs;
this_obj->synch_cs = NULL;
- mono_mutex_destroy (synch_cs);
+ mono_coop_mutex_destroy (synch_cs);
g_free (synch_cs);
}
THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
mono_thread_current_check_pending_interrupt ();
-
+
while (TRUE) {
+ gboolean alerted = FALSE;
+
mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
-
- MONO_PREPARE_BLOCKING;
- res = SleepEx(ms,TRUE);
- MONO_FINISH_BLOCKING;
-
+
+ res = mono_thread_info_sleep (ms, &alerted);
+
mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
- if (res == WAIT_IO_COMPLETION) { /* we might have been interrupted */
+ if (alerted) {
MonoException* exc = mono_thread_execute_interruption ();
if (exc) {
mono_raise_exception (exc);
}
int
-ves_icall_System_Threading_Thread_GetPriority (MonoThread *this)
+ves_icall_System_Threading_Thread_GetPriority (MonoThread *this_obj)
{
return ThreadPriority_Lowest;
}
return *current_thread_ptr;
}
+/* Return the thread object belonging to INTERNAL in the current domain */
+static MonoThread *
+mono_thread_current_for_thread (MonoInternalThread *internal)
+{
+ MonoDomain *domain = mono_domain_get ();
+ MonoThread **current_thread_ptr;
+
+ 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;
+}
+
MonoInternalThread*
mono_thread_internal_current (void)
{
g_free(handles);
if(ret==WAIT_FAILED) {
- THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
+ THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, mono_native_thread_id_get ()));
return(FALSE);
} else if(ret==WAIT_TIMEOUT) {
- THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
+ THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, mono_native_thread_id_get ()));
return(FALSE);
}
mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
- THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, GetCurrentThreadId (), ret));
+ THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, mono_native_thread_id_get (), ret));
/*
* These need to be here. See MSDN dos on WaitForMultipleObjects.
guint32 ret;
MonoInternalThread *thread = mono_thread_internal_current ();
- THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, GetCurrentThreadId (), handle, ms));
+ THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, mono_native_thread_id_get (), handle, ms));
if(ms== -1) {
ms=INFINITE;
mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
if(ret==WAIT_FAILED) {
- THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
+ THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, mono_native_thread_id_get ()));
return(FALSE);
} else if(ret==WAIT_TIMEOUT) {
- THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
+ THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, mono_native_thread_id_get ()));
return(FALSE);
}
ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
{
MonoObject *res;
- res = InterlockedCompareExchangePointer ((gpointer *)location, value, comparand);
+ res = (MonoObject *)InterlockedCompareExchangePointer ((volatile gpointer *)location, value, comparand);
mono_gc_wbarrier_generic_nostore (location);
return res;
}
ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
{
MonoObject *res;
- res = InterlockedExchangePointer ((gpointer *)location, value);
+ res = (MonoObject *)InterlockedExchangePointer ((volatile gpointer *)location, value);
mono_gc_wbarrier_generic_nostore (location);
return res;
}
}
void
-ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this, guint32 state)
+ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this_obj, guint32 state)
{
- mono_thread_clr_state (this, state);
+ mono_thread_clr_state (this_obj, (MonoThreadState)state);
if (state & ThreadState_Background) {
/* If the thread changes the background mode, the main thread has to
}
void
-ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this, guint32 state)
+ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this_obj, guint32 state)
{
- mono_thread_set_state (this, state);
+ mono_thread_set_state (this_obj, (MonoThreadState)state);
if (state & ThreadState_Background) {
/* If the thread changes the background mode, the main thread has to
}
guint32
-ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this)
+ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this_obj)
{
guint32 state;
- LOCK_THREAD (this);
+ LOCK_THREAD (this_obj);
- state = this->state;
+ state = this_obj->state;
- UNLOCK_THREAD (this);
+ UNLOCK_THREAD (this_obj);
return state;
}
void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
{
MonoInternalThread *current;
- gboolean throw;
+ gboolean throw_;
MonoInternalThread *thread = this_obj->internal_thread;
LOCK_THREAD (thread);
current = mono_thread_internal_current ();
thread->thread_interrupt_requested = TRUE;
- throw = current != thread && (thread->state & ThreadState_WaitSleepJoin);
+ throw_ = current != thread && (thread->state & ThreadState_WaitSleepJoin);
UNLOCK_THREAD (thread);
- if (throw) {
+ if (throw_) {
abort_thread_internal (thread, TRUE, FALSE);
}
}
void mono_thread_current_check_pending_interrupt ()
{
MonoInternalThread *thread = mono_thread_internal_current ();
- gboolean throw = FALSE;
+ gboolean throw_ = FALSE;
LOCK_THREAD (thread);
if (thread->thread_interrupt_requested) {
- throw = TRUE;
+ throw_ = TRUE;
thread->thread_interrupt_requested = FALSE;
}
UNLOCK_THREAD (thread);
- if (throw) {
+ if (throw_) {
mono_raise_exception (mono_get_exception_thread_interrupted ());
}
}
}
thread->abort_exc = NULL;
- UNLOCK_THREAD (thread);
-
- THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
+ THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), thread, (gsize)thread->tid));
/* During shutdown, we can't wait for other threads */
if (!shutting_down)
/* Make sure the thread is awake */
mono_thread_resume (thread);
-
+
+ UNLOCK_THREAD (thread);
+
abort_thread_internal (thread, TRUE, TRUE);
}
}
}
+/* LOCKING: LOCK_THREAD(thread) must be held */
static gboolean
mono_thread_resume (MonoInternalThread *thread)
{
- LOCK_THREAD (thread);
-
if ((thread->state & ThreadState_SuspendRequested) != 0) {
thread->state &= ~ThreadState_SuspendRequested;
- UNLOCK_THREAD (thread);
return TRUE;
}
(thread->state & ThreadState_Aborted) != 0 ||
(thread->state & ThreadState_Stopped) != 0)
{
- UNLOCK_THREAD (thread);
return FALSE;
}
- return resume_thread_internal (thread);
+ UNLOCK_THREAD (thread);
+
+ /* Awake the thread */
+ if (!mono_thread_info_resume (thread_get_tid (thread)))
+ return FALSE;
+
+ LOCK_THREAD (thread);
+
+ thread->state &= ~ThreadState_Suspended;
+
+ return TRUE;
}
void
ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
{
- if (!thread->internal_thread || !mono_thread_resume (thread->internal_thread)) {
+ if (!thread->internal_thread) {
mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
- return;
+ } else {
+ LOCK_THREAD (thread->internal_thread);
+ if (!mono_thread_resume (thread->internal_thread))
+ mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
+ UNLOCK_THREAD (thread->internal_thread);
}
}
gint8
ves_icall_System_Threading_Volatile_Read1 (void *ptr)
{
- return InterlockedRead8 (ptr);
+ return InterlockedRead8 ((volatile gint8 *)ptr);
}
gint16
ves_icall_System_Threading_Volatile_Read2 (void *ptr)
{
- return InterlockedRead16 (ptr);
+ return InterlockedRead16 ((volatile gint16 *)ptr);
}
gint32
ves_icall_System_Threading_Volatile_Read4 (void *ptr)
{
- return InterlockedRead (ptr);
+ return InterlockedRead ((volatile gint32 *)ptr);
}
gint64
return val;
}
#endif
- return InterlockedRead64 (ptr);
+ return InterlockedRead64 ((volatile gint64 *)ptr);
}
void *
ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
{
- return InterlockedReadPointer (ptr);
+ return InterlockedReadPointer ((volatile gpointer *)ptr);
}
double
}
#endif
- u.ival = InterlockedRead64 (ptr);
+ u.ival = InterlockedRead64 ((volatile gint64 *)ptr);
return u.fval;
}
{
IntFloatUnion u;
- u.ival = InterlockedRead (ptr);
+ u.ival = InterlockedRead ((volatile gint32 *)ptr);
return u.fval;
}
MonoObject*
ves_icall_System_Threading_Volatile_Read_T (void *ptr)
{
- return InterlockedReadPointer (ptr);
+ return (MonoObject *)InterlockedReadPointer ((volatile gpointer *)ptr);
}
void
void
ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
{
- InterlockedWrite8 (ptr, value);
+ InterlockedWrite8 ((volatile gint8 *)ptr, value);
}
void
ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
{
- InterlockedWrite16 (ptr, value);
+ InterlockedWrite16 ((volatile gint16 *)ptr, value);
}
void
ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
{
- InterlockedWrite (ptr, value);
+ InterlockedWrite ((volatile gint32 *)ptr, value);
}
void
}
#endif
- InterlockedWrite64 (ptr, value);
+ InterlockedWrite64 ((volatile gint64 *)ptr, value);
}
void
ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
{
- InterlockedWritePointer (ptr, value);
+ InterlockedWritePointer ((volatile gpointer *)ptr, value);
}
void
u.fval = value;
- InterlockedWrite64 (ptr, u.ival);
+ InterlockedWrite64 ((volatile gint64 *)ptr, u.ival);
}
void
u.fval = value;
- InterlockedWrite (ptr, u.ival);
+ InterlockedWrite ((volatile gint32 *)ptr, u.ival);
}
void
void mono_thread_init (MonoThreadStartCB start_cb,
MonoThreadAttachCB attach_cb)
{
- mono_mutex_init_recursive(&threads_mutex);
- mono_mutex_init_recursive(&interlocked_mutex);
- mono_mutex_init_recursive(&joinable_threads_mutex);
+ mono_coop_mutex_init_recursive (&threads_mutex);
+
+ mono_os_mutex_init_recursive(&interlocked_mutex);
+ mono_os_mutex_init_recursive(&joinable_threads_mutex);
background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
g_assert(background_change_event != NULL);
* critical sections can be locked when mono_thread_cleanup is
* called.
*/
- mono_mutex_destroy (&threads_mutex);
- mono_mutex_destroy (&interlocked_mutex);
- mono_mutex_destroy (&delayed_free_table_mutex);
- mono_mutex_destroy (&small_id_mutex);
+ mono_coop_mutex_destroy (&threads_mutex);
+ mono_os_mutex_destroy (&interlocked_mutex);
+ mono_os_mutex_destroy (&delayed_free_table_mutex);
+ mono_os_mutex_destroy (&small_id_mutex);
CloseHandle (background_change_event);
#endif
remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
{
struct wait_data *wait=(struct wait_data *)user;
- gsize self = GetCurrentThreadId ();
- MonoInternalThread *thread = value;
+ MonoNativeThreadId self = mono_native_thread_id_get ();
+ MonoInternalThread *thread = (MonoInternalThread *)value;
HANDLE handle;
if (wait->num >= MAXIMUM_WAIT_OBJECTS)
return FALSE;
/* The finalizer thread is not a background thread */
- if (thread->tid != self && (thread->state & ThreadState_Background) != 0 &&
- !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
-
+ if (!mono_native_thread_id_equals (thread_get_tid (thread), self)
+ && (thread->state & ThreadState_Background) != 0
+ && (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) == 0
+ ) {
handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
if (handle == NULL)
return FALSE;
return TRUE;
}
- return (thread->tid != self && !mono_gc_is_finalizer_internal_thread (thread));
+ return !mono_native_thread_id_equals (thread_get_tid (thread), self)
+ && !mono_gc_is_finalizer_internal_thread (thread);
}
/**
mono_thread_info_yield ();
}
-static void terminate_thread (gpointer key, gpointer value, gpointer user)
-{
- MonoInternalThread *thread=(MonoInternalThread *)value;
-
- if(thread->tid != (gsize)user) {
- /*TerminateThread (thread->handle, -1);*/
- }
-}
-
-void mono_thread_abort_all_other_threads (void)
-{
- gsize self = GetCurrentThreadId ();
-
- mono_threads_lock ();
- THREAD_DEBUG (g_message ("%s: There are %d threads to abort", __func__,
- mono_g_hash_table_size (threads));
- mono_g_hash_table_foreach (threads, print_tids, NULL));
-
- mono_g_hash_table_foreach (threads, terminate_thread, (gpointer)self);
-
- mono_threads_unlock ();
-}
-
static void
collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
{
struct wait_data wait_data;
struct wait_data *wait = &wait_data;
int i;
- gsize self = GetCurrentThreadId ();
+ MonoNativeThreadId self = mono_native_thread_id_get ();
guint32 eventidx = 0;
gboolean starting, finished;
for (i = 0; i < wait->num; ++i) {
MonoInternalThread *thread = wait->threads [i];
- if ((thread->tid == self) || mono_gc_is_finalizer_internal_thread (thread) || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
+ if (mono_native_thread_id_equals (thread_get_tid (thread), self)
+ || mono_gc_is_finalizer_internal_thread (thread)
+ || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)
+ ) {
//CloseHandle (wait->handles [i]);
wait->threads [i] = NULL; /* ignore this thread in next loop */
continue;
starting = FALSE;
mono_threads_unlock ();
if (starting)
- Sleep (100);
+ mono_thread_info_sleep (100, NULL);
else
finished = TRUE;
}
}
}
+typedef struct {
+ MonoInternalThread *thread;
+ MonoStackFrameInfo *frames;
+ int nframes, max_frames;
+ int nthreads, max_threads;
+ MonoInternalThread **threads;
+} ThreadDumpUserData;
+
static gboolean thread_dump_requested;
-static G_GNUC_UNUSED gboolean
-print_stack_frame_to_string (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
+/* This needs to be async safe */
+static gboolean
+collect_frame (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
{
- GString *p = (GString*)data;
- MonoMethod *method = NULL;
- if (frame->type == FRAME_TYPE_MANAGED)
- method = mono_jit_info_get_method (frame->ji);
+ ThreadDumpUserData *ud = (ThreadDumpUserData *)data;
- if (method) {
- gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
- g_string_append_printf (p, " %s\n", location);
- g_free (location);
- } else
- g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
+ if (ud->nframes < ud->max_frames) {
+ memcpy (&ud->frames [ud->nframes], frame, sizeof (MonoStackFrameInfo));
+ ud->nframes ++;
+ }
return FALSE;
}
+/* This needs to be async safe */
static SuspendThreadResult
-print_thread_dump (MonoThreadInfo *info, gpointer ud)
+get_thread_dump (MonoThreadInfo *info, gpointer ud)
+{
+ ThreadDumpUserData *user_data = (ThreadDumpUserData *)ud;
+ MonoInternalThread *thread = user_data->thread;
+
+#if 0
+/* This no longer works with remote unwinding */
+#ifndef HOST_WIN32
+ wapi_desc = wapi_current_thread_desc ();
+ g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
+ free (wapi_desc);
+#endif
+#endif
+
+ if (thread == mono_thread_internal_current ())
+ mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame, NULL, MONO_UNWIND_SIGNAL_SAFE, ud);
+ else
+ mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, ud);
+
+ return MonoResumeThread;
+}
+
+typedef struct {
+ int nthreads, max_threads;
+ MonoInternalThread **threads;
+} CollectThreadsUserData;
+
+static void
+collect_thread (gpointer key, gpointer value, gpointer user)
+{
+ CollectThreadsUserData *ud = (CollectThreadsUserData *)user;
+ MonoInternalThread *thread = (MonoInternalThread *)value;
+
+ if (ud->nthreads < ud->max_threads)
+ ud->threads [ud->nthreads ++] = thread;
+}
+
+/*
+ * Collect running threads into the THREADS array.
+ * THREADS should be an array allocated on the stack.
+ */
+static int
+collect_threads (MonoInternalThread **thread_array, int max_threads)
+{
+ CollectThreadsUserData ud;
+
+ memset (&ud, 0, sizeof (ud));
+ /* This array contains refs, but its on the stack, so its ok */
+ ud.threads = thread_array;
+ ud.max_threads = max_threads;
+
+ mono_threads_lock ();
+ mono_g_hash_table_foreach (threads, collect_thread, &ud);
+ mono_threads_unlock ();
+
+ return ud.nthreads;
+}
+
+static void
+dump_thread (MonoInternalThread *thread, ThreadDumpUserData *ud)
{
- MonoInternalThread *thread = ud;
GString* text = g_string_new (0);
char *name;
GError *error = NULL;
+ int i;
+
+ ud->thread = thread;
+ ud->nframes = 0;
+ /* Collect frames for the thread */
+ if (thread == mono_thread_internal_current ()) {
+ get_thread_dump (mono_thread_info_current (), ud);
+ } else {
+ mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, ud);
+ }
+
+ /*
+ * Do all the non async-safe work outside of get_thread_dump.
+ */
if (thread->name) {
name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
g_assert (!error);
g_string_append_printf (text, "\n\"%s\"", name);
g_free (name);
}
- else if (thread->threadpool_thread)
+ else if (thread->threadpool_thread) {
g_string_append (text, "\n\"<threadpool thread>\"");
- else
+ } else {
g_string_append (text, "\n\"<unnamed thread>\"");
+ }
-#if 0
-/* This no longer works with remote unwinding */
-#ifndef HOST_WIN32
- wapi_desc = wapi_current_thread_desc ();
- g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
- free (wapi_desc);
-#endif
-#endif
+ for (i = 0; i < ud->nframes; ++i) {
+ MonoStackFrameInfo *frame = &ud->frames [i];
+ MonoMethod *method = NULL;
- mono_get_eh_callbacks ()->mono_walk_stack_with_state (print_stack_frame_to_string, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, text);
+ if (frame->type == FRAME_TYPE_MANAGED)
+ method = mono_jit_info_get_method (frame->ji);
+
+ if (method) {
+ gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
+ g_string_append_printf (text, " %s\n", location);
+ g_free (location);
+ } else {
+ g_string_append_printf (text, " at <unknown> <0x%05x>\n", frame->native_offset);
+ }
+ }
fprintf (stdout, "%s", text->str);
g_string_free (text, TRUE);
fflush (stdout);
- return MonoResumeThread;
-}
-
-static void
-dump_thread (gpointer key, gpointer value, gpointer user)
-{
- MonoInternalThread *thread = (MonoInternalThread *)value;
-
- if (thread == mono_thread_internal_current ())
- return;
-
- /*
- FIXME This still can hang if we stop a thread during malloc.
- FIXME This can hang if we suspend on a critical method and the GC kicks in. A fix might be to have function
- that takes a callback and runs it with the target suspended.
- 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 (thread_get_tid (thread), FALSE, print_thread_dump, thread);
}
void
mono_threads_perform_thread_dump (void)
{
+ ThreadDumpUserData ud;
+ MonoInternalThread *thread_array [128];
+ int tindex, nthreads;
+
if (!thread_dump_requested)
return;
printf ("Full thread dump:\n");
- /* We take the loader lock and the root domain lock as to increase our odds of not deadlocking if
- something needs then in the process.
- */
- mono_loader_lock ();
- mono_domain_lock (mono_get_root_domain ());
+ /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
+ nthreads = collect_threads (thread_array, 128);
- mono_threads_lock ();
- mono_g_hash_table_foreach (threads, dump_thread, NULL);
- mono_threads_unlock ();
+ memset (&ud, 0, sizeof (ud));
+ ud.frames = g_new0 (MonoStackFrameInfo, 256);
+ ud.max_frames = 256;
+
+ for (tindex = 0; tindex < nthreads; ++tindex)
+ dump_thread (thread_array [tindex], &ud);
- mono_domain_unlock (mono_get_root_domain ());
- mono_loader_unlock ();
+ g_free (ud.frames);
thread_dump_requested = FALSE;
}
+/* Obtain the thread dump of all threads */
+static void
+mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_frames)
+{
+ ThreadDumpUserData ud;
+ MonoInternalThread *thread_array [128];
+ MonoDomain *domain = mono_domain_get ();
+ MonoDebugSourceLocation *location;
+ int tindex, nthreads;
+
+ *out_threads = NULL;
+ *out_stack_frames = NULL;
+
+ /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
+ nthreads = collect_threads (thread_array, 128);
+
+ memset (&ud, 0, sizeof (ud));
+ ud.frames = g_new0 (MonoStackFrameInfo, 256);
+ ud.max_frames = 256;
+
+ *out_threads = mono_array_new (domain, mono_defaults.thread_class, nthreads);
+ *out_stack_frames = mono_array_new (domain, mono_defaults.array_class, nthreads);
+
+ for (tindex = 0; tindex < nthreads; ++tindex) {
+ MonoInternalThread *thread = thread_array [tindex];
+ MonoArray *thread_frames;
+ int i;
+
+ ud.thread = thread;
+ ud.nframes = 0;
+
+ /* Collect frames for the thread */
+ if (thread == mono_thread_internal_current ()) {
+ get_thread_dump (mono_thread_info_current (), &ud);
+ } else {
+ mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, &ud);
+ }
+
+ mono_array_setref_fast (*out_threads, tindex, mono_thread_current_for_thread (thread));
+
+ thread_frames = mono_array_new (domain, mono_defaults.stack_frame_class, ud.nframes);
+ mono_array_setref_fast (*out_stack_frames, tindex, thread_frames);
+
+ for (i = 0; i < ud.nframes; ++i) {
+ MonoStackFrameInfo *frame = &ud.frames [i];
+ MonoMethod *method = NULL;
+ MonoStackFrame *sf = (MonoStackFrame *)mono_object_new (domain, mono_defaults.stack_frame_class);
+
+ sf->native_offset = frame->native_offset;
+
+ if (frame->type == FRAME_TYPE_MANAGED)
+ method = mono_jit_info_get_method (frame->ji);
+
+ if (method) {
+ sf->method_address = (gsize) frame->ji->code_start;
+
+ MONO_OBJECT_SETREF (sf, method, mono_method_get_object (domain, method, NULL));
+
+ location = mono_debug_lookup_source_location (method, frame->native_offset, domain);
+ if (location) {
+ sf->il_offset = location->il_offset;
+
+ if (location && location->source_file) {
+ MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
+ sf->line = location->row;
+ sf->column = location->column;
+ }
+ mono_debug_free_source_location (location);
+ } else {
+ sf->il_offset = -1;
+ }
+ }
+ mono_array_setref (thread_frames, i, sf);
+ }
+ }
+
+ g_free (ud.frames);
+}
+
/**
* mono_threads_request_thread_dump:
*
static void
ref_stack_destroy (gpointer ptr)
{
- RefStack *rs = ptr;
+ RefStack *rs = (RefStack *)ptr;
if (rs != NULL) {
g_free (rs->refs);
g_assert (rs != NULL);
if (rs->bottom >= rs->allocated) {
- rs->refs = g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
+ rs->refs = (void **)g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
rs->allocated <<= 1;
rs->refs [rs->allocated] = NULL;
}
SPIN_LOCK (thread->lock_thread_id);
if (thread->appdomain_refs == NULL)
thread->appdomain_refs = ref_stack_new (16);
- ref_stack_push (thread->appdomain_refs, domain);
+ ref_stack_push ((RefStack *)thread->appdomain_refs, domain);
SPIN_UNLOCK (thread->lock_thread_id);
}
}
if (thread) {
/* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
SPIN_LOCK (thread->lock_thread_id);
- ref_stack_pop (thread->appdomain_refs);
+ ref_stack_pop ((RefStack *)thread->appdomain_refs);
SPIN_UNLOCK (thread->lock_thread_id);
}
}
{
gboolean res;
SPIN_LOCK (thread->lock_thread_id);
- res = ref_stack_find (thread->appdomain_refs, domain);
+ res = ref_stack_find ((RefStack *)thread->appdomain_refs, domain);
SPIN_UNLOCK (thread->lock_thread_id);
return res;
}
static void
mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
{
- gpointer *static_data = addr;
+ gpointer *static_data = (gpointer *)addr;
for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
- void **ptr = static_data [i];
+ void **ptr = (void **)static_data [i];
if (!ptr)
continue;
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 = (void **)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 void
alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
{
- MonoInternalThread *thread = value;
+ MonoInternalThread *thread = (MonoInternalThread *)value;
guint32 offset = GPOINTER_TO_UINT (user);
mono_alloc_static_data (&(thread->static_data), offset, TRUE);
static void
free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
{
- MonoInternalThread *thread = value;
- OffsetSize *data = user;
+ MonoInternalThread *thread = (MonoInternalThread *)value;
+ OffsetSize *data = (OffsetSize *)user;
int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
char *ptr;
if (!ctx)
return;
- OffsetSize *data = user;
+ OffsetSize *data = (OffsetSize *)user;
int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
char *ptr;
static void
do_free_special (gpointer key, gpointer value, gpointer data)
{
- MonoClassField *field = key;
+ MonoClassField *field = (MonoClassField *)key;
guint32 offset = GPOINTER_TO_UINT (value);
gint32 align;
guint32 size;
static gboolean
last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
{
- MonoJitInfo **dest = data;
+ MonoJitInfo **dest = (MonoJitInfo **)data;
*dest = frame->ji;
return TRUE;
}
static SuspendThreadResult
abort_thread_critical (MonoThreadInfo *info, gpointer ud)
{
- AbortThreadData *data = ud;
+ AbortThreadData *data = (AbortThreadData *)ud;
MonoInternalThread *thread = data->thread;
MonoJitInfo *ji = NULL;
gboolean protected_wrapper;
static SuspendThreadResult
suspend_thread_critical (MonoThreadInfo *info, gpointer ud)
{
- SuspendThreadData *data = ud;
+ SuspendThreadData *data = (SuspendThreadData *)ud;
MonoInternalThread *thread = data->thread;
MonoJitInfo *ji = NULL;
gboolean protected_wrapper;
if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
InterlockedIncrement (&thread_interruption_requested);
if (data->interrupt)
- data->interrupt_token = mono_thread_info_prepare_interrupt (thread->thread_info);
+ data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
if (mono_thread_notify_pending_exc_fn && !running_managed)
/* The JIT will notify the thread about the interruption */
mono_thread_info_end_self_suspend ();
}
-/*This is called with @thread synch_cs held and it must release it*/
-static gboolean
-resume_thread_internal (MonoInternalThread *thread)
-{
- UNLOCK_THREAD (thread);
- /* Awake the thread */
- if (!mono_thread_info_resume (thread_get_tid (thread)))
- return FALSE;
- LOCK_THREAD (thread);
- thread->state &= ~ThreadState_Suspended;
- UNLOCK_THREAD (thread);
- return TRUE;
-}
-
/*
* mono_thread_is_foreign:
mono_bool
mono_thread_is_foreign (MonoThread *thread)
{
- MonoThreadInfo *info = thread->internal_thread->thread_info;
+ MonoThreadInfo *info = (MonoThreadInfo *)thread->internal_thread->thread_info;
return info->runtime_thread == FALSE;
}
}
}
}
+
+void
+ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces)
+{
+ mono_threads_get_thread_dump (out_threads, out_stack_traces);
+}