return offset;
}
+static inline MonoNativeThreadId
+thread_get_tid (MonoInternalThread *thread)
+{
+ /* We store the tid as a guint64 to keep the object layout constant between platforms */
+ return MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
+}
+
/* handle_store() and handle_remove() manage the array of threads that
* still need to be waited for when the main thread exits.
*
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.
+ * This can happen only during shutdown.
+ * The shutting_down flag is not always set, so we can't assert on it.
+ */
if (thread->synch_cs)
LOCK_THREAD (thread);
- else
- g_assert (shutting_down);
thread->state |= ThreadState_Stopped;
thread->state &= ~ThreadState_Background;
*/
mono_profiler_thread_start (tid);
+ /* if the name was set before starting, we didn't invoke the profiler callback */
+ if (internal->name && (internal->flags & MONO_THREAD_FLAG_NAME_SET)) {
+ char *tname = g_utf16_to_utf8 (internal->name, -1, NULL, NULL, NULL);
+ mono_profiler_thread_name (internal->tid, tname);
+ g_free (tname);
+ }
/* start_func is set only for unmanaged start functions */
if (start_func) {
start_func (start_arg);
thread_cleanup (internal);
+ internal->tid = 0;
+
/* Remove the reference to the thread object in the TLS data,
* so the thread object can be finalized. This won't be
* reached if the thread threw an uncaught exception, so those
MonoNativeThreadId tid;
guint32 create_flags;
+ /*
+ * Join joinable threads to prevent running out of threads since the finalizer
+ * thread might be blocked/backlogged.
+ */
+ mono_threads_join_threads ();
+
mono_threads_lock ();
if (shutting_down) {
g_free (start_info);
}
void
-mono_thread_detach (MonoThread *thread)
+mono_thread_detach_internal (MonoInternalThread *thread)
{
g_return_if_fail (thread != NULL);
- THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->internal_thread->tid));
+ THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
- thread_cleanup (thread->internal_thread);
+ thread_cleanup (thread);
SET_CURRENT_OBJECT (NULL);
mono_domain_unset ();
*/
}
+void
+mono_thread_detach (MonoThread *thread)
+{
+ if (thread)
+ mono_thread_detach_internal (thread->internal_thread);
+}
+
void
mono_thread_exit ()
{
}
/*
- * This is called from the finalizer of the internal thread object. Since threads keep a reference to their
- * thread object while running, by the time this function is called, the thread has already exited/detached,
- * i.e. thread_cleanup () has ran.
+ * This is called from the finalizer of the internal thread object.
*/
void
ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this, HANDLE thread)
{
THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
+ /*
+ * Since threads keep a reference to their thread object while running, by the time this function is called,
+ * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
+ * when thread_cleanup () can be called after this.
+ */
if (thread)
CloseHandle (thread);
UNLOCK_THREAD (this_obj);
- if (this_obj->name) {
+ if (this_obj->name && this_obj->tid) {
char *tname = mono_string_to_utf8 (name);
mono_profiler_thread_name (this_obj->tid, tname);
+ mono_thread_info_set_name (thread_get_tid (this_obj), tname);
mono_free (tname);
}
}
return arr;
copy = mono_array_new (domain, mono_defaults.byte_class, arr->max_length);
- mono_gc_memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
+ memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
return copy;
}
continue;
/* Re-calculate ms according to the time passed */
- diff_ms = (mono_100ns_ticks () - start) / 10000;
+ diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
if (diff_ms >= ms) {
ret = WAIT_TIMEOUT;
break;
/* Do this WaitSleepJoin check before creating objects */
mono_thread_current_check_pending_interrupt ();
- numhandles = mono_array_length(mono_handles);
+ /* We fail in managed if the array has more than 64 elements */
+ numhandles = (guint32)mono_array_length(mono_handles);
handles = g_new0(HANDLE, numhandles);
for(i = 0; i < numhandles; i++) {
gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
{
HANDLE handles [MAXIMUM_WAIT_OBJECTS];
- guint32 numhandles;
+ uintptr_t numhandles;
guint32 ret;
guint32 i;
MonoObject *waitHandle;
*/
static void signal_thread_state_change (MonoInternalThread *thread)
{
+#ifndef HOST_WIN32
+ gpointer wait_handle;
+#endif
+
if (thread == mono_thread_internal_current ()) {
/* Do it synchronously */
MonoException *exc = mono_thread_request_interruption (FALSE);
}
#ifdef HOST_WIN32
- QueueUserAPC ((PAPCFUNC)interruption_request_apc, thread->handle, NULL);
+ QueueUserAPC ((PAPCFUNC)interruption_request_apc, thread->handle, (ULONG_PTR)NULL);
#else
- /* fixme: store the state somewhere */
- mono_thread_kill (thread, mono_thread_get_abort_signal ());
-
/*
* This will cause waits to be broken.
* It will also prevent the thread from entering a wait, so if the thread returns
* functions in the io-layer until the signal handler calls QueueUserAPC which will
* make it return.
*/
- wapi_interrupt_thread (thread->handle);
+ wait_handle = wapi_prepare_interrupt_thread (thread->handle);
+
+ /* fixme: store the state somewhere */
+ mono_thread_kill (thread, mono_thread_get_abort_signal ());
+
+ wapi_finish_interrupt_thread (wait_handle);
#endif /* HOST_WIN32 */
}
void mono_thread_cleanup (void)
{
#if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
+ MonoThreadInfo *info;
+
/* The main thread must abandon any held mutexes (particularly
* important for named mutexes as they are shared across
* processes, see bug 74680.) This will happen when the
* thread exits, but if it's not running in a subthread it
* won't exit in time.
*/
- /* Using non-w32 API is a nasty kludge, but I couldn't find
- * anything in the documentation that would let me do this
- * here yet still be safe to call on windows.
- */
- _wapi_thread_signal_self (mono_environment_exitcode_get ());
+ info = mono_thread_info_current ();
+ wapi_thread_handle_set_exited (info->handle, mono_environment_exitcode_get ());
#endif
#if 0
/*
* On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
* it can still run io-layer etc. code. So wait for it to really exit.
+ * FIXME: This won't join threads which are not in the joinable_hash yet.
*/
mono_thread_join ((gpointer)tid);
return;
}
- handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
+ handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
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 = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
+ handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
if (handle == NULL)
return FALSE;
return;
if (wait->num<MAXIMUM_WAIT_OBJECTS) {
- handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
+ handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
if (handle == NULL)
return;
HANDLE handle;
if (wait->num<MAXIMUM_WAIT_OBJECTS) {
- handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
+ handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
if (handle == NULL)
return;
#endif
mono_get_eh_callbacks ()->mono_walk_stack_with_state (print_stack_frame_to_string, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, text);
- mono_thread_info_resume (mono_thread_info_get_tid (info));
+ mono_thread_info_finish_suspend_and_resume (info);
fprintf (stdout, "%s", text->str);
/* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
- HANDLE handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
+ HANDLE handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
if (handle == NULL)
return;
data->wait.handles [data->wait.num] = handle;
static uintptr_t* static_reference_bitmaps [NUM_STATIC_DATA_IDX];
static void
-mark_tls_slots (void *addr, MonoGCMarkFunc mark_func)
+mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
{
int i;
gpointer *static_data = addr;
void ** p = ptr;
while (bmap) {
if ((bmap & 1) && *p) {
- mark_func (p);
+ mark_func (p, gc_data);
}
p++;
bmap >>= 1;
return NULL;
}
+#if SIZEOF_VOID_P == 4
+#define ONE_P 1
+#else
+#define ONE_P 1ll
+#endif
+
static void
update_tls_reference_bitmap (guint32 offset, uintptr_t *bitmap, int numbits)
{
offset /= sizeof (gpointer);
/* offset is now the bitmap offset */
for (i = 0; i < numbits; ++i) {
- if (bitmap [i / sizeof (uintptr_t)] & (1L << (i & (sizeof (uintptr_t) * 8 -1))))
- rb [(offset + i) / (sizeof (uintptr_t) * 8)] |= (1L << ((offset + i) & (sizeof (uintptr_t) * 8 -1)));
+ if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
+ rb [(offset + i) / (sizeof (uintptr_t) * 8)] |= (ONE_P << ((offset + i) & (sizeof (uintptr_t) * 8 -1)));
}
}
if (!thread->static_data || !thread->static_data [idx])
return;
ptr = ((char*) thread->static_data [idx]) + (data->offset & 0xffffff);
- mono_gc_bzero (ptr, data->size);
+ mono_gc_bzero_atomic (ptr, data->size);
}
static void
or similar */
/* Our implementation of this function ignores the func argument */
#ifdef HOST_WIN32
- QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, NULL);
+ QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
#else
- wapi_thread_interrupt_self ();
+ wapi_self_interrupt ();
#endif
return NULL;
}
}
if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (&info->suspend_state)) {
- mono_thread_info_resume (mono_thread_info_get_tid (info));
+ mono_thread_info_finish_suspend_and_resume (info);
return;
}
/*someone is already interrupting it*/
if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1) {
- mono_thread_info_resume (mono_thread_info_get_tid (info));
+ mono_thread_info_finish_suspend_and_resume (info);
return;
}
InterlockedIncrement (&thread_interruption_requested);
/*Set the thread to call */
if (install_async_abort)
mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
- mono_thread_info_resume (mono_thread_info_get_tid (info));
+ mono_thread_info_finish_suspend_and_resume (info);
} else {
- gpointer interrupt_handle;
/*
* This will cause waits to be broken.
* It will also prevent the thread from entering a wait, so if the thread returns
* make it return.
*/
#ifndef HOST_WIN32
+ gpointer interrupt_handle;
interrupt_handle = wapi_prepare_interrupt_thread (thread->handle);
#endif
- mono_thread_info_resume (mono_thread_info_get_tid (info));
+ mono_thread_info_finish_suspend_and_resume (info);
#ifndef HOST_WIN32
wapi_finish_interrupt_thread (interrupt_handle);
#endif
}
static void
-transition_to_suspended (MonoInternalThread *thread)
+transition_to_suspended (MonoInternalThread *thread, MonoThreadInfo *info)
{
if ((thread->state & ThreadState_SuspendRequested) == 0) {
g_assert (0); /*FIXME we should not reach this */
/*Make sure we balance the suspend count.*/
- mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid);
+ if (info)
+ mono_thread_info_finish_suspend_and_resume (info);
} else {
thread->state &= ~ThreadState_SuspendRequested;
thread->state |= ThreadState_Suspended;
- mono_thread_info_finish_suspend ();
+ if (info)
+ mono_thread_info_finish_suspend (info);
}
UNLOCK_THREAD (thread);
}
LOCK_THREAD (thread);
if (thread == mono_thread_internal_current ()) {
- transition_to_suspended (thread);
+ transition_to_suspended (thread, NULL);
mono_thread_info_self_suspend ();
} else {
MonoThreadInfo *info;
running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
if (running_managed && !protected_wrapper) {
- transition_to_suspended (thread);
+ transition_to_suspended (thread, info);
} else {
+#ifndef HOST_WIN32
gpointer interrupt_handle;
+#endif
if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
InterlockedIncrement (&thread_interruption_requested);
if (interrupt)
interrupt_handle = wapi_prepare_interrupt_thread (thread->handle);
#endif
- mono_thread_info_resume (mono_thread_info_get_tid (info));
+ mono_thread_info_finish_suspend_and_resume (info);
#ifndef HOST_WIN32
if (interrupt)
wapi_finish_interrupt_thread (interrupt_handle);
return;
}
- transition_to_suspended (thread);
+ transition_to_suspended (thread, NULL);
mono_thread_info_self_suspend ();
}
{
#ifndef HOST_WIN32
pthread_t thread;
+ gboolean found = FALSE;
joinable_threads_lock ();
if (!joinable_threads)
if (g_hash_table_lookup (joinable_threads, tid)) {
g_hash_table_remove (joinable_threads, tid);
joinable_thread_count --;
+ found = TRUE;
}
joinable_threads_unlock ();
+ if (!found)
+ return;
thread = (pthread_t)tid;
pthread_join (thread, NULL);
#endif