state->gc_stackdata_size = stackdata_size;
}
+static gpointer
+mono_threads_enter_gc_safe_region_unbalanced_with_info (MonoThreadInfo *info, gpointer *stackdata);
+
gpointer
mono_threads_enter_gc_safe_region (gpointer *stackdata)
+{
+ return mono_threads_enter_gc_safe_region_with_info (mono_thread_info_current_unchecked (), stackdata);
+}
+
+gpointer
+mono_threads_enter_gc_safe_region_with_info (MonoThreadInfo *info, gpointer *stackdata)
{
gpointer cookie;
if (!mono_threads_is_coop_enabled ())
return NULL;
- cookie = mono_threads_enter_gc_safe_region_unbalanced (stackdata);
+ cookie = mono_threads_enter_gc_safe_region_unbalanced_with_info (info, stackdata);
#ifdef ENABLE_CHECKED_BUILD_GC
if (mono_check_mode_enabled (MONO_CHECK_MODE_GC))
gpointer
mono_threads_enter_gc_safe_region_unbalanced (gpointer *stackdata)
{
- MonoThreadInfo *info;
+ return mono_threads_enter_gc_safe_region_unbalanced_with_info (mono_thread_info_current_unchecked (), stackdata);
+}
+static gpointer
+mono_threads_enter_gc_safe_region_unbalanced_with_info (MonoThreadInfo *info, gpointer *stackdata)
+{
if (!mono_threads_is_coop_enabled ())
return NULL;
gpointer
mono_threads_enter_gc_unsafe_region (gpointer *stackdata)
+{
+ return mono_threads_enter_gc_unsafe_region_with_info (mono_thread_info_current_unchecked (), stackdata);
+}
+
+gpointer
+mono_threads_enter_gc_unsafe_region_with_info (THREAD_INFO_TYPE *info, gpointer *stackdata)
{
gpointer cookie;
if (!mono_threads_is_coop_enabled ())
return NULL;
- cookie = mono_threads_enter_gc_unsafe_region_unbalanced (stackdata);
+ cookie = mono_threads_enter_gc_unsafe_region_unbalanced_with_info (info, stackdata);
#ifdef ENABLE_CHECKED_BUILD_GC
if (mono_check_mode_enabled (MONO_CHECK_MODE_GC))
gpointer
mono_threads_enter_gc_unsafe_region_unbalanced (gpointer *stackdata)
{
- MonoThreadInfo *info;
+ return mono_threads_enter_gc_unsafe_region_unbalanced_with_info (mono_thread_info_current_unchecked (), stackdata);
+}
+gpointer
+mono_threads_enter_gc_unsafe_region_unbalanced_with_info (MonoThreadInfo *info, gpointer *stackdata)
+{
if (!mono_threads_is_coop_enabled ())
return NULL;
mono_threads_state_poll ();
}
+/*
+ * The following are used when detaching a thread. We need to pass the MonoThreadInfo*
+ * as a paramater as the thread info TLS key is being destructed, meaning that
+ * mono_thread_info_current_unchecked will return NULL, which would lead to a
+ * runtime assertion error when trying to switch the state of the current thread.
+ */
+
+gpointer
+mono_threads_enter_gc_safe_region_with_info (THREAD_INFO_TYPE *info, gpointer *stackdata);
+
+#define MONO_ENTER_GC_SAFE_WITH_INFO(info) \
+ do { \
+ gpointer __gc_safe_dummy; \
+ gpointer __gc_safe_cookie = mono_threads_enter_gc_safe_region_with_info ((info), &__gc_safe_dummy)
+
+#define MONO_EXIT_GC_SAFE_WITH_INFO MONO_EXIT_GC_SAFE
+
+gpointer
+mono_threads_enter_gc_unsafe_region_with_info (THREAD_INFO_TYPE *info, gpointer *stackdata);
+
+#define MONO_ENTER_GC_UNSAFE_WITH_INFO(info) \
+ do { \
+ gpointer __gc_unsafe_dummy; \
+ gpointer __gc_unsafe_cookie = mono_threads_enter_gc_unsafe_region_with_info ((info), &__gc_unsafe_dummy)
+
+#define MONO_EXIT_GC_UNSAFE_WITH_INFO MONO_EXIT_GC_UNSAFE
+
+gpointer
+mono_threads_enter_gc_unsafe_region_unbalanced_with_info (THREAD_INFO_TYPE *info, gpointer *stackdata);
+
G_END_DECLS
#endif
The GC has to acquire this lock before starting a STW to make sure
a runtime suspend won't make it wronly see a thread in a safepoint
when it is in fact not.
+
+This has to be a naked locking primitive, and not a coop aware one, as
+it needs to be usable when destroying thread_info_key, the TLS key for
+the current MonoThreadInfo. In this case, mono_thread_info_current_unchecked,
+(which is used inside MONO_ENTER_GC_SAFE), would return NULL, leading
+to an assertion error. We then simply switch state manually in
+mono_thread_info_suspend_lock_with_info.
*/
-static MonoCoopSem global_suspend_semaphore;
+static MonoSemType global_suspend_semaphore;
static size_t thread_info_size;
static MonoThreadInfoCallbacks threads_callbacks;
return info;
}
+static void
+mono_thread_info_suspend_lock_with_info (MonoThreadInfo *info);
+
static void
unregister_thread (void *arg)
{
- MonoThreadInfo *info = (MonoThreadInfo *) arg;
- int small_id = info->small_id;
+ gpointer gc_unsafe_stackdata;
+ MonoThreadInfo *info;
+ int small_id;
+
+ info = (MonoThreadInfo *) arg;
g_assert (info);
+ small_id = info->small_id;
+
+ /* We only enter the GC unsafe region, as when exiting this function, the thread
+ * will be detached, and the current MonoThreadInfo* will be destroyed. */
+ mono_threads_enter_gc_unsafe_region_unbalanced_with_info (info, &gc_unsafe_stackdata);
+
THREADS_DEBUG ("unregistering info %p\n", info);
mono_native_tls_set_value (thread_exited_key, GUINT_TO_POINTER (1));
if (threads_callbacks.thread_detach)
threads_callbacks.thread_detach (info);
- mono_thread_info_suspend_lock ();
+ mono_thread_info_suspend_lock_with_info (info);
/*
Now perform the callback that must be done under locks.
unified_suspend_enabled = g_getenv ("MONO_ENABLE_UNIFIED_SUSPEND") != NULL || mono_threads_is_coop_enabled ();
- mono_coop_sem_init (&global_suspend_semaphore, 1);
+ mono_os_sem_init (&global_suspend_semaphore, 1);
mono_os_sem_init (&suspend_semaphore, 0);
mono_lls_init (&thread_list, NULL, HAZARD_FREE_NO_LOCK);
A GC that has safepoints must take this lock as part of its
STW to make sure no unsafe pending suspend is in progress.
*/
+
+static void
+mono_thread_info_suspend_lock_with_info (MonoThreadInfo *info)
+{
+ g_assert (info);
+
+ MONO_ENTER_GC_SAFE_WITH_INFO(info);
+
+ int res = mono_os_sem_wait (&global_suspend_semaphore, MONO_SEM_FLAGS_NONE);
+ g_assert (res != -1);
+
+ MONO_EXIT_GC_SAFE_WITH_INFO;
+}
+
void
mono_thread_info_suspend_lock (void)
{
- int res = mono_coop_sem_wait (&global_suspend_semaphore, MONO_SEM_FLAGS_NONE);
- g_assert (res != -1);
+ mono_thread_info_suspend_lock_with_info (mono_thread_info_current_unchecked ());
}
void
mono_thread_info_suspend_unlock (void)
{
- mono_coop_sem_post (&global_suspend_semaphore);
+ mono_os_sem_post (&global_suspend_semaphore);
}
/*