From dfc8deaa7ff257ba53f42d1dd4eda594531298f9 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Thu, 22 Oct 2015 21:01:10 +0100 Subject: [PATCH 1/3] [thread] Fix race between async suspend and compensation The race only happens on Posix with unified suspend. The chain of event is the following: - T1 suspend the world (calls `sgen_unified_suspend_stop_world`) - T2 is async suspended - T2 execute suspend_signal_handler: - T2 finish async suspend - T2->suspend_can_continue is set to FALSE as the thread is detaching - T2 notify T1 via `mono_threads_notify_initiator_of_suspend` - T2 is yielded (via the OS scheduler, or forced via a `sleep`) - T1 returns from `mono_threads_wait_pending_operations` - T1 does its stuff - T1 restart the world - T1 (or any another thread, except for T2) suspend the world (it does not necessarily uses `sgen_unified_suspend_stop_world`) - T2 is async suspended: incrementation of T2->suspend_count to 2, but it is not signalled because it is already in ASYNC_SUSPENDED state - T2 wakes up (for any reason) and execute compensation <- ERROR: suspend_count != 1 This race can happen because when async suspending, we notify the suspendor before executing the compensation, in this case for a thread which is detaching. By simply post-ponning the notification, just after the compensation, we eliminate this race. --- mono/utils/mono-threads-posix-signals.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/mono/utils/mono-threads-posix-signals.c b/mono/utils/mono-threads-posix-signals.c index 1dfdd38b5711..d6b638829288 100644 --- a/mono/utils/mono-threads-posix-signals.c +++ b/mono/utils/mono-threads-posix-signals.c @@ -178,7 +178,6 @@ suspend_signal_handler (int _dummy, siginfo_t *info, void *context) /* thread_state_init_from_sigctx return FALSE if the current thread is detaching and suspend can't continue. */ current->suspend_can_continue = ret; - /* Block the restart signal. We need to block the restart signal while posting to the suspend_ack semaphore or we race to sigsuspend, @@ -186,19 +185,23 @@ suspend_signal_handler (int _dummy, siginfo_t *info, void *context) */ pthread_sigmask (SIG_BLOCK, &suspend_ack_signal_mask, NULL); - /* We're done suspending */ - mono_threads_notify_initiator_of_suspend (current); - /* This thread is doomed, all we can do is give up and let the suspender recover. */ if (!ret) { THREADS_SUSPEND_DEBUG ("\tThread is dying, failed to capture state %p\n", current); mono_threads_transition_async_suspend_compensation (current); + + /* We're done suspending */ + mono_threads_notify_initiator_of_suspend (current); + /* Unblock the restart signal. */ pthread_sigmask (SIG_UNBLOCK, &suspend_ack_signal_mask, NULL); goto done; } + /* We're done suspending */ + mono_threads_notify_initiator_of_suspend (current); + do { current->signal = 0; sigsuspend (&suspend_signal_mask); From e17fb55862593059fd10c6ff4d47d57b84a0201e Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Wed, 21 Oct 2015 16:49:00 +0100 Subject: [PATCH 2/3] [sgen] Remove sgen specific suspend code --- mono/metadata/Makefile.am | 4 - mono/metadata/sgen-client-mono.h | 5 - mono/metadata/sgen-mono.c | 20 +- mono/metadata/sgen-os-coop.c | 81 ------ mono/metadata/sgen-os-mach.c | 159 ---------- mono/metadata/sgen-os-posix.c | 274 ------------------ mono/metadata/sgen-os-win32.c | 160 ---------- mono/metadata/sgen-stw.c | 126 +------- mono/utils/Makefile.am | 1 - mono/utils/mono-threads-posix-abort-syscall.c | 1 - mono/utils/mono-threads-posix-signals.c | 71 ++--- mono/utils/mono-threads-posix-signals.h | 31 -- mono/utils/mono-threads-posix.c | 1 - mono/utils/mono-threads-state-machine.c | 3 +- mono/utils/mono-threads.c | 9 - mono/utils/mono-threads.h | 24 +- msvc/libmonoutils.vcxproj | 1 - 17 files changed, 65 insertions(+), 906 deletions(-) delete mode 100644 mono/metadata/sgen-os-coop.c delete mode 100644 mono/metadata/sgen-os-mach.c delete mode 100644 mono/metadata/sgen-os-posix.c delete mode 100644 mono/metadata/sgen-os-win32.c delete mode 100644 mono/utils/mono-threads-posix-signals.h diff --git a/mono/metadata/Makefile.am b/mono/metadata/Makefile.am index d0e6fc2fa576..2ba9d66cce84 100644 --- a/mono/metadata/Makefile.am +++ b/mono/metadata/Makefile.am @@ -231,10 +231,6 @@ boehm_sources = \ boehm-gc.c sgen_sources = \ - sgen-os-posix.c \ - sgen-os-mach.c \ - sgen-os-win32.c \ - sgen-os-coop.c \ sgen-bridge.c \ sgen-bridge.h \ sgen-bridge-internal.h \ diff --git a/mono/metadata/sgen-client-mono.h b/mono/metadata/sgen-client-mono.h index e986ae0c2ed5..e190e8dd41e1 100644 --- a/mono/metadata/sgen-client-mono.h +++ b/mono/metadata/sgen-client-mono.h @@ -655,11 +655,6 @@ sgen_client_binary_protocol_gray_dequeue (gpointer queue, gpointer cursor, gpoin { } -int sgen_thread_handshake (BOOL suspend); -gboolean sgen_suspend_thread (SgenThreadInfo *info); -gboolean sgen_resume_thread (SgenThreadInfo *info); -void sgen_wait_for_suspend_ack (int count); - #ifdef HAVE_KW_THREAD extern __thread SgenThreadInfo *sgen_thread_info; #define TLAB_ACCESS_INIT diff --git a/mono/metadata/sgen-mono.c b/mono/metadata/sgen-mono.c index bd94f85cc4a0..a599cf921f24 100644 --- a/mono/metadata/sgen-mono.c +++ b/mono/metadata/sgen-mono.c @@ -36,6 +36,7 @@ #include "metadata/gc-internal.h" #include "utils/mono-memory-model.h" #include "utils/mono-logger-internal.h" +#include "utils/mono-threads.h" #ifdef HEAVY_STATISTICS static guint64 stat_wbarrier_set_arrayref = 0; @@ -190,6 +191,18 @@ mono_gc_wbarrier_value_copy_bitmap (gpointer _dest, gpointer _src, int size, uns sgen_wbarrier_value_copy_bitmap (_dest, _src, size, bitmap); } +int +mono_gc_get_suspend_signal (void) +{ + return mono_threads_posix_get_suspend_signal (); +} + +int +mono_gc_get_restart_signal (void) +{ + return mono_threads_posix_get_restart_signal (); +} + static MonoMethod *write_barrier_conc_method; static MonoMethod *write_barrier_noconc_method; @@ -2864,13 +2877,6 @@ sgen_client_init (void) } #endif - /* - * This needs to happen before any internal allocations because - * it inits the small id which is required for hazard pointer - * operations. - */ - sgen_os_init (); - mono_gc_register_thread (&dummy); } diff --git a/mono/metadata/sgen-os-coop.c b/mono/metadata/sgen-os-coop.c deleted file mode 100644 index 165c0d4a4533..000000000000 --- a/mono/metadata/sgen-os-coop.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * sgen-os-coop.c: SGen Cooperative backend support. - * - * Author: - * João Matos (joao.matos@xamarin.com) - * Copyright (C) 2015 Xamarin Inc - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License 2.0 as published by the Free Software Foundation; - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License 2.0 along with this library; if not, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "config.h" -#ifdef HAVE_SGEN_GC - - -#include -#include "sgen/sgen-gc.h" -#include "sgen/sgen-archdep.h" -#include "sgen/sgen-protocol.h" -#include "metadata/object-internals.h" -#include "metadata/gc-internal.h" - - -#if defined(USE_COOP_GC) - -gboolean -sgen_resume_thread (SgenThreadInfo *info) -{ - g_error ("FIXME"); - return FALSE; -} - -gboolean -sgen_suspend_thread (SgenThreadInfo *info) -{ - g_error ("FIXME"); - return FALSE; -} - -void -sgen_wait_for_suspend_ack (int count) -{ -} - -/* LOCKING: assumes the GC lock is held */ -int -sgen_thread_handshake (BOOL suspend) -{ - g_error ("FIXME"); - return 0; -} - -void -sgen_os_init (void) -{ -} - -int -mono_gc_get_suspend_signal (void) -{ - return -1; -} - -int -mono_gc_get_restart_signal (void) -{ - return -1; -} - -#endif -#endif \ No newline at end of file diff --git a/mono/metadata/sgen-os-mach.c b/mono/metadata/sgen-os-mach.c deleted file mode 100644 index 46d30d81c4d6..000000000000 --- a/mono/metadata/sgen-os-mach.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * sgen-os-mach.c: Mach-OS support. - * - * Author: - * Paolo Molaro (lupus@ximian.com) - * Mark Probst (mprobst@novell.com) - * Geoff Norton (gnorton@novell.com) - * - * Copyright 2010 Novell, Inc (http://www.novell.com) - * Copyright (C) 2012 Xamarin Inc - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License 2.0 as published by the Free Software Foundation; - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License 2.0 along with this library; if not, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "config.h" -#ifdef HAVE_SGEN_GC - - -#include -#include "sgen/sgen-gc.h" -#include "sgen/sgen-archdep.h" -#include "sgen/sgen-protocol.h" -#include "sgen/sgen-thread-pool.h" -#include "metadata/object-internals.h" -#include "metadata/gc-internal.h" - -#if defined(__MACH__) -#include "utils/mach-support.h" -#endif - -#if defined(__MACH__) && MONO_MACH_ARCH_SUPPORTED - -#if !defined(USE_COOP_GC) -gboolean -sgen_resume_thread (SgenThreadInfo *info) -{ - return thread_resume (info->client_info.info.native_handle) == KERN_SUCCESS; -} - -gboolean -sgen_suspend_thread (SgenThreadInfo *info) -{ - mach_msg_type_number_t num_state; - thread_state_t state; - kern_return_t ret; - ucontext_t ctx; - mcontext_t mctx; - - gpointer stack_start; - - state = (thread_state_t) alloca (mono_mach_arch_get_thread_state_size ()); - mctx = (mcontext_t) alloca (mono_mach_arch_get_mcontext_size ()); - - ret = thread_suspend (info->client_info.info.native_handle); - if (ret != KERN_SUCCESS) - return FALSE; - - ret = mono_mach_arch_get_thread_state (info->client_info.info.native_handle, state, &num_state); - if (ret != KERN_SUCCESS) - return FALSE; - - mono_mach_arch_thread_state_to_mcontext (state, mctx); - ctx.uc_mcontext = mctx; - - info->client_info.stopped_domain = mono_thread_info_tls_get (info, TLS_KEY_DOMAIN); - info->client_info.stopped_ip = (gpointer) mono_mach_arch_get_ip (state); - info->client_info.stack_start = NULL; - stack_start = (char*) mono_mach_arch_get_sp (state) - REDZONE_SIZE; - /* If stack_start is not within the limits, then don't set it in info and we will be restarted. */ - if (stack_start >= info->client_info.stack_start_limit && stack_start <= info->client_info.stack_end) { - info->client_info.stack_start = stack_start; - -#ifdef USE_MONO_CTX - mono_sigctx_to_monoctx (&ctx, &info->client_info.ctx); -#else - ARCH_COPY_SIGCTX_REGS (&info->client_info.regs, &ctx); -#endif - } else { - g_assert (!info->client_info.stack_start); - } - - /* Notify the JIT */ - if (mono_gc_get_gc_callbacks ()->thread_suspend_func) - mono_gc_get_gc_callbacks ()->thread_suspend_func (info->client_info.runtime_data, &ctx, NULL); - - SGEN_LOG (2, "thread %p stopped at %p stack_start=%p", (void*)(gsize)info->client_info.info.native_handle, info->client_info.stopped_ip, info->client_info.stack_start); - binary_protocol_thread_suspend ((gpointer)mono_thread_info_get_tid (info), info->client_info.stopped_ip); - - return TRUE; -} - -void -sgen_wait_for_suspend_ack (int count) -{ - /* mach thread_resume is synchronous so we dont need to wait for them */ -} - -/* LOCKING: assumes the GC lock is held */ -int -sgen_thread_handshake (BOOL suspend) -{ - SgenThreadInfo *cur_thread = mono_thread_info_current (); - kern_return_t ret; - SgenThreadInfo *info; - - int count = 0; - - cur_thread->client_info.suspend_done = TRUE; - FOREACH_THREAD_SAFE (info) { - if (info == cur_thread || sgen_thread_pool_is_thread_pool_thread (mono_thread_info_get_tid (info))) - continue; - - info->client_info.suspend_done = FALSE; - if (info->client_info.gc_disabled) - continue; - - if (suspend) { - if (!sgen_suspend_thread (info)) - continue; - } else { - ret = thread_resume (info->client_info.info.native_handle); - if (ret != KERN_SUCCESS) - continue; - } - count ++; - } END_FOREACH_THREAD_SAFE - return count; -} - -void -sgen_os_init (void) -{ -} - -int -mono_gc_get_suspend_signal (void) -{ - return -1; -} - -int -mono_gc_get_restart_signal (void) -{ - return -1; -} -#endif -#endif -#endif diff --git a/mono/metadata/sgen-os-posix.c b/mono/metadata/sgen-os-posix.c deleted file mode 100644 index a45d6be1d9c4..000000000000 --- a/mono/metadata/sgen-os-posix.c +++ /dev/null @@ -1,274 +0,0 @@ -/* - * sgen-os-posix.c: Posix support. - * - * Author: - * Paolo Molaro (lupus@ximian.com) - * Mark Probst (mprobst@novell.com) - * Geoff Norton (gnorton@novell.com) - * - * Copyright 2010 Novell, Inc (http://www.novell.com) - * Copyright (C) 2012 Xamarin Inc - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License 2.0 as published by the Free Software Foundation; - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License 2.0 along with this library; if not, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "config.h" - -#if defined(HAVE_SGEN_GC) && !defined(USE_COOP_GC) -#if !defined(__MACH__) && !MONO_MACH_ARCH_SUPPORTED && defined(HAVE_PTHREAD_KILL) - -#include -#include -#include "sgen/sgen-gc.h" -#include "metadata/gc-internal.h" -#include "sgen/sgen-archdep.h" -#include "metadata/object-internals.h" -#include "utils/mono-signal-handler.h" - -#if defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) -const static int suspend_signal_num = SIGXFSZ; -#else -const static int suspend_signal_num = SIGPWR; -#endif -const static int restart_signal_num = SIGXCPU; - -static SgenSemaphore suspend_ack_semaphore; -static SgenSemaphore *suspend_ack_semaphore_ptr; - -static sigset_t suspend_signal_mask; -static sigset_t suspend_ack_signal_mask; - -static void -suspend_thread (SgenThreadInfo *info, void *context) -{ - int stop_count; -#ifndef USE_MONO_CTX - gpointer regs [ARCH_NUM_REGS]; -#endif - MonoContext ctx; - gpointer stack_start; - - info->client_info.stopped_domain = mono_domain_get (); - info->client_info.signal = 0; - stop_count = sgen_global_stop_count; - /* duplicate signal */ - if (0 && info->client_info.stop_count == stop_count) - return; - -#ifdef USE_MONO_CTX - if (context) { - mono_sigctx_to_monoctx (context, &ctx); - info->client_info.stopped_ip = MONO_CONTEXT_GET_IP (&ctx); - stack_start = (((guint8 *) MONO_CONTEXT_GET_SP (&ctx)) - REDZONE_SIZE); - } else { - info->client_info.stopped_ip = NULL; - stack_start = NULL; - } -#else - info->client_info.stopped_ip = context ? (gpointer) ARCH_SIGCTX_IP (context) : NULL; - stack_start = context ? (char*) ARCH_SIGCTX_SP (context) - REDZONE_SIZE : NULL; -#endif - - /* If stack_start is not within the limits, then don't set it - in info and we will be restarted. */ - if (stack_start >= info->client_info.stack_start_limit && stack_start <= info->client_info.stack_end) { - info->client_info.stack_start = stack_start; - -#ifdef USE_MONO_CTX - if (context) { - memcpy (&info->client_info.ctx, &ctx, sizeof (MonoContext)); - } else { - memset (&info->client_info.ctx, 0, sizeof (MonoContext)); - } -#else - if (context) { - ARCH_COPY_SIGCTX_REGS (regs, context); - memcpy (&info->client_info.regs, regs, sizeof (info->client_info.regs)); - } else { - memset (&info->client_info.regs, 0, sizeof (info->client_info.regs)); - } -#endif - } else { - g_assert (!info->client_info.stack_start); - } - - /* Notify the JIT */ - if (mono_gc_get_gc_callbacks ()->thread_suspend_func) - mono_gc_get_gc_callbacks ()->thread_suspend_func (info->client_info.runtime_data, context, NULL); - - SGEN_LOG (4, "Posting suspend_ack_semaphore for suspend from %p %p", info, (gpointer)mono_native_thread_id_get ()); - - /* - Block the restart signal. - We need to block the restart signal while posting to the suspend_ack semaphore or we race to sigsuspend, - which might miss the signal and get stuck. - */ - pthread_sigmask (SIG_BLOCK, &suspend_ack_signal_mask, NULL); - - /* notify the waiting thread */ - SGEN_SEMAPHORE_POST (suspend_ack_semaphore_ptr); - info->client_info.stop_count = stop_count; - - /* wait until we receive the restart signal */ - do { - info->client_info.signal = 0; - sigsuspend (&suspend_signal_mask); - } while (info->client_info.signal != restart_signal_num); - - /* Unblock the restart signal. */ - pthread_sigmask (SIG_UNBLOCK, &suspend_ack_signal_mask, NULL); - - SGEN_LOG (4, "Posting suspend_ack_semaphore for resume from %p %p\n", info, (gpointer)mono_native_thread_id_get ()); - /* notify the waiting thread */ - SGEN_SEMAPHORE_POST (suspend_ack_semaphore_ptr); -} - -/* LOCKING: assumes the GC lock is held (by the stopping thread) */ -MONO_SIG_HANDLER_FUNC (static, suspend_handler) -{ - /* - * The suspend signal handler potentially uses syscalls that - * can set errno, and it calls functions that use the hazard - * pointer machinery. Since we're interrupting other code we - * must restore those to the values they had when we - * interrupted. - */ - SgenThreadInfo *info; - int old_errno = errno; - int hp_save_index = mono_hazard_pointer_save_for_signal_handler (); - MONO_SIG_HANDLER_GET_CONTEXT; - - info = mono_thread_info_current (); - suspend_thread (info, ctx); - - mono_hazard_pointer_restore_for_signal_handler (hp_save_index); - errno = old_errno; -} - -MONO_SIG_HANDLER_FUNC (static, restart_handler) -{ - SgenThreadInfo *info; - int old_errno = errno; - - info = mono_thread_info_current (); - info->client_info.signal = restart_signal_num; - SGEN_LOG (4, "Restart handler in %p %p", info, (gpointer)mono_native_thread_id_get ()); - errno = old_errno; -} - -gboolean -sgen_resume_thread (SgenThreadInfo *info) -{ - return mono_threads_pthread_kill (info, restart_signal_num) == 0; -} - -gboolean -sgen_suspend_thread (SgenThreadInfo *info) -{ - return mono_threads_pthread_kill (info, suspend_signal_num) == 0; -} - -void -sgen_wait_for_suspend_ack (int count) -{ - int i, result; - - for (i = 0; i < count; ++i) { - while ((result = SGEN_SEMAPHORE_WAIT (suspend_ack_semaphore_ptr)) != 0) { - if (errno != EINTR) { - g_error ("SGEN_SEMAPHORE_WAIT FAILED with %d errno %d (%s)", result, errno, strerror (errno)); - } - } - } -} - -int -sgen_thread_handshake (BOOL suspend) -{ - int count, result; - SgenThreadInfo *info; - int signum = suspend ? suspend_signal_num : restart_signal_num; - - MonoNativeThreadId me = mono_native_thread_id_get (); - - count = 0; - mono_thread_info_current ()->client_info.suspend_done = TRUE; - FOREACH_THREAD_SAFE (info) { - if (mono_native_thread_id_equals (mono_thread_info_get_tid (info), me)) { - continue; - } - info->client_info.suspend_done = FALSE; - if (info->client_info.gc_disabled) - continue; - /*if (signum == suspend_signal_num && info->stop_count == global_stop_count) - continue;*/ - result = mono_threads_pthread_kill (info, signum); - if (result == 0) { - count++; - } else { - info->client_info.skip = 1; - } - } END_FOREACH_THREAD_SAFE - - sgen_wait_for_suspend_ack (count); - - SGEN_LOG (4, "%s handshake for %d threads\n", suspend ? "suspend" : "resume", count); - - return count; -} - -void -sgen_os_init (void) -{ - struct sigaction sinfo; - - if (mono_thread_info_unified_management_enabled ()) - return; - - suspend_ack_semaphore_ptr = &suspend_ack_semaphore; - SGEN_SEMAPHORE_INIT (&suspend_ack_semaphore, 0); - - sigfillset (&sinfo.sa_mask); - sinfo.sa_flags = SA_RESTART | SA_SIGINFO; - sinfo.sa_sigaction = suspend_handler; - if (sigaction (suspend_signal_num, &sinfo, NULL) != 0) { - g_error ("failed sigaction"); - } - - sinfo.sa_handler = (void*) restart_handler; - if (sigaction (restart_signal_num, &sinfo, NULL) != 0) { - g_error ("failed sigaction"); - } - - sigfillset (&suspend_signal_mask); - sigdelset (&suspend_signal_mask, restart_signal_num); - - sigemptyset (&suspend_ack_signal_mask); - sigaddset (&suspend_ack_signal_mask, restart_signal_num); - -} - -int -mono_gc_get_suspend_signal (void) -{ - return suspend_signal_num; -} - -int -mono_gc_get_restart_signal (void) -{ - return restart_signal_num; -} -#endif -#endif diff --git a/mono/metadata/sgen-os-win32.c b/mono/metadata/sgen-os-win32.c deleted file mode 100644 index 3145a5e35353..000000000000 --- a/mono/metadata/sgen-os-win32.c +++ /dev/null @@ -1,160 +0,0 @@ -#include "config.h" - -#if defined(HAVE_SGEN_GC) && defined(HOST_WIN32) - -#include "io-layer/io-layer.h" - -#include "sgen/sgen-gc.h" -#include "metadata/gc-internal.h" - -gboolean -sgen_resume_thread (SgenThreadInfo *info) -{ - DWORD id = mono_thread_info_get_tid (info); - HANDLE handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id); - DWORD result; - - g_assert (handle); - - result = ResumeThread (handle); - g_assert (result != (DWORD)-1); - - CloseHandle (handle); - - return result != (DWORD)-1; -} - -gboolean -sgen_suspend_thread (SgenThreadInfo *info) -{ - DWORD id = mono_thread_info_get_tid (info); - HANDLE handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id); - CONTEXT context; - DWORD result; - - g_assert (id != GetCurrentThreadId ()); - - g_assert (handle); - - result = SuspendThread (handle); - if (result == (DWORD)-1) { - fprintf (stderr, "could not suspend thread %x (handle %p): %d\n", id, handle, GetLastError ()); fflush (stderr); - CloseHandle (handle); - return FALSE; - } - - context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL; - - if (!GetThreadContext (handle, &context)) { - g_assert_not_reached (); - ResumeThread (handle); - CloseHandle (handle); - return FALSE; - } - - g_assert (context.ContextFlags & CONTEXT_INTEGER); - g_assert (context.ContextFlags & CONTEXT_CONTROL); - - CloseHandle (handle); - -#if !defined(MONO_CROSS_COMPILE) -#ifdef USE_MONO_CTX - memset (&info->client_info.ctx, 0, sizeof (MonoContext)); -#ifdef TARGET_AMD64 - info->client_info.ctx.gregs[AMD64_RIP] = context.Rip; - info->client_info.ctx.gregs[AMD64_RAX] = context.Rax; - info->client_info.ctx.gregs[AMD64_RCX] = context.Rcx; - info->client_info.ctx.gregs[AMD64_RDX] = context.Rdx; - info->client_info.ctx.gregs[AMD64_RBX] = context.Rbx; - info->client_info.ctx.gregs[AMD64_RSP] = context.Rsp; - info->client_info.ctx.gregs[AMD64_RBP] = context.Rbp; - info->client_info.ctx.gregs[AMD64_RSI] = context.Rsi; - info->client_info.ctx.gregs[AMD64_RDI] = context.Rdi; - info->client_info.ctx.gregs[AMD64_R8] = context.R8; - info->client_info.ctx.gregs[AMD64_R9] = context.R9; - info->client_info.ctx.gregs[AMD64_R10] = context.R10; - info->client_info.ctx.gregs[AMD64_R11] = context.R11; - info->client_info.ctx.gregs[AMD64_R12] = context.R12; - info->client_info.ctx.gregs[AMD64_R13] = context.R13; - info->client_info.ctx.gregs[AMD64_R14] = context.R14; - info->client_info.ctx.gregs[AMD64_R15] = context.R15; - info->client_info.stopped_ip = info->client_info.ctx.gregs[AMD64_RIP]; - info->client_info.stack_start = (char*)info->client_info.ctx.gregs[AMD64_RSP] - REDZONE_SIZE; -#else - info->client_info.ctx.edi = context.Edi; - info->client_info.ctx.esi = context.Esi; - info->client_info.ctx.ebx = context.Ebx; - info->client_info.ctx.edx = context.Edx; - info->client_info.ctx.ecx = context.Ecx; - info->client_info.ctx.eax = context.Eax; - info->client_info.ctx.ebp = context.Ebp; - info->client_info.ctx.esp = context.Esp; - info->client_info.stopped_ip = (gpointer)context.Eip; - info->client_info.stack_start = (char*)context.Esp - REDZONE_SIZE; -#endif - -#else - info->client_info.regs [0] = context.Edi; - info->client_info.regs [1] = context.Esi; - info->client_info.regs [2] = context.Ebx; - info->client_info.regs [3] = context.Edx; - info->client_info.regs [4] = context.Ecx; - info->client_info.regs [5] = context.Eax; - info->client_info.regs [6] = context.Ebp; - info->client_info.regs [7] = context.Esp; - info->client_info.stopped_ip = (gpointer)context.Eip; - info->client_info.stack_start = (char*)context.Esp - REDZONE_SIZE; -#endif -#endif - - /* Notify the JIT */ - if (mono_gc_get_gc_callbacks ()->thread_suspend_func) - mono_gc_get_gc_callbacks ()->thread_suspend_func (info->client_info.runtime_data, NULL, NULL); - - return TRUE; -} - -void -sgen_wait_for_suspend_ack (int count) -{ - /* Win32 suspend/resume is synchronous, so we don't need to wait for anything */ -} - -int -sgen_thread_handshake (BOOL suspend) -{ - SgenThreadInfo *info; - SgenThreadInfo *current = mono_thread_info_current (); - int count = 0; - - current->client_info.suspend_done = TRUE; - FOREACH_THREAD_SAFE (info) { - if (info == current) - continue; - info->client_info.suspend_done = FALSE; - if (info->client_info.gc_disabled) - continue; - if (suspend) { - if (!sgen_suspend_thread (info)) - continue; - } else { - if (!sgen_resume_thread (info)) - continue; - } - ++count; - } END_FOREACH_THREAD_SAFE - return count; -} - -void -sgen_os_init (void) -{ -} - -int -mono_gc_get_suspend_signal (void) -{ - return -1; -} - -#endif diff --git a/mono/metadata/sgen-stw.c b/mono/metadata/sgen-stw.c index 17d86487cb3f..18e552294d07 100644 --- a/mono/metadata/sgen-stw.c +++ b/mono/metadata/sgen-stw.c @@ -35,6 +35,7 @@ #include "sgen/sgen-client.h" #include "metadata/sgen-bridge-internal.h" #include "metadata/gc-internal.h" +#include "utils/mono-threads.h" #define TV_DECLARE SGEN_TV_DECLARE #define TV_GETTIME SGEN_TV_GETTIME @@ -68,7 +69,7 @@ update_current_thread_stack (void *start) void *reg_ptr = cur_thread_regs; #endif SgenThreadInfo *info = mono_thread_info_current (); - + info->client_info.stack_start = align_pointer (&stack_guard); g_assert (info->client_info.stack_start >= info->client_info.stack_start_limit && info->client_info.stack_start < info->client_info.stack_end); #ifdef USE_MONO_CTX @@ -84,107 +85,6 @@ update_current_thread_stack (void *start) #endif } -static gboolean -is_ip_in_managed_allocator (MonoDomain *domain, gpointer ip) -{ - MonoJitInfo *ji; - - if (!mono_thread_internal_current ()) - /* Happens during thread attach */ - return FALSE; - - if (!ip || !domain) - return FALSE; - if (!sgen_has_critical_method ()) - return FALSE; - - /* - * mono_jit_info_table_find is not async safe since it calls into the AOT runtime to load information for - * missing methods (#13951). To work around this, we disable the AOT fallback. For this to work, the JIT needs - * to register the jit info for all GC critical methods after they are JITted/loaded. - */ - ji = mono_jit_info_table_find_internal (domain, ip, FALSE, FALSE); - if (!ji) - return FALSE; - - return sgen_is_critical_method (mono_jit_info_get_method (ji)); -} - -static int -restart_threads_until_none_in_managed_allocator (void) -{ - SgenThreadInfo *info; - int num_threads_died = 0; - int sleep_duration = -1; - - for (;;) { - int restart_count = 0, restarted_count = 0; - /* restart all threads that stopped in the - allocator */ - FOREACH_THREAD_SAFE (info) { - gboolean result; - if (info->client_info.skip || info->client_info.gc_disabled || info->client_info.suspend_done) - continue; - if (mono_thread_info_is_live (info) && - (!info->client_info.stack_start || info->client_info.in_critical_region || info->client_info.info.inside_critical_region || - is_ip_in_managed_allocator (info->client_info.stopped_domain, info->client_info.stopped_ip))) { - binary_protocol_thread_restart ((gpointer)mono_thread_info_get_tid (info)); - SGEN_LOG (3, "thread %p resumed.", (void*) (size_t) info->client_info.info.native_handle); - result = sgen_resume_thread (info); - if (result) { - ++restart_count; - } else { - info->client_info.skip = 1; - } - } else { - /* we set the stopped_ip to - NULL for threads which - we're not restarting so - that we can easily identify - the others */ - info->client_info.stopped_ip = NULL; - info->client_info.stopped_domain = NULL; - info->client_info.suspend_done = TRUE; - } - } END_FOREACH_THREAD_SAFE - /* if no threads were restarted, we're done */ - if (restart_count == 0) - break; - - /* wait for the threads to signal their restart */ - sgen_wait_for_suspend_ack (restart_count); - - if (sleep_duration < 0) { - mono_thread_info_yield (); - sleep_duration = 0; - } else { - g_usleep (sleep_duration); - sleep_duration += 10; - } - - /* stop them again */ - FOREACH_THREAD (info) { - gboolean result; - if (info->client_info.skip || info->client_info.stopped_ip == NULL) - continue; - result = sgen_suspend_thread (info); - - if (result) { - ++restarted_count; - } else { - info->client_info.skip = 1; - } - } END_FOREACH_THREAD - /* some threads might have died */ - num_threads_died += restart_count - restarted_count; - /* wait for the threads to signal their suspension - again */ - sgen_wait_for_suspend_ack (restarted_count); - } - - return num_threads_died; -} - static void acquire_gc_locks (void) { @@ -227,15 +127,7 @@ sgen_client_stop_world (int generation) SGEN_LOG (3, "stopping world n %d from %p %p", sgen_global_stop_count, mono_thread_info_current (), (gpointer)mono_native_thread_id_get ()); TV_GETTIME (stop_world_time); - if (mono_thread_info_unified_management_enabled ()) { - sgen_unified_suspend_stop_world (); - } else { - int count, dead; - count = sgen_thread_handshake (TRUE); - dead = restart_threads_until_none_in_managed_allocator (); - if (count < dead) - g_error ("More threads have died (%d) that been initialy suspended %d", dead, count); - } + sgen_unified_suspend_stop_world (); SGEN_LOG (3, "world stopped"); @@ -273,10 +165,7 @@ sgen_client_restart_world (int generation, GGTimingInfo *timing) TV_GETTIME (start_handshake); - if (mono_thread_info_unified_management_enabled ()) - sgen_unified_suspend_restart_world (); - else - sgen_thread_handshake (FALSE); + sgen_unified_suspend_restart_world (); TV_GETTIME (end_sw); time_restart_world += TV_ELAPSED (start_handshake, end_sw); @@ -445,11 +334,7 @@ sgen_unified_suspend_stop_world (void) mono_threads_wait_pending_operations (); if (sleep_duration < 0) { -#ifdef HOST_WIN32 - SwitchToThread (); -#else - sched_yield (); -#endif + mono_thread_info_yield (); sleep_duration = 0; } else { g_usleep (sleep_duration); @@ -497,4 +382,5 @@ sgen_unified_suspend_restart_world (void) mono_threads_wait_pending_operations (); mono_threads_end_global_suspend (); } + #endif diff --git a/mono/utils/Makefile.am b/mono/utils/Makefile.am index 0b465253d540..563df3f7d4c1 100644 --- a/mono/utils/Makefile.am +++ b/mono/utils/Makefile.am @@ -102,7 +102,6 @@ monoutils_sources = \ mono-threads-state-machine.c \ mono-threads-posix.c \ mono-threads-posix-signals.c \ - mono-threads-posix-signals.h \ mono-threads-mach.c \ mono-threads-mach-helper.c \ mono-threads-windows.c \ diff --git a/mono/utils/mono-threads-posix-abort-syscall.c b/mono/utils/mono-threads-posix-abort-syscall.c index 4935bd1b3686..7c7d90f9fa07 100644 --- a/mono/utils/mono-threads-posix-abort-syscall.c +++ b/mono/utils/mono-threads-posix-abort-syscall.c @@ -15,7 +15,6 @@ #endif #include "mono-threads.h" -#include "mono-threads-posix-signals.h" #if defined(USE_POSIX_SYSCALL_ABORT) diff --git a/mono/utils/mono-threads-posix-signals.c b/mono/utils/mono-threads-posix-signals.c index d6b638829288..ec056fa92aa0 100644 --- a/mono/utils/mono-threads-posix-signals.c +++ b/mono/utils/mono-threads-posix-signals.c @@ -18,7 +18,6 @@ #include #include "mono-semaphore.h" -#include "mono-threads-posix-signals.h" #if defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #define DEFAULT_SUSPEND_SIGNAL SIGXFSZ @@ -72,45 +71,6 @@ signal_add_handler (int signo, gpointer handler, int flags) #endif } -static int -suspend_signal_get (void) -{ -#if defined(PLATFORM_ANDROID) - return SIGUNUSED; -#elif !defined (SIGRTMIN) -#ifdef SIGUSR1 - return SIGUSR1; -#else - return -1; -#endif /* SIGUSR1 */ -#else - static int suspend_signum = -1; - if (suspend_signum == -1) - suspend_signum = signal_search_alternative (-1); - return suspend_signum; -#endif /* SIGRTMIN */ -} - -static int -restart_signal_get (void) -{ -#if defined(PLATFORM_ANDROID) - return SIGTTOU; -#elif !defined (SIGRTMIN) -#ifdef SIGUSR2 - return SIGUSR2; -#else - return -1; -#endif /* SIGUSR1 */ -#else - static int resume_signum = -1; - if (resume_signum == -1) - resume_signum = signal_search_alternative (suspend_signal_get () + 1); - return resume_signum; -#endif /* SIGRTMIN */ -} - - static int abort_signal_get (void) { @@ -125,7 +85,7 @@ abort_signal_get (void) #else static int abort_signum = -1; if (abort_signum == -1) - abort_signum = signal_search_alternative (restart_signal_get () + 1); + abort_signum = signal_search_alternative (MAX (DEFAULT_RESTART_SIGNAL, DEFAULT_SUSPEND_SIGNAL) + 1); return abort_signum; #endif /* SIGRTMIN */ } @@ -251,13 +211,8 @@ mono_threads_posix_init_signals (MonoThreadPosixInitSignals signals) switch (signals) { case MONO_THREADS_POSIX_INIT_SIGNALS_SUSPEND_RESTART: { - if (mono_thread_info_unified_management_enabled ()) { - suspend_signal_num = DEFAULT_SUSPEND_SIGNAL; - restart_signal_num = DEFAULT_RESTART_SIGNAL; - } else { - suspend_signal_num = suspend_signal_get (); - restart_signal_num = restart_signal_get (); - } + suspend_signal_num = DEFAULT_SUSPEND_SIGNAL; + restart_signal_num = DEFAULT_RESTART_SIGNAL; sigfillset (&suspend_signal_mask); sigdelset (&suspend_signal_mask, restart_signal_num); @@ -307,4 +262,24 @@ mono_threads_posix_get_abort_signal (void) return abort_signal_num; } +#else /* defined(USE_POSIX_BACKEND) || defined(USE_POSIX_SYSCALL_ABORT) */ + +gint +mono_threads_posix_get_suspend_signal (void) +{ + return -1; +} + +gint +mono_threads_posix_get_restart_signal (void) +{ + return -1; +} + +gint +mono_threads_posix_get_abort_signal (void) +{ + return -1; +} + #endif /* defined(USE_POSIX_BACKEND) || defined(USE_POSIX_SYSCALL_ABORT) */ diff --git a/mono/utils/mono-threads-posix-signals.h b/mono/utils/mono-threads-posix-signals.h deleted file mode 100644 index 2bdcf8e789ac..000000000000 --- a/mono/utils/mono-threads-posix-signals.h +++ /dev/null @@ -1,31 +0,0 @@ - -#ifndef __MONO_THREADS_POSIX_SIGNALS_H__ -#define __MONO_THREADS_POSIX_SIGNALS_H__ - -#include -#include - -#include "mono-threads.h" - -#if defined(USE_POSIX_BACKEND) || defined(USE_POSIX_SYSCALL_ABORT) - -typedef enum { - MONO_THREADS_POSIX_INIT_SIGNALS_SUSPEND_RESTART, - MONO_THREADS_POSIX_INIT_SIGNALS_ABORT, -} MonoThreadPosixInitSignals; - -void -mono_threads_posix_init_signals (MonoThreadPosixInitSignals signals); - -gint -mono_threads_posix_get_suspend_signal (void); - -gint -mono_threads_posix_get_restart_signal (void); - -gint -mono_threads_posix_get_abort_signal (void); - -#endif /* defined(USE_POSIX_BACKEND) || defined(USE_POSIX_SYSCALL_ABORT) */ - -#endif /* __MONO_THREADS_POSIX_SIGNALS_H__ */ \ No newline at end of file diff --git a/mono/utils/mono-threads-posix.c b/mono/utils/mono-threads-posix.c index ccbd7606b3d3..07243f0bf5b5 100644 --- a/mono/utils/mono-threads-posix.c +++ b/mono/utils/mono-threads-posix.c @@ -15,7 +15,6 @@ #endif #include -#include #include #include diff --git a/mono/utils/mono-threads-state-machine.c b/mono/utils/mono-threads-state-machine.c index 098e02c7ee32..f4730695b428 100644 --- a/mono/utils/mono-threads-state-machine.c +++ b/mono/utils/mono-threads-state-machine.c @@ -466,7 +466,8 @@ mono_threads_transition_async_suspend_compensation (MonoThreadInfo* info) - the thread was previously suspended, which means we should never reach end suspend in the first place. - another suspend happened concurrently, which means the global suspend lock didn't happen. */ - g_assert (suspend_count == 1); + if (G_UNLIKELY(suspend_count != 1)) + g_error ("[%p] suspend_count = %d, but must be 1", mono_thread_info_get_tid (info), suspend_count); if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_RUNNING, suspend_count - 1), raw_state) != raw_state) goto retry_state_change; trace_state_change ("COMPENSATE_FINISH_ASYNC_SUSPEND", info, raw_state, STATE_RUNNING, -1); diff --git a/mono/utils/mono-threads.c b/mono/utils/mono-threads.c index 6bfd46cc3ef1..fba3f0ec2460 100644 --- a/mono/utils/mono-threads.c +++ b/mono/utils/mono-threads.c @@ -61,7 +61,6 @@ static gboolean mono_threads_inited = FALSE; static MonoSemType suspend_semaphore; static size_t pending_suspends; -static gboolean unified_suspend_enabled; #define mono_thread_info_run_state(info) (((MonoThreadInfo*)info)->thread_state & THREAD_STATE_MASK) @@ -603,8 +602,6 @@ mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t info_size) #endif g_assert (res); - unified_suspend_enabled = g_getenv ("MONO_ENABLE_UNIFIED_SUSPEND") != NULL || MONO_THREADS_PLATFORM_REQUIRES_UNIFIED_SUSPEND; - MONO_SEM_INIT (&global_suspend_semaphore, 1); MONO_SEM_INIT (&suspend_semaphore, 0); @@ -1040,12 +1037,6 @@ mono_thread_info_abort_socket_syscall_for_close (MonoNativeThreadId tid) mono_thread_info_suspend_unlock (); } -gboolean -mono_thread_info_unified_management_enabled (void) -{ - return unified_suspend_enabled; -} - /* * mono_thread_info_set_is_async_context: * diff --git a/mono/utils/mono-threads.h b/mono/utils/mono-threads.h index 3c6a0af39e49..1bffcfd55681 100644 --- a/mono/utils/mono-threads.h +++ b/mono/utils/mono-threads.h @@ -401,9 +401,6 @@ mono_thread_info_end_self_suspend (void); //END of new API -gboolean -mono_thread_info_unified_management_enabled (void); - void mono_thread_info_setup_async_call (THREAD_INFO_TYPE *info, void (*target_func)(void*), void *user_data); @@ -661,4 +658,25 @@ gboolean mono_threads_wait_pending_operations (void); void mono_threads_begin_global_suspend (void); void mono_threads_end_global_suspend (void); +#if defined(USE_POSIX_BACKEND) || defined(USE_POSIX_SYSCALL_ABORT) + +typedef enum { + MONO_THREADS_POSIX_INIT_SIGNALS_SUSPEND_RESTART, + MONO_THREADS_POSIX_INIT_SIGNALS_ABORT, +} MonoThreadPosixInitSignals; + +void +mono_threads_posix_init_signals (MonoThreadPosixInitSignals signals); + +#endif /* defined(USE_POSIX_BACKEND) || defined(USE_POSIX_SYSCALL_ABORT) */ + +gint +mono_threads_posix_get_suspend_signal (void); + +gint +mono_threads_posix_get_restart_signal (void); + +gint +mono_threads_posix_get_abort_signal (void); + #endif /* __MONO_THREADS_H__ */ diff --git a/msvc/libmonoutils.vcxproj b/msvc/libmonoutils.vcxproj index 939f52048d73..fd8cf5b4c9c1 100644 --- a/msvc/libmonoutils.vcxproj +++ b/msvc/libmonoutils.vcxproj @@ -133,7 +133,6 @@ - From 28b10947ae10ac1f8d4266025c12e55f15492908 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Thu, 22 Oct 2015 18:51:17 -0400 Subject: [PATCH 3/3] [coop] update native call marshalling to pass thread state transition functions a stack ptr arg. mono_threads_prepare_blocking, mono_threads_finish_blocking, mono_threads_reset_blocking_start, mono_threads_reset_blocking_end all take a stack pointer argument. Update the native and managed wrappers to pass it to them. --- mono/metadata/marshal.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/mono/metadata/marshal.c b/mono/metadata/marshal.c index 54909ea97bc8..cbd037ce96a6 100644 --- a/mono/metadata/marshal.c +++ b/mono/metadata/marshal.c @@ -242,10 +242,10 @@ mono_marshal_init (void) mono_remoting_init (); #ifdef USE_COOP_GC - register_icall (mono_threads_prepare_blocking, "mono_threads_prepare_blocking", "int", FALSE); - register_icall (mono_threads_finish_blocking, "mono_threads_finish_blocking", "void int", FALSE); - register_icall (mono_threads_reset_blocking_start, "mono_threads_reset_blocking_start","int", TRUE); - register_icall (mono_threads_reset_blocking_end, "mono_threads_reset_blocking_end","void int", TRUE); + register_icall (mono_threads_prepare_blocking, "mono_threads_prepare_blocking", "ptr ptr", FALSE); + register_icall (mono_threads_finish_blocking, "mono_threads_finish_blocking", "void ptr ptr", FALSE); + register_icall (mono_threads_reset_blocking_start, "mono_threads_reset_blocking_start","ptr ptr", TRUE); + register_icall (mono_threads_reset_blocking_end, "mono_threads_reset_blocking_end","void ptr ptr", TRUE); #endif } } @@ -7061,7 +7061,7 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM int type, param_shift = 0; static MonoMethodSignature *get_last_error_sig = NULL; #ifdef USE_COOP_GC - int coop_gc_var; + int coop_gc_stack_dummy, coop_gc_var; #endif memset (&m, 0, sizeof (m)); @@ -7101,7 +7101,9 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM } #ifdef USE_COOP_GC - /* local 4, the local to be used when calling the suspend funcs */ + /* local 4, dummy local used to get a stack address for suspend funcs */ + coop_gc_stack_dummy = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); + /* local 5, the local to be used when calling the suspend funcs */ coop_gc_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); #endif @@ -7133,6 +7135,7 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM } #ifdef USE_COOP_GC + mono_mb_emit_ldloc_addr (mb, coop_gc_stack_dummy); mono_mb_emit_icall (mb, mono_threads_prepare_blocking); mono_mb_emit_stloc (mb, coop_gc_var); #endif @@ -7183,6 +7186,7 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM #ifdef USE_COOP_GC mono_mb_emit_ldloc (mb, coop_gc_var); + mono_mb_emit_ldloc_addr (mb, coop_gc_stack_dummy); mono_mb_emit_icall (mb, mono_threads_finish_blocking); #endif @@ -7686,7 +7690,7 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i int i, *tmp_locals; gboolean closed = FALSE; #ifdef USE_COOP_GC - int coop_gc_var; + int coop_gc_var, coop_gc_dummy_local; #endif sig = m->sig; @@ -7717,6 +7721,8 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i /* local 4, the local to be used when calling the reset_blocking funcs */ /* tons of code hardcode 3 to be the return var */ coop_gc_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); + /* local 5, the local used to get a stack address for suspend funcs */ + coop_gc_dummy_local = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); #endif mono_mb_emit_icon (mb, 0); @@ -7731,6 +7737,7 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i #ifdef USE_COOP_GC /* XXX can we merge reset_blocking_start with JIT_ATTACH above and save one call? */ + mono_mb_emit_ldloc_addr (mb, coop_gc_dummy_local); mono_mb_emit_icall (mb, mono_threads_reset_blocking_start); mono_mb_emit_stloc (mb, coop_gc_var); #endif @@ -7866,6 +7873,7 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i #ifdef USE_COOP_GC /* XXX merge reset_blocking_end with detach */ mono_mb_emit_ldloc (mb, coop_gc_var); + mono_mb_emit_ldloc_addr (mb, coop_gc_dummy_local); mono_mb_emit_icall (mb, mono_threads_reset_blocking_end); #endif