Skip to content

Commit

Permalink
[runtime] Add a mono_thread_detach_if_exiting () public api function …
Browse files Browse the repository at this point in the history
…which can be called by embedding code to detach the runtime if the code is running from a pthread dtor. Fixes part of #21164.
  • Loading branch information
vargaz committed Aug 22, 2014
1 parent 93e5904 commit 0d839a1
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 1 deletion.
6 changes: 6 additions & 0 deletions mono/metadata/sgen-gc.c
Expand Up @@ -3881,6 +3881,12 @@ sgen_thread_unregister (SgenThreadInfo *p)
binary_protocol_thread_unregister ((gpointer)tid);
SGEN_LOG (3, "unregister thread %p (%p)", p, (gpointer)tid);

#ifndef HAVE_KW_THREAD
mono_native_tls_set_value (thread_info_key, NULL);
#else
sgen_thread_info = NULL;
#endif

if (p->info.runtime_thread)
mono_threads_add_joinable_thread ((gpointer)tid);

Expand Down
21 changes: 21 additions & 0 deletions mono/metadata/threads.c
Expand Up @@ -987,6 +987,27 @@ mono_thread_detach (MonoThread *thread)
mono_thread_detach_internal (thread->internal_thread);
}

/*
* mono_thread_detach_if_exiting:
*
* Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
* This should be used at the end of embedding code which calls into managed code, and which
* can be called from pthread dtors, like dealloc: implementations in objective-c.
*/
void
mono_thread_detach_if_exiting (void)
{
if (mono_thread_info_is_exiting ()) {
MonoInternalThread *thread;

thread = mono_thread_internal_current ();
if (thread) {
mono_thread_detach_internal (thread);
mono_thread_info_detach ();
}
}
}

void
mono_thread_exit ()
{
Expand Down
2 changes: 2 additions & 0 deletions mono/metadata/threads.h
Expand Up @@ -48,6 +48,8 @@ MONO_API void mono_threads_request_thread_dump (void);

MONO_API mono_bool mono_thread_is_foreign (MonoThread *thread);

extern MONO_API void mono_thread_detach_if_exiting (void);

MONO_END_DECLS

#endif /* _MONO_METADATA_THREADS_H_ */
1 change: 1 addition & 0 deletions mono/utils/mono-threads-mach-helper.c
Expand Up @@ -11,6 +11,7 @@

#if defined(__MACH__)

#include <stdio.h>
#include <objc/runtime.h>
#include <objc/message.h>
#include <mono/utils/mono-compiler.h>
Expand Down
43 changes: 42 additions & 1 deletion mono/utils/mono-threads.c
Expand Up @@ -41,7 +41,7 @@ static MonoSemType global_suspend_semaphore;
static size_t thread_info_size;
static MonoThreadInfoCallbacks threads_callbacks;
static MonoThreadInfoRuntimeCallbacks runtime_callbacks;
static MonoNativeTlsKey thread_info_key, small_id_key;
static MonoNativeTlsKey thread_info_key, thread_exited_key, small_id_key;
static MonoLinkedListSet thread_list;
static gboolean disable_new_interrupt = FALSE;
static gboolean mono_threads_inited = FALSE;
Expand Down Expand Up @@ -168,6 +168,8 @@ unregister_thread (void *arg)

THREADS_DEBUG ("unregistering info %p\n", info);

mono_native_tls_set_value (thread_exited_key, GUINT_TO_POINTER (1));

mono_threads_core_unregister (info);

/*
Expand Down Expand Up @@ -206,6 +208,27 @@ unregister_thread (void *arg)
mono_thread_small_id_free (small_id);
}

static void
thread_exited_dtor (void *arg)
{
#if defined(__MACH__)
/*
* Since we use pthread dtors to clean up thread data, if a thread
* is attached to the runtime by another pthread dtor after our dtor
* has ran, it will never be detached, leading to various problems
* since the thread ids etc. will be reused while they are still in
* the threads hashtables etc.
* Dtors are called in a loop until all user tls entries are 0,
* but the loop has a maximum count (4), so if we set the tls
* variable every time, it will remain set when system tls dtors
* are ran. This allows mono_thread_info_is_exiting () to detect
* whenever the thread is exiting, even if it is executed from a
* system tls dtor (i.e. obj-c dealloc methods).
*/
mono_native_tls_set_value (thread_exited_key, GUINT_TO_POINTER (1));
#endif
}

/**
* Removes the current thread from the thread list.
* This must be called from the thread unregister callback and nowhere else.
Expand Down Expand Up @@ -304,6 +327,22 @@ mono_thread_info_detach (void)
}
}

/*
* mono_thread_info_is_exiting:
*
* Return whenever the current thread is exiting, i.e. it is running pthread
* dtors.
*/
gboolean
mono_thread_info_is_exiting (void)
{
#if defined(__MACH__)
if (mono_native_tls_get_value (thread_exited_key) == GUINT_TO_POINTER (1))
return TRUE;
#endif
return FALSE;
}

void
mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t info_size)
{
Expand All @@ -312,8 +351,10 @@ mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t info_size)
thread_info_size = info_size;
#ifdef HOST_WIN32
res = mono_native_tls_alloc (&thread_info_key, NULL);
res = mono_native_tls_alloc (&thread_exited_key, NULL);
#else
res = mono_native_tls_alloc (&thread_info_key, unregister_thread);
res = mono_native_tls_alloc (&thread_exited_key, thread_exited_dtor);
#endif
g_assert (res);

Expand Down
3 changes: 3 additions & 0 deletions mono/utils/mono-threads.h
Expand Up @@ -227,6 +227,9 @@ mono_thread_info_attach (void *baseptr) MONO_INTERNAL;
void
mono_thread_info_detach (void) MONO_INTERNAL;

gboolean
mono_thread_info_is_exiting (void) MONO_INTERNAL;

THREAD_INFO_TYPE *
mono_thread_info_current (void) MONO_INTERNAL;

Expand Down

0 comments on commit 0d839a1

Please sign in to comment.