Revert "This introduces the new suspend machinery. Right now the unified STW is disab...
authorRodrigo Kumpera <kumpera@gmail.com>
Wed, 25 Feb 2015 22:39:26 +0000 (17:39 -0500)
committerRodrigo Kumpera <kumpera@gmail.com>
Wed, 25 Feb 2015 22:39:26 +0000 (17:39 -0500)
mono/metadata/sgen-os-posix.c
mono/metadata/sgen-stw.c
mono/metadata/threads.c
mono/utils/Makefile.am
mono/utils/mono-threads-mach.c
mono/utils/mono-threads-posix.c
mono/utils/mono-threads-state-machine.c [deleted file]
mono/utils/mono-threads-windows.c
mono/utils/mono-threads.c
mono/utils/mono-threads.h

index a05d2afef158ce4a4cceb0cece4c41d171a8cb08..9b86dad7b6289eceaa0b7d79abb6197367b3e034 100644 (file)
@@ -233,9 +233,6 @@ sgen_os_init (void)
 {
        struct sigaction sinfo;
 
-       if (mono_thread_info_unified_management_enabled ())
-               return;
-
        suspend_ack_semaphore_ptr = &suspend_ack_semaphore;
        MONO_SEM_INIT (&suspend_ack_semaphore, 0);
 
index 564dffed6f358c05b92292dea0321c7ec2cdf4a4..6a1d03230bd0b500cc1048253d8b2195c37a0d99 100644 (file)
 #include "utils/mono-time.h"
 #include "utils/dtrace.h"
 #include "utils/mono-counters.h"
-#include "utils/mono-threads.h"
 
 #define TV_DECLARE SGEN_TV_DECLARE
 #define TV_GETTIME SGEN_TV_GETTIME
 #define TV_ELAPSED SGEN_TV_ELAPSED
 
-static int sgen_unified_suspend_restart_world (void);
-static int sgen_unified_suspend_stop_world (void);
-
 inline static void*
 align_pointer (void *ptr)
 {
@@ -229,16 +225,11 @@ sgen_stop_world (int generation)
        sgen_global_stop_count++;
        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 ()) {
-               count = sgen_unified_suspend_stop_world ();
-       } else {
-               count = sgen_thread_handshake (FALSE);
-               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);
-               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);
+       count -= dead;
 
        SGEN_LOG (3, "world stopped %d thread(s)", count);
        mono_profiler_gc_event (MONO_GC_EVENT_POST_STOP_WORLD, generation);
@@ -294,13 +285,7 @@ sgen_restart_world (int generation, GGTimingInfo *timing)
        } END_FOREACH_THREAD
 
        TV_GETTIME (start_handshake);
-
-       if (mono_thread_info_unified_management_enabled ())
-               count = sgen_unified_suspend_restart_world ();
-       else
-               count = sgen_thread_handshake (FALSE);
-
-
+       count = sgen_thread_handshake (FALSE);
        TV_GETTIME (end_sw);
        time_restart_world += TV_ELAPSED (start_handshake, end_sw);
        usec = TV_ELAPSED (stop_world_time, end_sw);
@@ -347,192 +332,4 @@ sgen_init_stw (void)
        mono_counters_register ("World restart", MONO_COUNTER_GC | MONO_COUNTER_ULONG | MONO_COUNTER_TIME, &time_restart_world);
 }
 
-/* Unified suspend code */
-
-static gboolean
-sgen_is_thread_in_current_stw (SgenThreadInfo *info)
-{
-       /*
-       A thread explicitly asked to be skiped because it holds no managed state.
-       This is used by TP and finalizer threads.
-       FIXME Use an atomic variable for this to avoid everyone taking the GC LOCK.
-       */
-       if (info->gc_disabled) {
-               return FALSE;
-       }
-
-       /*
-       We have detected that this thread is failing/dying, ignore it.
-       FIXME: can't we merge this with thread_is_dying?
-       */
-       if (info->skip) {
-               return FALSE;
-       }
-
-       /*
-       Suspending the current thread will deadlock us, bad idea.
-       */
-       if (info == mono_thread_info_current ()) {
-               return FALSE;
-       }
-
-       /*
-       We can't suspend the workers that will do all the heavy lifting.
-       FIXME Use some state bit in SgenThreadInfo for this.
-       */
-       if (sgen_is_worker_thread (mono_thread_info_get_tid (info))) {
-               return FALSE;
-       }
-
-       /*
-       The thread has signaled that it started to detach, ignore it.
-       FIXME: can't we merge this with skip
-       */
-       if (!mono_thread_info_is_live (info)) {
-               return FALSE;
-       }
-
-       return TRUE;
-}
-
-static void
-update_sgen_info (SgenThreadInfo *info)
-{
-       char *stack_start;
-
-       /* Once we remove the old suspend code, we should move sgen to directly access the state in MonoThread */
-       info->stopped_domain = mono_thread_info_tls_get (info, TLS_KEY_DOMAIN);
-       info->stopped_ip = (gpointer) MONO_CONTEXT_GET_IP (&info->info.suspend_state.ctx);
-       stack_start = (char*)MONO_CONTEXT_GET_SP (&info->info.suspend_state.ctx) - REDZONE_SIZE;
-
-       /* altstack signal handler, sgen can't handle them, mono-threads should have handled this. */
-       if (stack_start < (char*)info->stack_start_limit || stack_start >= (char*)info->stack_end)
-               g_error ("BAD STACK");
-
-       info->stack_start = stack_start;
-       info->ctx = info->info.suspend_state.ctx;
-}
-
-static int
-sgen_unified_suspend_stop_world (void)
-{
-       int restart_counter;
-       SgenThreadInfo *info;
-       int count = 0;
-       int sleep_duration = -1;
-
-       mono_threads_begin_global_suspend ();
-       THREADS_STW_DEBUG ("[GC-STW-BEGIN] *** BEGIN SUSPEND *** \n");
-
-       FOREACH_THREAD_SAFE (info) {
-               info->skip = FALSE;
-               info->suspend_done = FALSE;
-               if (sgen_is_thread_in_current_stw (info)) {
-                       info->skip = !mono_thread_info_begin_suspend (info, FALSE);
-                       THREADS_STW_DEBUG ("[GC-STW-BEGIN-SUSPEND] SUSPEND thread %p skip %d\n", info, info->skip);
-                       if (!info->skip)
-                               ++count;
-               } else {
-                       THREADS_STW_DEBUG ("[GC-STW-BEGIN-SUSPEND] IGNORE thread %p skip %d\n", info, info->skip);
-               }
-       } END_FOREACH_THREAD_SAFE
-
-       mono_thread_info_current ()->suspend_done = TRUE;
-       mono_threads_wait_pending_operations ();
-
-       for (;;) {
-               restart_counter = 0;
-               FOREACH_THREAD_SAFE (info) {
-                       if (info->suspend_done || !sgen_is_thread_in_current_stw (info)) {
-                               THREADS_STW_DEBUG ("[GC-STW-RESTART] IGNORE thread %p not been processed done %d current %d\n", info, info->suspend_done, !sgen_is_thread_in_current_stw (info));
-                               continue;
-                       }
-
-                       /*
-                       All threads that reach here are pristine suspended. This means the following:
-
-                       - We haven't accepted the previous suspend as good.
-                       - We haven't gave up on it for this STW (it's either bad or asked not to)
-                       */
-                       if (!mono_threads_core_check_suspend_result (info)) {
-                               THREADS_STW_DEBUG ("[GC-STW-RESTART] SKIP thread %p failed to finish to suspend\n", info);
-                               info->skip = TRUE;
-                       } else if (mono_thread_info_in_critical_location (info)) {
-                               gboolean res;
-                               g_assert (mono_thread_info_suspend_count (info) == 1);
-                               res = mono_thread_info_begin_resume (info);
-                               THREADS_STW_DEBUG ("[GC-STW-RESTART] RESTART thread %p skip %d\n", info, res);
-                               if (res)
-                                       ++restart_counter;
-                               else
-                                       info->skip = TRUE;
-                       } else {
-                               THREADS_STW_DEBUG ("[GC-STW-RESTART] DONE thread %p deemed fully suspended\n", info);
-                               g_assert (!info->in_critical_region);
-                               info->suspend_done = TRUE;
-                       }
-               } END_FOREACH_THREAD_SAFE
-
-               if (restart_counter == 0)
-                       break;
-               mono_threads_wait_pending_operations ();
-
-               if (sleep_duration < 0) {
-#ifdef HOST_WIN32
-                       SwitchToThread ();
-#else
-                       sched_yield ();
-#endif
-                       sleep_duration = 0;
-               } else {
-                       g_usleep (sleep_duration);
-                       sleep_duration += 10;
-               }
-
-               FOREACH_THREAD_SAFE (info) {
-                       if (sgen_is_thread_in_current_stw (info) && mono_thread_info_is_running (info)) {
-                               gboolean res = mono_thread_info_begin_suspend (info, FALSE);
-                               THREADS_STW_DEBUG ("[GC-STW-RESTART] SUSPEND thread %p skip %d\n", info, res);
-                               if (!res)
-                                       info->skip = TRUE;
-                       }
-               } END_FOREACH_THREAD_SAFE
-
-               mono_threads_wait_pending_operations ();
-       }
-
-       FOREACH_THREAD_SAFE (info) {
-               if (sgen_is_thread_in_current_stw (info)) {
-                       THREADS_STW_DEBUG ("[GC-STW-SUSPEND-END] thread %p is suspended\n", info);
-                       g_assert (info->suspend_done);
-                       update_sgen_info (info);
-               } else {
-                       g_assert (!info->suspend_done);
-               }
-       } END_FOREACH_THREAD_SAFE
-
-       return count;
-}
-
-static int
-sgen_unified_suspend_restart_world (void)
-{
-       SgenThreadInfo *info;
-       int count = 0;
-
-       THREADS_STW_DEBUG ("[GC-STW-END] *** BEGIN RESUME ***\n");
-       FOREACH_THREAD_SAFE (info) {
-               if (sgen_is_thread_in_current_stw (info)) {
-                       g_assert (mono_thread_info_begin_resume (info));
-                       THREADS_STW_DEBUG ("[GC-STW-RESUME-WORLD] RESUME thread %p\n", info);
-                       ++count;
-               } else {
-                       THREADS_STW_DEBUG ("[GC-STW-RESUME-WORLD] IGNORE thread %p\n", info);
-               }
-       } END_FOREACH_THREAD_SAFE
-
-       mono_threads_wait_pending_operations ();
-       mono_threads_end_global_suspend ();
-       return count;
-}
 #endif
index de5805ad80d3fa920b611a1f17f426944e4bcf62..5347447103672f05cdc1b2ff4751870dd36b2f3f 100644 (file)
@@ -4687,9 +4687,8 @@ suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
 
        LOCK_THREAD (thread);
        if (thread == mono_thread_internal_current ()) {
-               mono_thread_info_begin_self_suspend ();
                transition_to_suspended (thread, NULL);
-               mono_thread_info_end_self_suspend ();
+               mono_thread_info_self_suspend ();
        } else {
                MonoThreadInfo *info;
                MonoJitInfo *ji;
@@ -4766,9 +4765,8 @@ self_suspend_internal (MonoInternalThread *thread)
                return;
        }
 
-       mono_thread_info_begin_self_suspend ();
        transition_to_suspended (thread, NULL);
-       mono_thread_info_end_self_suspend ();
+       mono_thread_info_self_suspend ();
 }
 
 /*This is called with @thread synch_cs held and it must release it*/
index c6288c4b0577eeb54fdc36cf2d7831e615754e94..8003b5666666f3f32aee3016854dcfdaa8d6a08a 100644 (file)
@@ -99,7 +99,6 @@ monoutils_sources = \
        mono-linked-list-set.c  \
        mono-linked-list-set.h  \
        mono-threads.c  \
-       mono-threads-state-machine.c    \
        mono-threads-posix.c    \
        mono-threads-mach.c     \
        mono-threads-mach-helper.c      \
index 709ac31aea65f96cf2b2bd8f283fcae549f21029..c0b28a12d8e97de1295be3e7ad1bed653a37dd6a 100644 (file)
@@ -9,21 +9,17 @@
 
 #include "config.h"
 
+#if defined(__MACH__)
+
 /* For pthread_main_np, pthread_get_stackaddr_np and pthread_get_stacksize_np */
-#if defined (__MACH__)
 #define _DARWIN_C_SOURCE 1
-#endif
-
-#include <mono/utils/mono-threads.h>
-#include <mono/utils/mono-mmap.h>
-
-#if defined (USE_MACH_BACKEND)
 
 #include <mono/utils/mach-support.h>
 #include <mono/utils/mono-compiler.h>
 #include <mono/utils/mono-semaphore.h>
 #include <mono/utils/mono-threads.h>
 #include <mono/utils/hazard-pointer.h>
+#include <mono/utils/mono-mmap.h>
 
 void
 mono_threads_init_platform (void)
@@ -31,6 +27,12 @@ mono_threads_init_platform (void)
        mono_threads_init_dead_letter ();
 }
 
+void
+mono_threads_core_interrupt (MonoThreadInfo *info)
+{
+       thread_abort (info->native_handle);
+}
+
 void
 mono_threads_core_abort_syscall (MonoThreadInfo *info)
 {
@@ -43,7 +45,7 @@ mono_threads_core_needs_abort_syscall (void)
 }
 
 gboolean
-mono_threads_core_begin_async_suspend (MonoThreadInfo *info, gboolean interrupt_kernel)
+mono_threads_core_suspend (MonoThreadInfo *info, gboolean interrupt_kernel)
 {
        kern_return_t ret;
        gboolean res;
@@ -51,40 +53,17 @@ mono_threads_core_begin_async_suspend (MonoThreadInfo *info, gboolean interrupt_
        g_assert (info);
 
        ret = thread_suspend (info->native_handle);
-       THREADS_SUSPEND_DEBUG ("SUSPEND %p -> %d\n", (void*)info->native_handle, ret);
        if (ret != KERN_SUCCESS)
                return FALSE;
-
-       /* We're in the middle of a self-suspend, resume and register */
-       if (!mono_threads_transition_finish_async_suspend (info)) {
-               mono_threads_add_to_pending_operation_set (info);
-               g_assert (thread_resume (info->native_handle) == KERN_SUCCESS);
-               THREADS_SUSPEND_DEBUG ("FAILSAFE RESUME/1 %p -> %d\n", (void*)info->native_handle, 0);
-               //XXX interrupt_kernel doesn't make sense in this case as the target is not in a syscall
-               return TRUE;
-       }
        res = mono_threads_get_runtime_callbacks ()->
                thread_state_init_from_handle (&info->suspend_state, info);
-       THREADS_SUSPEND_DEBUG ("thread state %p -> %d\n", (void*)info->native_handle, res);
-       if (res) {
-               if (interrupt_kernel)
-                       thread_abort (info->native_handle);
-       } else {
-               mono_threads_transition_async_suspend_compensation (info);
-               g_assert (thread_resume (info->native_handle) == KERN_SUCCESS);
-               THREADS_SUSPEND_DEBUG ("FAILSAFE RESUME/2 %p -> %d\n", (void*)info->native_handle, 0);
-       }
+       if (!res)
+               thread_resume (info->native_handle);
        return res;
 }
 
 gboolean
-mono_threads_core_check_suspend_result (MonoThreadInfo *info)
-{
-       return TRUE;
-}
-
-gboolean
-mono_threads_core_begin_async_resume (MonoThreadInfo *info)
+mono_threads_core_resume (MonoThreadInfo *info)
 {
        kern_return_t ret;
 
@@ -120,9 +99,8 @@ mono_threads_core_begin_async_resume (MonoThreadInfo *info)
                        return FALSE;
        }
 
-       ret = thread_resume (info->native_handle);
-       THREADS_SUSPEND_DEBUG ("RESUME %p -> %d\n", (void*)info->native_handle, ret);
 
+       ret = thread_resume (info->native_handle);
        return ret == KERN_SUCCESS;
 }
 
@@ -167,9 +145,7 @@ mono_threads_core_set_name (MonoNativeThreadId tid, const char *name)
 {
        /* pthread_setnmae_np() on Mac is not documented and doesn't receive thread id. */
 }
-#endif /* USE_MACH_BACKEND */
 
-#ifdef __MACH__
 void
 mono_threads_core_get_stack_bounds (guint8 **staddr, size_t *stsize)
 {
index 8beb693a51cc2ba4ab6120fef1f7e2c379641dd3..9aa28fba74de0e2f57e12c56a2bd72ae651845b0 100644 (file)
@@ -9,11 +9,6 @@
 
 #include <config.h>
 
-/* For pthread_main_np, pthread_get_stackaddr_np and pthread_get_stacksize_np */
-#if defined (__MACH__)
-#define _DARWIN_C_SOURCE 1
-#endif
-
 #include <mono/utils/mono-compiler.h>
 #include <mono/utils/mono-semaphore.h>
 #include <mono/utils/mono-threads.h>
@@ -48,6 +43,10 @@ typedef struct {
        HANDLE handle;
 } StartInfo;
 
+#ifdef PLATFORM_ANDROID
+static int no_interrupt_signo;
+#endif
+
 static void*
 inner_start_thread (void *arg)
 {
@@ -289,121 +288,18 @@ mono_threads_pthread_kill (MonoThreadInfo *info, int signum)
 
 }
 
-#if defined (USE_POSIX_BACKEND)
-
-static int suspend_signal_num;
-static int restart_signal_num;
-static int abort_signal_num;
-static sigset_t suspend_signal_mask;
-static sigset_t suspend_ack_signal_mask;
-
-
-#if defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
-#define DEFAULT_SUSPEND_SIGNAL SIGXFSZ
-#else
-#define DEFAULT_SUSPEND_SIGNAL SIGPWR
-#endif
-#define DEFAULT_RESTART_SIGNAL SIGXCPU
-#define DEFAULT_ABORT_SIGNAL SIGWINCH
-
-static int
-mono_thread_search_alt_signal (int min_signal)
-{
-#if !defined (SIGRTMIN)
-       g_error ("signal search only works with RTMIN");
-#else
-       static int abort_signum = -1;
-       int i;
-       if (abort_signum != -1)
-               return abort_signum;
-       /* we try to avoid SIGRTMIN and any one that might have been set already, see bug #75387 */
-       for (i = MAX (min_signal, SIGRTMIN) + 1; i < SIGRTMAX; ++i) {
-               struct sigaction sinfo;
-               sigaction (i, NULL, &sinfo);
-               if (sinfo.sa_handler == SIG_DFL && (void*)sinfo.sa_sigaction == (void*)SIG_DFL) {
-                       abort_signum = i;
-                       return i;
-               }
-       }
-       g_error ("Could not find an available signal");
-#endif
-}
-
-static int
-mono_thread_get_alt_suspend_signal (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;
-       int i;
-       if (suspend_signum == -1)
-               suspend_signum = mono_thread_search_alt_signal (-1);
-       return suspend_signum;
-#endif /* SIGRTMIN */
-}
-
-static int
-mono_thread_get_alt_resume_signal (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;
-       int i;
-       if (resume_signum == -1)
-               resume_signum = mono_thread_search_alt_signal (mono_thread_get_alt_suspend_signal ());
-       return resume_signum;
-#endif /* SIGRTMIN */
-}
-
+#if !defined (__MACH__)
 
 #if !defined(__native_client__)
-static void
-restart_signal_handler (int _dummy, siginfo_t *_info, void *context)
-{
-       MonoThreadInfo *info;
-       int old_errno = errno;
-
-       info = mono_thread_info_current ();
-       info->signal = restart_signal_num;
-       errno = old_errno;
-}
-
 static void
 suspend_signal_handler (int _dummy, siginfo_t *info, void *context)
 {
-       int old_errno = errno;
-       int hp_save_index = mono_hazard_pointer_save_for_signal_handler ();
-
-
        MonoThreadInfo *current = mono_thread_info_current ();
        gboolean ret;
-
-       THREADS_SUSPEND_DEBUG ("SIGNAL HANDLER FOR %p [%p]\n", current, (void*)current->native_handle);
+       
        if (current->syscall_break_signal) {
                current->syscall_break_signal = FALSE;
-               THREADS_SUSPEND_DEBUG ("\tsyscall break for %p\n", current);
-               goto done;
-       }
-
-       /* Have we raced with self suspend? */
-       if (!mono_threads_transition_finish_async_suspend (current)) {
-               current->suspend_can_continue = TRUE;
-               THREADS_SUSPEND_DEBUG ("\tlost race with self suspend %p\n", current);
-               goto done;
+               return;
        }
 
        ret = mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (&current->suspend_state, context);
@@ -411,35 +307,16 @@ 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,
-       which might miss the signal and get stuck.
-       */
-       pthread_sigmask (SIG_BLOCK, &suspend_ack_signal_mask, NULL);
-
-       /* We're done suspending */
-       mono_threads_notify_initiator_of_suspend (current);
+       MONO_SEM_POST (&current->begin_suspend_semaphore);
 
        /* 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);
-               /* Unblock the restart signal. */
-               pthread_sigmask (SIG_UNBLOCK, &suspend_ack_signal_mask, NULL);
+       if (!ret)
+               return;
 
-               goto done;
+       while (MONO_SEM_WAIT (&current->resume_semaphore) != 0) {
+               /*if (EINTR != errno) ABORT("sem_wait failed"); */
        }
 
-       do {
-               current->signal = 0;
-               sigsuspend (&suspend_signal_mask);
-       } while (current->signal != restart_signal_num);
-
-       /* Unblock the restart signal. */
-       pthread_sigmask (SIG_UNBLOCK, &suspend_ack_signal_mask, NULL);
-
        if (current->async_target) {
 #if MONO_ARCH_HAS_MONO_CONTEXT
                MonoContext tmp = current->suspend_state.ctx;
@@ -451,20 +328,8 @@ suspend_signal_handler (int _dummy, siginfo_t *info, void *context)
 #endif
        }
 
-       /* We're done resuming */
-       mono_threads_notify_initiator_of_resume (current);
-
-done:
-       mono_hazard_pointer_restore_for_signal_handler (hp_save_index);
-       errno = old_errno;
-}
-
-static void
-abort_signal_handler (int _dummy, siginfo_t *info, void *context)
-{
-       suspend_signal_handler (_dummy, info, context);
+       MONO_SEM_POST (&current->finish_resume_semaphore);
 }
-
 #endif
 
 static void
@@ -477,8 +342,7 @@ mono_posix_add_signal_handler (int signo, gpointer handler, int flags)
        int ret;
 
        sa.sa_sigaction = handler;
-       sigfillset (&sa.sa_mask);
-
+       sigemptyset (&sa.sa_mask);
        sa.sa_flags = SA_SIGINFO | flags;
        ret = sigaction (signo, &sa, &previous_sa);
 
@@ -489,33 +353,37 @@ mono_posix_add_signal_handler (int signo, gpointer handler, int flags)
 void
 mono_threads_init_platform (void)
 {
-       sigset_t signal_set;
-
-       abort_signal_num = DEFAULT_ABORT_SIGNAL;
-       if (mono_thread_info_unified_management_enabled ()) {
-               suspend_signal_num = DEFAULT_SUSPEND_SIGNAL;
-               restart_signal_num = DEFAULT_RESTART_SIGNAL;
-       } else {
-               suspend_signal_num = mono_thread_get_alt_suspend_signal ();
-               restart_signal_num = mono_thread_get_alt_resume_signal ();
-       }
-
-       sigfillset (&suspend_signal_mask);
-       sigdelset (&suspend_signal_mask, restart_signal_num);
+#if !defined(__native_client__)
+       int abort_signo;
 
-       sigemptyset (&suspend_ack_signal_mask);
-       sigaddset (&suspend_ack_signal_mask, restart_signal_num);
+       /*
+       FIXME we should use all macros from mini to make this more portable
+       FIXME it would be very sweet if sgen could end up using this too.
+       */
+       if (!mono_thread_info_new_interrupt_enabled ())
+               return;
+       abort_signo = mono_thread_get_abort_signal ();
+       mono_posix_add_signal_handler (abort_signo, suspend_signal_handler, 0);
 
-       mono_posix_add_signal_handler (suspend_signal_num, suspend_signal_handler, SA_RESTART);
-       mono_posix_add_signal_handler (restart_signal_num, restart_signal_handler, SA_RESTART);
-       mono_posix_add_signal_handler (abort_signal_num, abort_signal_handler, 0);
+#ifdef PLATFORM_ANDROID
+       /*
+        * Lots of android native code can't handle the EINTR caused by
+        * the normal abort signal, so use a different signal for the
+        * no interruption case, which is used by sdb.
+        * FIXME: Use this on all platforms.
+        * SIGUSR1 is used by dalvik/art.
+        */
+       no_interrupt_signo = SIGWINCH;
+       g_assert (abort_signo != no_interrupt_signo);
+       mono_posix_add_signal_handler (no_interrupt_signo, suspend_signal_handler, SA_RESTART);
+#endif
+#endif
+}
 
-       /* ensure all the new signals are unblocked */
-       sigemptyset (&signal_set);
-       sigaddset (&signal_set, suspend_signal_num);
-       sigaddset (&signal_set, restart_signal_num);
-       sigaddset (&signal_set, abort_signal_num);
-       sigprocmask (SIG_UNBLOCK, &signal_set, NULL);
+void
+mono_threads_core_interrupt (MonoThreadInfo *info)
+{
+       /* Handled in mono_threads_core_suspend () */
 }
 
 void
@@ -526,7 +394,7 @@ mono_threads_core_abort_syscall (MonoThreadInfo *info)
        This signal should not be interpreted as a suspend request.
        */
        info->syscall_break_signal = TRUE;
-       mono_threads_pthread_kill (info, abort_signal_num);
+       mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
 }
 
 gboolean
@@ -536,39 +404,39 @@ mono_threads_core_needs_abort_syscall (void)
 }
 
 gboolean
-mono_threads_core_begin_async_suspend (MonoThreadInfo *info, gboolean interrupt_kernel)
+mono_threads_core_suspend (MonoThreadInfo *info, gboolean interrupt_kernel)
 {
-       int sig = interrupt_kernel ? abort_signal_num :  suspend_signal_num;
-
-       if (!mono_threads_pthread_kill (info, sig)) {
-               mono_threads_add_to_pending_operation_set (info);
-               return TRUE;
+       /*FIXME, check return value*/
+#ifdef PLATFORM_ANDROID
+       if (!interrupt_kernel)
+               mono_threads_pthread_kill (info, no_interrupt_signo);
+       else
+               mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
+#else
+               mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
+#endif
+       while (MONO_SEM_WAIT (&info->begin_suspend_semaphore) != 0) {
+               /* g_assert (errno == EINTR); */
        }
-       return FALSE;
-}
-
-gboolean
-mono_threads_core_check_suspend_result (MonoThreadInfo *info)
-{
        return info->suspend_can_continue;
 }
 
-/*
-This begins async resume. This function must do the following:
-
-- Install an async target if one was requested.
-- Notify the target to resume.
-*/
 gboolean
-mono_threads_core_begin_async_resume (MonoThreadInfo *info)
+mono_threads_core_resume (MonoThreadInfo *info)
 {
-       mono_threads_add_to_pending_operation_set (info);
-       return mono_threads_pthread_kill (info, restart_signal_num) == 0;
+       MONO_SEM_POST (&info->resume_semaphore);
+       while (MONO_SEM_WAIT (&info->finish_resume_semaphore) != 0) {
+               /* g_assert (errno == EINTR); */
+       }
+
+       return TRUE;
 }
 
 void
 mono_threads_platform_register (MonoThreadInfo *info)
 {
+       MONO_SEM_INIT (&info->begin_suspend_semaphore, 0);
+
 #if defined (PLATFORM_ANDROID)
        info->native_handle = gettid ();
 #endif
@@ -577,6 +445,7 @@ mono_threads_platform_register (MonoThreadInfo *info)
 void
 mono_threads_platform_free (MonoThreadInfo *info)
 {
+       MONO_SEM_DESTROY (&info->begin_suspend_semaphore);
 }
 
 MonoNativeThreadId
@@ -605,7 +474,7 @@ mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
 void
 mono_threads_core_set_name (MonoNativeThreadId tid, const char *name)
 {
-#if defined (HAVE_PTHREAD_SETNAME_NP) && !defined (__MACH__)
+#ifdef HAVE_PTHREAD_SETNAME_NP
        if (!name) {
                pthread_setname_np (tid, "");
        } else {
@@ -618,6 +487,6 @@ mono_threads_core_set_name (MonoNativeThreadId tid, const char *name)
 #endif
 }
 
-#endif /*defined (USE_POSIX_BACKEND)*/
+#endif /*!defined (__MACH__)*/
 
 #endif
diff --git a/mono/utils/mono-threads-state-machine.c b/mono/utils/mono-threads-state-machine.c
deleted file mode 100644 (file)
index 9bcaf4f..0000000
+++ /dev/null
@@ -1,549 +0,0 @@
-#include <config.h>
-
-#include <mono/utils/mono-compiler.h>
-#include <mono/utils/mono-threads.h>
-#include <mono/utils/mono-tls.h>
-#include <mono/utils/mono-memory-model.h>
-#include <mono/utils/atomic.h>
-
-#include <errno.h>
-
-/*thread state helpers*/
-static inline int
-get_thread_state (int thread_state)
-{
-       return thread_state & THREAD_STATE_MASK;
-}
-
-static inline int
-get_thread_suspend_count (int thread_state)
-{
-       return (thread_state & THREAD_SUSPEND_COUNT_MASK) >> THREAD_SUSPEND_COUNT_SHIFT;
-}
-
-static inline int
-build_thread_state (int thread_state, int suspend_count) 
-{
-       g_assert (suspend_count >= 0 && suspend_count <= THREAD_SUSPEND_COUNT_MAX);
-       g_assert (thread_state >= 0 && thread_state <= STATE_MAX);
-
-       return thread_state | (suspend_count << THREAD_SUSPEND_COUNT_SHIFT);
-}
-
-static const char*
-state_name (int state)
-{
-       static const char *state_names [] = {
-               "STARTING",
-               "RUNNING",
-               "DETACHED",
-               "ASYNC_SUSPENDED",
-               "SELF_SUSPENDED",
-               "ASYNC_SUSPEND_REQUESTED",
-               "SELF_SUSPEND_REQUESTED",
-               "SUSPEND_IN_PROGRESS",
-               "SUSPEND_PROMOTED_TO_ASYNC",
-       };
-       return state_names [get_thread_state (state)];
-}
-
-#define UNWRAP_THREAD_STATE(RAW,CUR,COUNT,INFO) do {   \
-       RAW = (INFO)->thread_state;     \
-       CUR = get_thread_state (RAW);   \
-       COUNT = get_thread_suspend_count (RAW); \
-} while (0)
-
-static void
-check_thread_state (MonoThreadInfo* info)
-{
-       int raw_state, cur_state, suspend_count;
-       UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
-       switch (cur_state) {
-       case STATE_STARTING:
-       case STATE_RUNNING:
-       case STATE_DETACHED:
-               g_assert (suspend_count == 0);
-               break;
-       case STATE_ASYNC_SUSPENDED:
-       case STATE_SELF_SUSPENDED:
-       case STATE_ASYNC_SUSPEND_REQUESTED:
-       case STATE_SELF_SUSPEND_REQUESTED:
-       case STATE_SUSPEND_IN_PROGRESS:
-       case STATE_SUSPEND_PROMOTED_TO_ASYNC:
-               g_assert (suspend_count > 0);
-               break;
-       default:
-               g_error ("Invalid state %d", cur_state);
-       }
-}
-
-static inline void
-trace_state_change (const char *transition, MonoThreadInfo *info, int cur_raw_state, int next_state, int suspend_count_delta)
-{
-       check_thread_state (info);
-       THREADS_STATE_MACHINE_DEBUG ("[%s][%p] %s -> %s (%d -> %d)\n",
-               transition,
-               mono_thread_info_get_tid (info),
-               state_name (get_thread_state (cur_raw_state)),
-               state_name (next_state),
-               get_thread_suspend_count (cur_raw_state),
-               get_thread_suspend_count (cur_raw_state) + suspend_count_delta);
-}
-
-/*
-This is the transition that signals that a thread is functioning.
-Its main goal is to catch threads been witnessed before been fully registered.
-*/
-void
-mono_threads_transition_attach (MonoThreadInfo* info)
-{
-       int raw_state, cur_state, suspend_count;
-
-retry_state_change:
-       UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
-       switch (cur_state) {
-       case STATE_STARTING:
-               g_assert (suspend_count == 0);
-               if (InterlockedCompareExchange (&info->thread_state, STATE_RUNNING, raw_state) != raw_state)
-                       goto retry_state_change;
-               trace_state_change ("ATTACH", info, raw_state, STATE_RUNNING, 0);
-               break;
-       default:
-               g_error ("Cannot transition current thread from %s with ATTACH", state_name (cur_state));
-       }
-}
-
-/*
-This is the transition that signals that a thread is no longer registered with the runtime.
-Its main goal is to catch threads been witnessed after they detach.
-
-This returns TRUE is the transition succeeded.
-If it returns false it means that there's a pending suspend that should be acted upon.
-*/
-gboolean
-mono_threads_transition_detach (MonoThreadInfo *info)
-{
-       int raw_state, cur_state, suspend_count;
-
-retry_state_change:
-       UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
-       switch (cur_state) {
-       case STATE_RUNNING:
-               g_assert (suspend_count == 0);
-               if (InterlockedCompareExchange (&info->thread_state, STATE_DETACHED, raw_state) != raw_state)
-                       goto retry_state_change;
-               trace_state_change ("DETACH", info, raw_state, STATE_DETACHED, 0);
-               return TRUE;
-       case STATE_ASYNC_SUSPEND_REQUESTED: //Can't detach until whoever asked us to suspend to be happy with us
-               return FALSE;
-/*
-STATE_ASYNC_SUSPENDED: Code should not be running while suspended.
-STATE_SELF_SUSPENDED: Code should not be running while suspended.
-STATE_SELF_SUSPEND_REQUESTED: This is a bug in the self suspend code that didn't execute the second part of it
-STATE_SUSPEND_IN_PROGRESS: This is an internal state of suspension
-STATE_SUSPEND_PROMOTED_TO_ASYNC: This is an internal state of suspension
-*/
-       default:
-               g_error ("Cannot transition current thread %p from %s with DETACH", info, state_name (cur_state));
-       }
-}
-
-/*
-This transition initiates the suspension of the current thread.
-*/
-void
-mono_threads_transition_request_self_suspension (MonoThreadInfo *info)
-{
-       int raw_state, cur_state, suspend_count;
-       g_assert (info ==  mono_thread_info_current ());
-
-retry_state_change:
-       UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
-
-       switch (cur_state) {
-       case STATE_RUNNING: //Post a self suspend request
-               g_assert (suspend_count == 0);
-               if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_SELF_SUSPEND_REQUESTED, 1), raw_state) != raw_state)
-                       goto retry_state_change;
-               trace_state_change ("SELF_SUSPEND_REQUEST", info, raw_state, STATE_SELF_SUSPEND_REQUESTED, 1);
-               break;
-
-       case STATE_ASYNC_SUSPEND_REQUESTED: //Bump the suspend count but don't change the request type as async takes preference
-               g_assert (suspend_count > 0 && suspend_count < THREAD_SUSPEND_COUNT_MAX);
-               if (InterlockedCompareExchange (&info->thread_state, build_thread_state (cur_state, suspend_count + 1), raw_state) != raw_state)
-                       goto retry_state_change;
-               trace_state_change ("SUSPEND_REQUEST", info, raw_state, cur_state, 1);
-               break;
-/*
-Other states:
-STATE_ASYNC_SUSPENDED: Code should not be running while suspended.
-STATE_SELF_SUSPENDED: Code should not be running while suspended.
-STATE_SELF_SUSPEND_REQUESTED: Self suspends should not nest as begin/end should be paired. [1]
-STATE_SUSPEND_IN_PROGRESS: This in an internal state of the self suspend finish protocol. A new self suspend request must not happen during it
-STATE_SUSPEND_PROMOTED_TO_ASYNC: This in an internal state of the self suspend finish protocol. A new self suspend request must not happen during it
-
-[1] This won't trap this sequence of requests: self suspend, async suspend and self suspend. 
-If this turns to be an issue we can introduce a new suspend request state for when both have been requested.
-*/
-       default:
-               g_error ("Cannot transition thread %p from %s with SUSPEND_REQUEST", info, state_name (cur_state));
-       }
-}
-
-/*
-This transition initiates the suspension of another thread.
-
-Returns TRUE if suspension notification will happen and FALSE if the target is already suspended.
-*/
-gboolean
-mono_threads_transition_request_async_suspension (MonoThreadInfo *info)
-{
-       int raw_state, cur_state, suspend_count;
-       g_assert (info != mono_thread_info_current ());
-
-retry_state_change:
-       UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
-
-       switch (cur_state) {
-       case STATE_RUNNING: //Post an async suspend request
-               g_assert (suspend_count == 0);
-               if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_ASYNC_SUSPEND_REQUESTED, 1), raw_state) != raw_state)
-                       goto retry_state_change;
-               trace_state_change ("ASYNC_SUSPEND_REQUESTED", info, raw_state, STATE_ASYNC_SUSPEND_REQUESTED, 1);
-               return TRUE; //This is the first async suspend request against the target
-
-       case STATE_ASYNC_SUSPENDED:
-       case STATE_SELF_SUSPENDED: //Async suspend can suspend the same thread multiple times as it starts from the outside
-               g_assert (suspend_count > 0 && suspend_count < THREAD_SUSPEND_COUNT_MAX);
-               if (InterlockedCompareExchange (&info->thread_state, build_thread_state (cur_state, suspend_count + 1), raw_state) != raw_state)
-                       goto retry_state_change;
-               trace_state_change ("ASYNC_SUSPEND_REQUESTED", info, raw_state, cur_state, 1);
-               return FALSE; //Thread is already suspended so we don't need to wait it to suspend
-
-       case STATE_SELF_SUSPEND_REQUESTED: //This suspend needs to notify the initiator, so we need to promote the suspend to async
-               g_assert (suspend_count > 0 && suspend_count < THREAD_SUSPEND_COUNT_MAX);
-               if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_ASYNC_SUSPEND_REQUESTED, suspend_count + 1), raw_state) != raw_state)
-                       goto retry_state_change;
-               trace_state_change ("ASYNC_SUSPEND_REQUESTED", info, raw_state, STATE_ASYNC_SUSPEND_REQUESTED, 1);
-               return TRUE; //This is the first async suspend request against the target
-
-       case STATE_SUSPEND_IN_PROGRESS: //Self suspend has already initiated, we need to tell it to inform us in the end
-               g_assert (suspend_count > 0 && suspend_count < THREAD_SUSPEND_COUNT_MAX);
-               g_assert (info != mono_thread_info_current ()); // if this is a self suspend request, which can't happen in this state, as this is the middle of the self suspend protocol.
-               if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_SUSPEND_PROMOTED_TO_ASYNC, suspend_count + 1), raw_state) != raw_state)
-                       goto retry_state_change;
-               trace_state_change ("ASYNC_SUSPEND_REQUESTED", info, raw_state, STATE_SUSPEND_PROMOTED_TO_ASYNC, 1);
-               return TRUE; //This is a self suspend in progress that now needs to notify the initiator
-               break;
-/*
-STATE_ASYNC_SUSPEND_REQUESTED: Since there can only be one async suspend in progress and it must finish, it should not be possible to witness this.
-STATE_SUSPEND_PROMOTED_TO_ASYNC: This is a self suspend that was promoted to an async suspend, which should not be possible to witness due to async suspends happening one at a time.
-*/
-       default:
-               g_error ("Cannot transition thread %p from %s with ASYNC_SUSPEND_REQUESTED", info, state_name (cur_state));
-       }
-       return FALSE;
-}
-
-/*
-Check the current state of the thread and try to init a self suspend.
-
-Returns TRUE is self suspend should start.
-
-*/
-gboolean
-mono_threads_transition_state_poll (MonoThreadInfo *info)
-{
-       int raw_state, cur_state, suspend_count;
-       g_assert (info == mono_thread_info_current ());
-
-retry_state_change:
-       UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
-       switch (cur_state) {
-       case STATE_RUNNING:
-               g_assert (suspend_count == 0);
-               trace_state_change ("STATE_POLL", info, raw_state, cur_state, 0);
-               return FALSE; //We're fine, don't suspend
-
-       case STATE_ASYNC_SUSPEND_REQUESTED: //Async suspend requested, service it with a self suspend
-               g_assert (suspend_count > 0);
-               if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_SUSPEND_PROMOTED_TO_ASYNC, suspend_count), raw_state) != raw_state)
-                       goto retry_state_change;
-               trace_state_change ("STATE_POLL", info, raw_state, STATE_SUSPEND_PROMOTED_TO_ASYNC, 0);
-               return TRUE;
-
-       case STATE_SELF_SUSPEND_REQUESTED: //Start the self suspend process
-               g_assert (suspend_count > 0);
-               if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_SUSPEND_IN_PROGRESS, suspend_count), raw_state) != raw_state)
-                       goto retry_state_change;
-               trace_state_change ("STATE_POLL", info, raw_state, STATE_SUSPEND_IN_PROGRESS, 0);
-               return TRUE;
-
-/*
-STATE_ASYNC_SUSPENDED: Code should not be running while suspended.
-STATE_SELF_SUSPENDED: Code should not be running while suspended.
-STATE_SUSPEND_IN_PROGRESS: State polling should not happen while self suspend is finishing
-STATE_SUSPEND_PROMOTED_TO_ASYNC: State polling should not happen while self suspend is finishing
-*/
-       default:
-               g_error ("Cannot transition thread %p from %s with STATE_POLL", info, state_name (cur_state));
-       }
-}
-
-/*
-Try to resume a suspended thread.
-
-Returns one of the following values:
-- Sucess: The thread was resumed.
-- Error: The thread was not suspended in the first place. [2]
-- InitSelfResume: The thread is blocked on self suspend and should be resumed 
-- InitAsycResume: The thread is blocked on async suspend and should be resumed
-
-[2] This threading system uses an unsigned suspend count. Which means a resume cannot be
-used as a suspend permit and cancel each other.
-
-Suspend permits are really useful to implement managed synchronization structures that
-don't consume native resources. The downside is that they further complicate the design of this
-system as the RUNNING state now has a non zero suspend counter.
-
-It can be implemented in the future if we find resume/suspend races that cannot be (efficiently) fixed by other means.
-
-One major issue with suspend permits is runtime facilities (GC, debugger) that must have the target suspended when requested.
-This would make permits really harder to add.
-*/
-MonoResumeResult
-mono_threads_transition_request_resume (MonoThreadInfo* info)
-{
-       int raw_state, cur_state, suspend_count;
-       g_assert (info != mono_thread_info_current ()); //One can't self resume [3]
-
-retry_state_change:
-       UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
-       switch (cur_state) {
-       case STATE_RUNNING: //Thread already running.
-               trace_state_change ("RESUME", info, raw_state, cur_state, 0);
-               return ResumeError; //Resume failed because thread was not blocked
-
-       case STATE_ASYNC_SUSPENDED:
-       case STATE_SELF_SUSPENDED: //Decrease the suspend_count and maybe resume
-               g_assert (suspend_count > 0);
-               if (suspend_count > 1) {
-                       if (InterlockedCompareExchange (&info->thread_state, build_thread_state (cur_state, suspend_count - 1), raw_state) != raw_state)
-                                       goto retry_state_change;
-                       trace_state_change ("RESUME", info, raw_state, cur_state, -1);
-
-                       return ResumeOk; //Resume worked and there's nothing for the caller to do.
-               } else {
-                       if (InterlockedCompareExchange (&info->thread_state, STATE_RUNNING, raw_state) != raw_state)
-                               goto retry_state_change;
-                       trace_state_change ("RESUME", info, raw_state, STATE_RUNNING, -1);
-
-                       if (cur_state == STATE_ASYNC_SUSPENDED)
-                               return ResumeInitAsyncResume; //Resume worked and caller must do async resume
-                       else
-                               return ResumeInitSelfResume; //Resume worked and caller must do self resume
-               }
-
-       case STATE_SELF_SUSPEND_REQUESTED: //Self suspend was requested but another thread decided to resume it.
-       case STATE_SUSPEND_IN_PROGRESS: //Self suspend is in progress but another thread decided to resume it. [4]
-               g_assert (suspend_count > 0);
-               if (suspend_count > 1) {
-                       if (InterlockedCompareExchange (&info->thread_state, build_thread_state (cur_state, suspend_count - 1), raw_state) != raw_state)
-                                       goto retry_state_change;
-                       trace_state_change ("RESUME", info, raw_state, cur_state, -1);
-               } else {
-                       if (InterlockedCompareExchange (&info->thread_state, STATE_RUNNING, raw_state) != raw_state)
-                               goto retry_state_change;
-                       trace_state_change ("RESUME", info, raw_state, STATE_RUNNING, -1);
-               }
-               return ResumeOk; //Resume worked and there's nothing for the caller to do (the target never actually suspend).
-
-/*
-
-STATE_ASYNC_SUSPEND_REQUESTED: Only one async suspend/resume operation can be in flight, so a resume cannot witness an internal state of suspend
-STATE_SUSPEND_PROMOTED_TO_ASYNC: Only one async suspend/resume operation can be in flight, so a resume cannot witness an internal state of suspend
-
-[3] A self-resume makes no sense given it requires the thread to be running, which means its suspend count must be zero. A self resume would make
-sense as a suspend permit, but as explained in [2] we don't support it so this is a bug.
-
-[4] It's questionable on whether a resume (an async operation) should be able to cancel a self suspend. The scenario where this would happen
-is similar to the one described in [2] when this is used for as a synchronization primitive.
-
-If this turns to be a problem we should either implement [2] or make this an invalid transition.
-
-*/
-       default:
-               g_error ("Cannot transition thread %p from %s with REQUEST_RESUME", info, state_name (cur_state));
-       }
-}
-
-/*
-Last part of the self suspend protocol.
-
-This must only happens in the context of a self suspend request. This means that the thread must be on one of the
-valid self suspend states.
-
-Returns one of the following values:
-
-- Resumed: Async resume happened and current thread should keep running
-- Suspend: Caller should wait for a resume signal
-- SelfSuspendNotifyAndWait: Notify the suspend initiator and wait for a resume signals
-*/
-MonoSelfSupendResult
-mono_threads_transition_finish_self_suspend (MonoThreadInfo* info)
-{
-       int raw_state, cur_state, suspend_count;
-       g_assert (info ==  mono_thread_info_current ());
-
-retry_state_change:
-       UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
-       switch (cur_state) {
-       case STATE_RUNNING: //An async resume hit us and we should keep running
-               trace_state_change ("FINISH_SELF_SUSPEND", info, raw_state, cur_state, 0);
-               return SelfSuspendResumed; //Caller should not suspend
-
-       case STATE_SUSPEND_IN_PROGRESS: //Self suspend finished
-       case STATE_SUSPEND_PROMOTED_TO_ASYNC: //Async suspend happened during the second step of self suspend so the caller needs to notify the initiator.
-               if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_SELF_SUSPENDED, suspend_count), raw_state) != raw_state)
-                       goto retry_state_change;
-               trace_state_change ("FINISH_SELF_SUSPEND", info, raw_state, STATE_SELF_SUSPENDED, 0);
-               if (cur_state == STATE_SUSPEND_IN_PROGRESS)
-                       return SelfSuspendWait; //Caller should wait for resume
-               else
-                       return SelfSuspendNotifyAndWait; //Caller should notify suspend initiator and wait for resume
-/*
-STATE_ASYNC_SUSPENDED: Code should not be running while suspended.
-STATE_SELF_SUSPENDED: Code should not be running while suspended.
-STATE_ASYNC_SUSPEND_REQUESTED: This state should one be witnessed by the state poll transition
-STATE_SELF_SUSPEND_REQUESTED: This state should one be witnessed by the state poll transition
-*/
-       default:
-               g_error ("Cannot transition thread %p from %s with FINISH_SELF_SUSPEND", info, state_name (cur_state));
-
-       }
-}
-
-/*
-This performs the last step of async suspend.
-
-Returns TRUE if the caller should wait for resume.
-*/
-gboolean
-mono_threads_transition_finish_async_suspend (MonoThreadInfo* info)
-{
-       int raw_state, cur_state, suspend_count;
-
-retry_state_change:
-       UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
-       switch (cur_state) {
-
-       case STATE_SELF_SUSPENDED: //async suspend raced with self suspend and lost
-               trace_state_change ("FINISH_ASYNC_SUSPEND", info, raw_state, cur_state, 0);
-               return FALSE; //let self suspend wait
-
-       case STATE_ASYNC_SUSPEND_REQUESTED:
-               if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_ASYNC_SUSPENDED, suspend_count), raw_state) != raw_state)
-                       goto retry_state_change;
-               trace_state_change ("FINISH_ASYNC_SUSPEND", info, raw_state, STATE_ASYNC_SUSPENDED, 0);
-               return TRUE; //Async suspend worked, now wait for resume
-
-       case STATE_SUSPEND_IN_PROGRESS:
-               if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_SUSPEND_PROMOTED_TO_ASYNC, suspend_count), raw_state) != raw_state)
-                       goto retry_state_change;
-               trace_state_change ("FINISH_ASYNC_SUSPEND", info, raw_state, STATE_SUSPEND_PROMOTED_TO_ASYNC, 0);
-               return FALSE; //async suspend race with self suspend and lost, let the other finish it
-/*
-STATE_RUNNING: A thread cannot escape suspension once requested.
-STATE_ASYNC_SUSPENDED: There can be only one suspend initiator at a given time, meaning this state should have been visible on the first stage of suspend.
-STATE_SELF_SUSPEND_REQUESTED: When self suspend and async suspend happen together, they converge to async suspend so this state should not be visible.
-STATE_SUSPEND_PROMOTED_TO_ASYNC: Given there's a single initiator this cannot happen.
-*/
-       default:
-               g_error ("Cannot transition thread %p from %s with FINISH_ASYNC_SUSPEND", info, state_name (cur_state));
-
-       }
-}
-
-/*
-This the compensatory transition for failed async suspend.
-
-Async suspend can land on a thread as it began cleaning up and is no longer
-functional. This happens as cleanup is a racy process from the async suspend
-perspective. The thread could have cleaned up its domain or jit_tls, for example.
-
-It can only transition the state as left by a sucessfull finish async suspend transition.
-
-*/
-void
-mono_threads_transition_async_suspend_compensation (MonoThreadInfo* info)
-{
-       int raw_state, cur_state, suspend_count;
-
-retry_state_change:
-       UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
-       switch (cur_state) {
-
-       case STATE_ASYNC_SUSPENDED:
-               /*
-               Must be one since if a self suspend is in progress the thread should still be async suspendable.
-               If count > 1 and no self suspend is in progress then it means one of the following two.
-               - 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 (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);
-               break;
-/*
-STATE_RUNNING
-STATE_SELF_SUSPENDED
-STATE_ASYNC_SUSPEND_REQUESTED
-STATE_SELF_SUSPEND_REQUESTED
-STATE_SUSPEND_PROMOTED_TO_ASYNC:
-STATE_SUSPEND_IN_PROGRESS: All those are invalid end states of a sucessfull finish async suspend
-*/
-       default:
-               g_error ("Cannot transition thread %p from %s with COMPENSATE_FINISH_ASYNC_SUSPEND", info, state_name (cur_state));
-
-       }
-}
-
-
-
-
-// State checking code
-/**
- * Return TRUE is the thread is in a runnable state.
-*/
-gboolean
-mono_thread_info_is_running (MonoThreadInfo *info)
-{
-       switch (get_thread_state (info->thread_state)) {
-       case STATE_RUNNING:
-       case STATE_ASYNC_SUSPEND_REQUESTED:
-       case STATE_SELF_SUSPEND_REQUESTED:
-               return TRUE;
-       }
-       return FALSE;
-}
-
-/**
- * Return TRUE is the thread is in an usable (suspendable) state
- */
-gboolean
-mono_thread_info_is_live (MonoThreadInfo *info)
-{
-       switch (get_thread_state (info->thread_state)) {
-       case STATE_STARTING:
-       case STATE_DETACHED:
-               return FALSE;
-       }
-       return TRUE;
-}
-
-int
-mono_thread_info_suspend_count (MonoThreadInfo *info)
-{
-       return get_thread_suspend_count (info->thread_state);
-}
\ No newline at end of file
index 30cd51baa4255a8da5a6a6c86366161478efb180..02bd26e0c793988c8fc4f2d15ac766df70c5014d 100755 (executable)
@@ -27,7 +27,7 @@ interrupt_apc (ULONG_PTR param)
 }
 
 void
-mono_threads_core_abort_syscall (MonoThreadInfo *info)
+mono_threads_core_interrupt (MonoThreadInfo *info)
 {
        DWORD id = mono_thread_info_get_tid (info);
        HANDLE handle;
@@ -51,57 +51,42 @@ mono_threads_core_needs_abort_syscall (void)
        return FALSE;
 }
 
+void
+mono_threads_core_self_suspend (MonoThreadInfo *info)
+{
+       g_assert_not_reached ();
+}
+
 gboolean
-mono_threads_core_begin_async_suspend (MonoThreadInfo *info, gboolean interrupt_kernel)
+mono_threads_core_suspend (MonoThreadInfo *info, gboolean interrupt_kernel)
 {
        DWORD id = mono_thread_info_get_tid (info);
        HANDLE handle;
        DWORD result;
        gboolean res;
 
+       g_assert (id != GetCurrentThreadId ());
+
        handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id);
        g_assert (handle);
 
        result = SuspendThread (handle);
-       THREADS_SUSPEND_DEBUG ("SUSPEND %p -> %d\n", (void*)id, ret);
        if (result == (DWORD)-1) {
+               fprintf (stderr, "could not suspend thread %x (handle %p): %d\n", id, handle, GetLastError ()); fflush (stderr);
                CloseHandle (handle);
                return FALSE;
        }
 
-       /* We're in the middle of a self-suspend, resume and register */
-       if (!mono_threads_transition_finish_async_suspend (info)) {
-               mono_threads_add_to_pending_operation_set (info);
-               g_assert (ResumeThread (handle) == KERN_SUCCESS);
-               CloseHandle (handle);
-               THREADS_SUSPEND_DEBUG ("FAILSAFE RESUME/1 %p -> %d\n", (void*)id, 0);
-               //XXX interrupt_kernel doesn't make sense in this case as the target is not in a syscall
-               return TRUE;
-       }
-       res = mono_threads_get_runtime_callbacks ()->thread_state_init_from_handle (&info->suspend_state, info);
-       THREADS_SUSPEND_DEBUG ("thread state %p -> %d\n", (void*)id, res);
-       if (res) {
-               //FIXME do we need to QueueUserAPC on this case?
-               if (interrupt_kernel)
-                       QueueUserAPC ((PAPCFUNC)interrupt_apc, handle, (ULONG_PTR)NULL);
-       } else {
-               mono_threads_transition_async_suspend_compensation (info);
-               g_assert (ResumeThread (handle) == KERN_SUCCESS);
-               THREADS_SUSPEND_DEBUG ("FAILSAFE RESUME/2 %p -> %d\n", (void*)info->native_handle, 0);
-       }
-
        CloseHandle (handle);
-       return res;
-}
 
-gboolean
-mono_threads_core_check_suspend_result (MonoThreadInfo *info)
-{
+       res = mono_threads_get_runtime_callbacks ()->thread_state_init_from_handle (&info->suspend_state, info);
+       g_assert (res);
+
        return TRUE;
 }
 
 gboolean
-mono_threads_core_begin_async_resume (MonoThreadInfo *info)
+mono_threads_core_resume (MonoThreadInfo *info)
 {
        DWORD id = mono_thread_info_get_tid (info);
        HANDLE handle;
@@ -133,19 +118,17 @@ mono_threads_core_begin_async_resume (MonoThreadInfo *info)
 
                context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
                res = SetThreadContext (handle, &context);
-               if (!res) {
-                       CloseHandle (handle);
-                       return FALSE;
-               }
+               g_assert (res);
        }
 
        result = ResumeThread (handle);
+       g_assert (result != (DWORD)-1);
+
        CloseHandle (handle);
 
        return result != (DWORD)-1;
 }
 
-
 void
 mono_threads_platform_register (MonoThreadInfo *info)
 {
index b9563713c8b0f95958391c4f465118a8b134cb60..db060efe0e93f4da4d7edcbcb9367f8be1993ffc 100644 (file)
@@ -18,8 +18,6 @@
 #include <mono/utils/mono-memory-model.h>
 #include <mono/utils/mono-mmap.h>
 #include <mono/utils/atomic.h>
-#include <mono/utils/mono-time.h>
-
 
 #include <errno.h>
 
@@ -27,6 +25,9 @@
 #include <mono/utils/mach-support.h>
 #endif
 
+#define THREADS_DEBUG(...)
+//#define THREADS_DEBUG(...) g_message(__VA_ARGS__)
+
 /*
 Mutex that makes sure only a single thread can be suspending others.
 Suspend is a very racy operation since it requires restarting until
@@ -54,117 +55,11 @@ static MonoLinkedListSet thread_list;
 static gboolean disable_new_interrupt = FALSE;
 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)
-
-/*warn at 50 ms*/
-#define SLEEP_DURATION_BEFORE_WARNING (50)
-/*abort at 1 sec*/
-#define SLEEP_DURATION_BEFORE_ABORT 1000
-
-static void
-wait_for_resume (MonoThreadInfo* info)
-{
-       MONO_SEM_WAIT_UNITERRUPTIBLE (&info->resume_semaphore);
-}
-
-void
-mono_threads_notify_initiator_of_suspend (MonoThreadInfo* info)
-{
-       THREADS_SUSPEND_DEBUG ("[INITIATOR-NOTIFY-SUSPEND] %p\n", info);
-       MONO_SEM_POST (&suspend_semaphore);
-}
-
-void
-mono_threads_notify_initiator_of_resume (MonoThreadInfo* info)
-{
-       THREADS_SUSPEND_DEBUG ("[INITIATOR-NOTIFY-RESUME] %p\n", info);
-       MONO_SEM_POST (&suspend_semaphore);
-}
-
-static void
-resume_self_suspended (MonoThreadInfo* info)
-{
-       THREADS_SUSPEND_DEBUG ("begin self-resume %p\n", info);
-       MONO_SEM_POST (&info->resume_semaphore);
-}
-
-static void
-resume_async_suspended (MonoThreadInfo *info)
-{
-       g_assert (mono_threads_core_begin_async_resume (info));
-}
-
-void
-mono_threads_add_to_pending_operation_set (MonoThreadInfo* info)
-{
-       THREADS_SUSPEND_DEBUG ("added %p to pending suspend\n", info);
-       ++pending_suspends;
-}
-
-void
-mono_threads_begin_global_suspend (void)
-{
-       g_assert (pending_suspends == 0);
-       THREADS_SUSPEND_DEBUG ("------ BEGIN GLOBAL OP\n");
-}
-
-void
-mono_threads_end_global_suspend (void) 
-{
-       g_assert (pending_suspends == 0);
-       THREADS_SUSPEND_DEBUG ("------ END GLOBAL OP\n");
-}
-
-static void
-dump_threads (void)
-{
-       MonoThreadInfo *info;
-       FOREACH_THREAD_SAFE (info) {
-               THREADS_SUSPEND_DEBUG ("--thread %p id %p state %x\n", info, mono_thread_info_get_tid (info), info->thread_state);
-       } END_FOREACH_THREAD_SAFE
-}
-
-gboolean
-mono_threads_wait_pending_operations (void)
-{
-       int i;
-       int c = pending_suspends;
-
-       /* Wait threads to park */
-       if (pending_suspends) {
-               MonoStopwatch suspension_time;
-               mono_stopwatch_start (&suspension_time);
-               THREADS_SUSPEND_DEBUG ("[INITIATOR-WAIT-COUNT] %d\n", c);
-               for (i = 0; i < pending_suspends; ++i) {
-                       THREADS_SUSPEND_DEBUG ("[INITIATOR-WAIT-WAITING]\n");
-                       if (!MONO_SEM_TIMEDWAIT (&suspend_semaphore, SLEEP_DURATION_BEFORE_ABORT))
-                               continue;
-                       mono_stopwatch_stop (&suspension_time);
-
-                       dump_threads ();
-
-                       THREADS_SUSPEND_DEBUG ("WAITING for %d threads, got %d suspended\n", (int)pending_suspends, i);
-                       THREADS_SUSPEND_DEBUG ("cur thread is %p\n", pthread_self ());
-                       g_error ("suspend_thread suspend took %d ms, which is more than the allowed %d ms", (int)mono_stopwatch_elapsed_ms (&suspension_time), SLEEP_DURATION_BEFORE_ABORT);
-               }
-               mono_stopwatch_stop (&suspension_time);
-               THREADS_SUSPEND_DEBUG ("Suspending %d threads took %d ms.\n", (int)pending_suspends, (int)mono_stopwatch_elapsed_ms (&suspension_time));
-
-       }
-
-       pending_suspends = 0;
-
-       return c > 0;
-}
+static void mono_threads_unregister_current_thread (MonoThreadInfo *info);
 
+#define mono_thread_info_run_state(info) (((MonoThreadInfo*)info)->thread_state & RUN_STATE_MASK)
+#define mono_thread_info_suspend_state(info) (((MonoThreadInfo*)info)->thread_state & SUSPEND_STATE_MASK)
 
-//Thread initialization code
-
-static void mono_threads_unregister_current_thread (MonoThreadInfo *info);
 
 static inline void
 mono_hazard_pointer_clear_all (MonoThreadHazardPointers *hp, int retain)
@@ -225,7 +120,9 @@ free_thread_info (gpointer mem)
 {
        MonoThreadInfo *info = mem;
 
+       MONO_SEM_DESTROY (&info->suspend_semaphore);
        MONO_SEM_DESTROY (&info->resume_semaphore);
+       MONO_SEM_DESTROY (&info->finish_resume_semaphore);
        mono_threads_platform_free (info);
 
        g_free (info);
@@ -253,7 +150,9 @@ register_thread (MonoThreadInfo *info, gpointer baseptr)
        mono_thread_info_set_tid (info, mono_native_thread_id_get ());
        info->small_id = small_id;
 
+       MONO_SEM_INIT (&info->suspend_semaphore, 1);
        MONO_SEM_INIT (&info->resume_semaphore, 0);
+       MONO_SEM_INIT (&info->finish_resume_semaphore, 0);
 
        /*set TLS early so SMR works */
        mono_native_tls_set_value (thread_info_key, info);
@@ -275,14 +174,7 @@ register_thread (MonoThreadInfo *info, gpointer baseptr)
        info->stack_end = staddr + stsize;
 
        mono_threads_platform_register (info);
-
-       /*
-       Transition it before taking any locks or publishing itself to reduce the chance
-       of others witnessing a detached thread.
-       We can reasonably expect that until this thread gets published, no other thread will
-       try to manipulate it.
-       */
-       mono_threads_transition_attach (info);
+       info->thread_state = STATE_RUNNING;
        mono_thread_info_suspend_lock ();
        /*If this fail it means a given thread has been registered twice, which doesn't make sense. */
        result = mono_thread_info_insert (info);
@@ -312,6 +204,8 @@ unregister_thread (void *arg)
        mono_native_tls_set_value (small_id_key, GUINT_TO_POINTER (info->small_id + 1));
 #endif
 
+       info->thread_state = STATE_SHUTTING_DOWN;
+
        /*
        First perform the callback that requires no locks.
        This callback has the potential of taking other locks, so we do it before.
@@ -331,8 +225,8 @@ unregister_thread (void *arg)
        if (threads_callbacks.thread_unregister)
                threads_callbacks.thread_unregister (info);
        mono_threads_unregister_current_thread (info);
-       mono_threads_transition_detach (info);
 
+       info->thread_state = STATE_DEAD;
        mono_thread_info_suspend_unlock ();
 
        /*now it's safe to free the thread info.*/
@@ -375,13 +269,6 @@ mono_threads_unregister_current_thread (MonoThreadInfo *info)
        g_assert (result);
 }
 
-static inline MonoThreadInfo*
-mono_thread_info_current_unchecked (void)
-{
-       return (MonoThreadInfo*)mono_native_tls_get_value (thread_info_key);
-}
-
-
 MonoThreadInfo*
 mono_thread_info_current (void)
 {
@@ -531,10 +418,7 @@ mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t info_size)
 #endif
        g_assert (res);
 
-       unified_suspend_enabled = g_getenv ("MONO_ENABLE_UNIFIED_SUSPEND") != NULL;
-
        MONO_SEM_INIT (&global_suspend_semaphore, 1);
-       MONO_SEM_INIT (&suspend_semaphore, 0);
 
        mono_lls_init (&thread_list, NULL);
        mono_thread_smr_init ();
@@ -576,120 +460,115 @@ mono_thread_info_suspend_sync (MonoNativeThreadId tid, gboolean interrupt_kernel
        MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();      
        MonoThreadInfo *info = mono_thread_info_lookup (tid); /*info on HP1*/
        if (!info) {
-g_assert (pending_suspends == 0);
                *error_condition = "Thread not found";
                return NULL;
        }
 
-       g_assert (pending_suspends == 0); /* FIXME remove this assert by better delimiting global ops */
-       // MONO_SEM_WAIT_UNITERRUPTIBLE (&info->suspend_semaphore);
+       MONO_SEM_WAIT_UNITERRUPTIBLE (&info->suspend_semaphore);
 
-       if (!mono_threads_transition_request_async_suspension (info)) {
-               g_assert (pending_suspends == 0);
-               mono_hazard_pointer_clear (hp, 1); //XXX this is questionable we got to clean the suspend/resume nonsense of critical sections
-               // MONO_SEM_POST (&info->suspend_semaphore);
+       /*thread is on the process of detaching*/
+       if (mono_thread_info_run_state (info) > STATE_RUNNING) {
+               mono_hazard_pointer_clear (hp, 1);
+               *error_condition = "Thread is detaching";
+               return NULL;
+       }
+
+       THREADS_DEBUG ("suspend %x IN COUNT %d\n", tid, info->suspend_count);
+
+       if (info->suspend_count) {
+               ++info->suspend_count;
+               mono_hazard_pointer_clear (hp, 1);
+               MONO_SEM_POST (&info->suspend_semaphore);
                return info;
        }
 
-       if (!mono_threads_core_begin_async_suspend (info, interrupt_kernel)) {
-               g_assert (pending_suspends == 0);
-               // MONO_SEM_POST (&info->suspend_semaphore);
+       if (!mono_threads_core_suspend (info, interrupt_kernel)) {
+               MONO_SEM_POST (&info->suspend_semaphore);
                mono_hazard_pointer_clear (hp, 1);
                *error_condition = "Could not suspend thread";
                return NULL;
        }
 
-       //Wait for the pending suspend to finish
-       mono_threads_wait_pending_operations ();
+       if (interrupt_kernel) 
+               mono_threads_core_interrupt (info);
 
-       if (!mono_threads_core_check_suspend_result (info)) {
-               g_assert (pending_suspends == 0);
+       ++info->suspend_count;
+       info->thread_state |= STATE_SUSPENDED;
+       MONO_SEM_POST (&info->suspend_semaphore);
 
-               mono_hazard_pointer_clear (hp, 1);
-               *error_condition = "Post suspend failed";
-               return NULL;
-       }
-       // MONO_SEM_POST (&info->suspend_semaphore);
        return info;
 }
 
-/*
-Signal that the current thread wants to be suspended.
-This function can be called without holding the suspend lock held.
-To finish suspending, call mono_suspend_check.
-*/
 void
-mono_thread_info_begin_self_suspend (void)
+mono_thread_info_self_suspend (void)
 {
-       MonoThreadInfo *info = mono_thread_info_current_unchecked ();
+       gboolean ret;
+       MonoThreadInfo *info = mono_thread_info_current ();
        if (!info)
                return;
 
-       THREADS_SUSPEND_DEBUG ("BEGIN SELF SUSPEND OF %p\n", info);
-       mono_threads_transition_request_self_suspension (info);
-}
+       MONO_SEM_WAIT_UNITERRUPTIBLE (&info->suspend_semaphore);
 
-void
-mono_thread_info_end_self_suspend (void)
-{
-       MonoThreadInfo *info;
+       THREADS_DEBUG ("self suspend IN COUNT %d\n", info->suspend_count);
 
-       info = mono_thread_info_current ();
-       if (!info)
-               return;
-       THREADS_SUSPEND_DEBUG ("FINISH SELF SUSPEND OF %p\n", info);
+       g_assert (info->suspend_count == 0);
+       ++info->suspend_count;
 
-       /* Begin stage two which allows us to save our state */
-       if (!mono_threads_transition_state_poll (info))
-               return;
+       info->thread_state |= STATE_SELF_SUSPENDED;
 
-       g_assert (mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (&info->suspend_state, NULL));
+       ret = mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (&info->suspend_state, NULL);
+       g_assert (ret);
 
-       /* commit the saved state and notify others if needed */
-       switch (mono_threads_transition_finish_self_suspend (info)) {
-       case SelfSuspendResumed:
-               return;
-       case SelfSuspendWait:
-               wait_for_resume (info);
-               break;
-       case SelfSuspendNotifyAndWait:
-               mono_threads_notify_initiator_of_suspend (info);
-               wait_for_resume (info);
-               mono_threads_notify_initiator_of_resume (info);
-               break;
-       }
+       MONO_SEM_POST (&info->suspend_semaphore);
+
+       MONO_SEM_WAIT_UNITERRUPTIBLE (&info->resume_semaphore);
+
+       g_assert (!info->async_target); /*FIXME this should happen normally for suspend. */
+       MONO_SEM_POST (&info->finish_resume_semaphore);
 }
 
 static gboolean
 mono_thread_info_core_resume (MonoThreadInfo *info)
 {
-       gboolean res = FALSE;
+       gboolean result;
+       MonoNativeThreadId tid = mono_thread_info_get_tid (info);
        if (info->create_suspended) {
-               MonoNativeThreadId tid = mono_thread_info_get_tid (info);
                /* Have to special case this, as the normal suspend/resume pair are racy, they don't work if he resume is received before the suspend */
                info->create_suspended = FALSE;
                mono_threads_core_resume_created (info, tid);
                return TRUE;
        }
 
-       switch (mono_threads_transition_request_resume (info)) {
-       case ResumeError:
-               res = FALSE;
-               break;
-       case ResumeOk:
-               res = TRUE;
-               break;
-       case ResumeInitSelfResume:
-               resume_self_suspended (info);
-               res = TRUE;
-               break;
-       case ResumeInitAsyncResume:
-               resume_async_suspended (info);
-               res = TRUE;
-               break;
+       MONO_SEM_WAIT_UNITERRUPTIBLE (&info->suspend_semaphore);
+
+       THREADS_DEBUG ("resume %x IN COUNT %d\n", tid, info->suspend_count);
+
+       if (info->suspend_count <= 0) {
+               MONO_SEM_POST (&info->suspend_semaphore);
+               return FALSE;
        }
 
-       return res;
+       /*
+        * The theory here is that if we manage to suspend the thread it means it did not
+        * start cleanup since it take the same lock. 
+       */
+       g_assert (mono_thread_info_get_tid (info));
+
+       if (--info->suspend_count == 0) {
+               if (mono_thread_info_suspend_state (info) == STATE_SELF_SUSPENDED) {
+                       MONO_SEM_POST (&info->resume_semaphore);
+                       MONO_SEM_WAIT_UNITERRUPTIBLE (&info->finish_resume_semaphore);
+                       result = TRUE;
+               } else {
+                       result = mono_threads_core_resume (info);
+               }
+               info->thread_state &= ~SUSPEND_STATE_MASK;
+       } else {
+               result = TRUE;
+       }
+
+       MONO_SEM_POST (&info->suspend_semaphore);
+       return result;
 }
 
 gboolean
@@ -697,53 +576,22 @@ mono_thread_info_resume (MonoNativeThreadId tid)
 {
        gboolean result; /* don't initialize it so the compiler can catch unitilized paths. */
        MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
-       MonoThreadInfo *info;
-
-       THREADS_SUSPEND_DEBUG ("RESUMING tid %p\n", (void*)tid);
-
-
-       mono_thread_info_suspend_lock ();
+       MonoThreadInfo *info = mono_thread_info_lookup (tid); /*info on HP1*/
 
-       g_assert (pending_suspends == 0);
-       info = mono_thread_info_lookup (tid); /*info on HP1*/
        if (!info) {
                result = FALSE;
                goto cleanup;
        }
-
        result = mono_thread_info_core_resume (info);
 
-       //Wait for the pending resume to finish
-       mono_threads_wait_pending_operations ();
-
 cleanup:
-       mono_thread_info_suspend_unlock ();
        mono_hazard_pointer_clear (hp, 1);
-       g_assert (pending_suspends == 0);
        return result;
 }
 
-gboolean
-mono_thread_info_begin_suspend (MonoThreadInfo *info, gboolean interrupt_kernel)
-{
-       gboolean res;
-       if (!mono_threads_transition_request_async_suspension (info))
-               return TRUE; //already suspended
-
-       res = mono_threads_core_begin_async_suspend (info, interrupt_kernel);
-       return res;
-}
-
-gboolean
-mono_thread_info_begin_resume (MonoThreadInfo *info)
-{
-       return mono_thread_info_core_resume (info);
-}
-
 void
 mono_thread_info_finish_suspend (MonoThreadInfo *info)
 {
-g_assert (pending_suspends == 0);
        mono_atomic_store_release (&mono_thread_info_current ()->inside_critical_region, FALSE);
 }
 
@@ -752,22 +600,12 @@ mono_thread_info_finish_suspend_and_resume (MonoThreadInfo *info)
 {
        MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
 
-       mono_thread_info_suspend_lock ();
-
-g_assert (pending_suspends == 0);
        /*Resume can access info after the target has resumed, so we must ensure it won't touch freed memory. */
        mono_hazard_pointer_set (hp, 1, info);
        mono_thread_info_core_resume (info);
        mono_hazard_pointer_clear (hp, 1);
 
-       //Wait for the pending resume to finish
-       mono_threads_wait_pending_operations ();
-
-g_assert (pending_suspends == 0);
-
        mono_atomic_store_release (&mono_thread_info_current ()->inside_critical_region, FALSE);
-
-       mono_thread_info_suspend_unlock ();
 }
 
 /*
@@ -785,10 +623,6 @@ is_thread_in_critical_region (MonoThreadInfo *info)
        if (info->inside_critical_region)
                return TRUE;
 
-       if (threads_callbacks.mono_thread_in_critical_region && threads_callbacks.mono_thread_in_critical_region (info)) {
-               return TRUE;
-       }
-
        /* Are we inside a GC critical region? */
        if (threads_callbacks.mono_thread_in_critical_region && threads_callbacks.mono_thread_in_critical_region (info)) {
                return TRUE;
@@ -815,12 +649,6 @@ is_thread_in_critical_region (MonoThreadInfo *info)
        return threads_callbacks.mono_method_is_critical (method);
 }
 
-gboolean
-mono_thread_info_in_critical_location (MonoThreadInfo *info)
-{
-       return is_thread_in_critical_region (info);
-}
-
 /*
 WARNING:
 If we are trying to suspend a target that is on a critical region
@@ -837,34 +665,29 @@ mono_thread_info_safe_suspend_sync (MonoNativeThreadId id, gboolean interrupt_ke
        MonoThreadInfo *info = NULL;
        int sleep_duration = 0;
 
-       THREADS_SUSPEND_DEBUG ("SUSPENDING tid %p\n", (void*)id);
        /*FIXME: unify this with self-suspend*/
        g_assert (id != mono_native_thread_id_get ());
 
        mono_thread_info_suspend_lock ();
-       mono_threads_begin_global_suspend ();
 
        for (;;) {
                const char *suspend_error = "Unknown error";
                if (!(info = mono_thread_info_suspend_sync (id, interrupt_kernel, &suspend_error))) {
-                       g_assert (pending_suspends == 0);
-                       goto fail;
+                       // g_warning ("failed to suspend thread %p due to %s, hopefully it is dead", (gpointer)id, suspend_error);
+                       mono_thread_info_suspend_unlock ();
+                       return NULL;
                }
-
                /*WARNING: We now are in interrupt context until we resume the thread. */
                if (!is_thread_in_critical_region (info))
                        break;
 
                if (!mono_thread_info_core_resume (info)) {
-                       g_assert (pending_suspends == 0);
+                       // g_warning ("failed to resume thread %p, hopefully it is dead", (gpointer)id);
                        mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
                        mono_thread_info_suspend_unlock ();
-                       goto fail;
+                       return NULL;
                }
-               THREADS_SUSPEND_DEBUG ("RESTARTED thread tid %p\n", (void*)id);
-
-               /* Wait for the pending resume to finish */
-               mono_threads_wait_pending_operations ();
+               THREADS_DEBUG ("restarted thread %p\n", (gpointer)id);
 
                if (!sleep_duration) {
 #ifdef HOST_WIN32
@@ -881,14 +704,9 @@ mono_thread_info_safe_suspend_sync (MonoNativeThreadId id, gboolean interrupt_ke
 
        /* XXX this clears HP 1, so we restated it again */
        mono_atomic_store_release (&mono_thread_info_current ()->inside_critical_region, TRUE);
-       mono_threads_end_global_suspend ();
        mono_thread_info_suspend_unlock ();
 
        return info;
-fail:
-       mono_threads_end_global_suspend ();
-       mono_thread_info_suspend_unlock ();
-       return NULL;
 }
 
 /**
@@ -901,8 +719,7 @@ currently used only to deliver exceptions.
 void
 mono_thread_info_setup_async_call (MonoThreadInfo *info, void (*target_func)(void*), void *user_data)
 {
-       /* An async call can only be setup on an async suspended thread */
-       g_assert (mono_thread_info_run_state (info) == STATE_ASYNC_SUSPENDED);
+       g_assert (info->suspend_count);
        /*FIXME this is a bad assert, we probably should do proper locking and fail if one is already set*/
        g_assert (!info->async_target);
        info->async_target = target_func;
@@ -970,12 +787,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;
-}
-
 /*
 Disabled by default for now.
 To enable this we need mini to implement the callbacks by MonoThreadInfoRuntimeCallbacks
@@ -1190,3 +1001,13 @@ mono_threads_consume_async_jobs (void)
 
        return InterlockedExchange (&info->service_requests, 0);
 }
+
+
+/**
+ * Return TRUE is the thread is in an usable (suspendable) state
+ */
+gboolean
+mono_thread_info_is_live (MonoThreadInfo *info)
+{
+       return mono_thread_info_run_state (info) == STATE_RUNNING;
+}
index 3477f2840d0839f587a62843d9bb8993a081a565..f4d468f76ade96214b5d8ac8c366882298654907 100644 (file)
@@ -82,69 +82,16 @@ and reduce the number of casts drastically.
 #define THREAD_INFO_TYPE MonoThreadInfo
 #endif
 
-/* Mono Threads internal configuration knows*/
-
-/* Logging - enable them below if you need specific logging for the category you need */
-#define MOSTLY_ASYNC_SAFE_PRINTF(...) do { \
-       char __buff[1024];      __buff [0] = '\0'; \
-       snprintf (__buff, sizeof (__buff), __VA_ARGS__);        \
-       write (1, __buff, strlen (__buff));     \
-} while (0)
-
-
-#if 1
-#define THREADS_DEBUG(...)
-#else
-#define THREADS_DEBUG MOSTLY_ASYNC_SAFE_PRINTF
-#endif
-
-#if 1
-#define THREADS_STW_DEBUG(...)
-#else
-#define THREADS_STW_DEBUG MOSTLY_ASYNC_SAFE_PRINTF
-#endif
-
-#if 1
-#define THREADS_SUSPEND_DEBUG(...)
-#else
-#define THREADS_SUSPEND_DEBUG MOSTLY_ASYNC_SAFE_PRINTF
-#endif
-
-#if 1
-#define THREADS_STATE_MACHINE_DEBUG(...)
-#else
-#define THREADS_STATE_MACHINE_DEBUG MOSTLY_ASYNC_SAFE_PRINTF
-#endif
-
-/* If this is defined, use the signals backed on Mach. Debug only as signals can't be made usable on OSX. */
-// #define USE_SIGNALS_ON_MACH
-
-#if defined (_POSIX_VERSION) || defined (__native_client__)
-#if defined (__MACH__) && !defined (USE_SIGNALS_ON_MACH)
-#define USE_MACH_BACKEND
-#else
-#define USE_POSIX_BACKEND
-#endif
-#endif
-
-
 enum {
-       STATE_STARTING                          = 0x00,
-       STATE_RUNNING                           = 0x01,
-       STATE_DETACHED                          = 0x02,
-
-       STATE_ASYNC_SUSPENDED                   = 0x03,
-       STATE_SELF_SUSPENDED                    = 0x04,
-       STATE_ASYNC_SUSPEND_REQUESTED   = 0x05,
-       STATE_SELF_SUSPEND_REQUESTED    = 0x06,
-       STATE_SUSPEND_IN_PROGRESS               = 0x07,
-       STATE_SUSPEND_PROMOTED_TO_ASYNC = 0x08,
-       STATE_MAX                                               = 0x08,
-
-       THREAD_STATE_MASK                       = 0x00FF,
-       THREAD_SUSPEND_COUNT_MASK       = 0xFF00,
-       THREAD_SUSPEND_COUNT_SHIFT      = 8,
-       THREAD_SUSPEND_COUNT_MAX        = 0xFF
+       STATE_STARTING                  = 0x00,
+       STATE_RUNNING                   = 0x01,
+       STATE_SHUTTING_DOWN             = 0x02,
+       STATE_DEAD                              = 0x03,
+       RUN_STATE_MASK                  = 0x0F,
+
+       STATE_SUSPENDED                 = 0x10,
+       STATE_SELF_SUSPENDED    = 0x20,
+       SUSPEND_STATE_MASK              = 0xF0,
 };
 
 /*
@@ -173,16 +120,14 @@ typedef struct {
        MonoSemType suspend_semaphore;
        int suspend_count;
 
-       // MonoSemType suspend_semaphore;
-       MonoSemType resume_semaphore;
+       MonoSemType finish_resume_semaphore;
+       MonoSemType resume_semaphore; 
 
        /* only needed by the posix backend */ 
-#if defined(USE_POSIX_BACKEND)
-       MonoSemType finish_resume_semaphore;
+#if (defined(_POSIX_VERSION) || defined(__native_client__)) && !defined (__MACH__)
+       MonoSemType begin_suspend_semaphore;
        gboolean syscall_break_signal;
        gboolean suspend_can_continue;
-       int signal;
-
 #endif
 
        /*In theory, only the posix backend needs this, but having it on mach/win32 simplifies things a lot.*/
@@ -335,21 +280,12 @@ mono_thread_info_finish_suspend (MonoThreadInfo *info) MONO_INTERNAL;
 void
 mono_thread_info_finish_suspend_and_resume (MonoThreadInfo *info) MONO_INTERNAL;
 
-//XXX new API, fix the world
-void
-mono_thread_info_begin_self_suspend (void) MONO_INTERNAL;
-
 void
-mono_thread_info_end_self_suspend (void) MONO_INTERNAL;
-
-//END of new API
+mono_thread_info_self_suspend (void) MONO_INTERNAL;
 
 gboolean
 mono_thread_info_new_interrupt_enabled (void) MONO_INTERNAL;
 
-gboolean
-mono_thread_info_unified_management_enabled (void) MONO_INTERNAL;
-
 void
 mono_thread_info_setup_async_call (THREAD_INFO_TYPE *info, void (*target_func)(void*), void *user_data) MONO_INTERNAL;
 
@@ -439,46 +375,13 @@ mono_threads_pthread_kill (THREAD_INFO_TYPE *info, int signum) MONO_INTERNAL;
 
 #endif /* !defined(HOST_WIN32) */
 
-
-/* Internal API between mono-threads and its backends. */
-
-/* Backend functions - a backend must implement all of the following */
-/*
-This is called very early in the runtime, it cannot access any runtime facilities.
-
-*/
+/* Plartform specific functions DON'T use them */
 void mono_threads_init_platform (void) MONO_INTERNAL; //ok
-
-/*
-This begins async suspend. This function must do the following:
-
--Ensure the target will EINTR any syscalls if @interrupt_kernel is true
--Call mono_threads_transition_finish_async_suspend as part of its async suspend.
--Register the thread for pending suspend with mono_threads_add_to_pending_operation_set if needed.
-
-If begin suspend fails the thread must be left uninterrupted and resumed.
-*/
-gboolean mono_threads_core_begin_async_suspend (THREAD_INFO_TYPE *info, gboolean interrupt_kernel) MONO_INTERNAL;
-
-/*
-This verifies the outcome of an async suspend operation.
-
-Some targets, such as posix, verify suspend results assynchronously. Suspend results must be
-available (in a non blocking way) after mono_threads_wait_pending_operations completes.
-*/
-gboolean mono_threads_core_check_suspend_result (THREAD_INFO_TYPE *info) MONO_INTERNAL;
-
-/*
-This begins async resume. This function must do the following:
-
-- Install an async target if one was requested.
-- Notify the target to resume.
-- Register the thread for pending ack with mono_threads_add_to_pending_operation_set if needed.
-*/
-gboolean mono_threads_core_begin_async_resume (THREAD_INFO_TYPE *info) MONO_INTERNAL;
-
+gboolean mono_threads_core_suspend (THREAD_INFO_TYPE *info, gboolean interrupt_kernel) MONO_INTERNAL;
+gboolean mono_threads_core_resume (THREAD_INFO_TYPE *info) MONO_INTERNAL;
 void mono_threads_platform_register (THREAD_INFO_TYPE *info) MONO_INTERNAL; //ok
 void mono_threads_platform_free (THREAD_INFO_TYPE *info) MONO_INTERNAL;
+void mono_threads_core_interrupt (THREAD_INFO_TYPE *info) MONO_INTERNAL;
 void mono_threads_core_abort_syscall (THREAD_INFO_TYPE *info) MONO_INTERNAL;
 gboolean mono_threads_core_needs_abort_syscall (void) MONO_INTERNAL;
 HANDLE mono_threads_core_create_thread (LPTHREAD_START_ROUTINE start, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid) MONO_INTERNAL;
@@ -506,54 +409,4 @@ mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
 void mono_threads_init_dead_letter (void) MONO_INTERNAL;
 void mono_threads_install_dead_letter (void) MONO_INTERNAL;
 
-/* mono-threads internal API used by the backends. */
-/*
-This tells the suspend initiator that we completed suspend and will now be waiting for resume.
-*/
-void mono_threads_notify_initiator_of_suspend (THREAD_INFO_TYPE* info) MONO_INTERNAL;
-/*
-This tells the resume initiator that we completed resume duties and will return to runnable state.
-*/
-void mono_threads_notify_initiator_of_resume (THREAD_INFO_TYPE* info) MONO_INTERNAL;
-
-/* Thread state machine functions */
-
-typedef enum {
-       ResumeError,
-       ResumeOk,
-       ResumeInitSelfResume,
-       ResumeInitAsyncResume,
-} MonoResumeResult;
-
-typedef enum {
-       SelfSuspendResumed,
-       SelfSuspendWait,
-       SelfSuspendNotifyAndWait,
-} MonoSelfSupendResult;
-
-void mono_threads_transition_attach (THREAD_INFO_TYPE* info) MONO_INTERNAL;
-gboolean mono_threads_transition_detach (THREAD_INFO_TYPE *info) MONO_INTERNAL;
-void mono_threads_transition_request_self_suspension (THREAD_INFO_TYPE *info) MONO_INTERNAL;
-gboolean mono_threads_transition_request_async_suspension (THREAD_INFO_TYPE *info) MONO_INTERNAL;
-gboolean mono_threads_transition_state_poll (THREAD_INFO_TYPE *info) MONO_INTERNAL;
-MonoResumeResult mono_threads_transition_request_resume (THREAD_INFO_TYPE* info) MONO_INTERNAL;
-MonoSelfSupendResult mono_threads_transition_finish_self_suspend (THREAD_INFO_TYPE* info) MONO_INTERNAL;
-gboolean mono_threads_transition_finish_async_suspend (THREAD_INFO_TYPE* info) MONO_INTERNAL;
-void mono_threads_transition_async_suspend_compensation (MonoThreadInfo* info) MONO_INTERNAL;
-
-
-/* Advanced suspend API, used for suspending multiple threads as once. */
-gboolean mono_thread_info_is_running (THREAD_INFO_TYPE *info) MONO_INTERNAL;
-gboolean mono_thread_info_is_live (THREAD_INFO_TYPE *info) MONO_INTERNAL;
-int mono_thread_info_suspend_count (THREAD_INFO_TYPE *info) MONO_INTERNAL;
-gboolean mono_thread_info_in_critical_location (THREAD_INFO_TYPE *info) MONO_INTERNAL;
-gboolean mono_thread_info_begin_suspend (THREAD_INFO_TYPE *info, gboolean interrupt_kernel) MONO_INTERNAL;
-gboolean mono_thread_info_begin_resume (THREAD_INFO_TYPE *info) MONO_INTERNAL;
-
-
-void mono_threads_add_to_pending_operation_set (THREAD_INFO_TYPE* info) MONO_INTERNAL; //XXX rename to something to reflect the fact that this is used for both suspend and resume
-gboolean mono_threads_wait_pending_operations (void) MONO_INTERNAL;
-void mono_threads_begin_global_suspend (void) MONO_INTERNAL;
-void mono_threads_end_global_suspend (void) MONO_INTERNAL;
-
 #endif /* __MONO_THREADS_H__ */