[arm64] Allow v8..v15 in unwind info on arm64. Fixes part of #21615.
[mono.git] / mono / metadata / sgen-os-posix.c
index 1b1f2a5641942064cbc65318ce22ae24a8fdc474..909b8382c81e2863355d1f1f5e4c3c50a40b032f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * sgen-os-posix.c: Simple generational GC.
+ * sgen-os-posix.c: Posix support.
  *
  * Author:
  *     Paolo Molaro (lupus@ximian.com)
@@ -7,25 +7,20 @@
  *     Geoff Norton (gnorton@novell.com)
  *
  * Copyright 2010 Novell, Inc (http://www.novell.com)
+ * Copyright (C) 2012 Xamarin Inc
  *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- * 
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * 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"
@@ -39,8 +34,9 @@
 #include "metadata/gc-internal.h"
 #include "metadata/sgen-archdep.h"
 #include "metadata/object-internals.h"
+#include "utils/mono-signal-handler.h"
 
-#if defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__)
+#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;
@@ -62,17 +58,14 @@ suspend_thread (SgenThreadInfo *info, void *context)
 #endif
        gpointer stack_start;
 
-       g_assert (info->doing_handshake);
-
        info->stopped_domain = mono_domain_get ();
        info->stopped_ip = context ? (gpointer) ARCH_SIGCTX_IP (context) : NULL;
+       info->signal = 0;
        stop_count = sgen_global_stop_count;
        /* duplicate signal */
        if (0 && info->stop_count == stop_count)
                return;
 
-       sgen_fill_thread_info_for_suspend (info);
-
        stack_start = context ? (char*) ARCH_SIGCTX_SP (context) - REDZONE_SIZE : NULL;
        /* If stack_start is not within the limits, then don't set it
           in info and we will be restarted. */
@@ -101,7 +94,7 @@ suspend_thread (SgenThreadInfo *info, void *context)
        if (mono_gc_get_gc_callbacks ()->thread_suspend_func)
                mono_gc_get_gc_callbacks ()->thread_suspend_func (info->runtime_data, context, NULL);
 
-       DEBUG (4, fprintf (gc_debug_file, "Posting suspend_ack_semaphore for suspend from %p %p\n", info, (gpointer)mono_native_thread_id_get ()));
+       SGEN_LOG (4, "Posting suspend_ack_semaphore for suspend from %p %p", info, (gpointer)mono_native_thread_id_get ());
 
        /*
        Block the restart signal. 
@@ -118,60 +111,46 @@ suspend_thread (SgenThreadInfo *info, void *context)
        do {
                info->signal = 0;
                sigsuspend (&suspend_signal_mask);
-       } while (info->signal != restart_signal_num && info->doing_handshake);
+       } while (info->signal != restart_signal_num);
 
        /* Unblock the restart signal. */
        pthread_sigmask (SIG_UNBLOCK, &suspend_ack_signal_mask, NULL);
 
-       DEBUG (4, fprintf (gc_debug_file, "Posting suspend_ack_semaphore for resume from %p %p\n", info, (gpointer)mono_native_thread_id_get ()));
+       SGEN_LOG (4, "Posting suspend_ack_semaphore for resume from %p %p\n", info, (gpointer)mono_native_thread_id_get ());
        /* notify the waiting thread */
        MONO_SEM_POST (suspend_ack_semaphore_ptr);
 }
 
 /* LOCKING: assumes the GC lock is held (by the stopping thread) */
-static void
-suspend_handler (int sig, siginfo_t *siginfo, void *context)
+MONO_SIGNAL_HANDLER_FUNC (static, suspend_handler, (int sig, siginfo_t *siginfo, void *context))
 {
+       /*
+        * 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 ();
 
        info = mono_thread_info_current ();
+       suspend_thread (info, context);
 
-       if (info) {
-               suspend_thread (info, context);
-       } else {
-               /* This can happen while a thread is dying */
-               //g_print ("no thread info in suspend\n");
-       }
-
+       mono_hazard_pointer_restore_for_signal_handler (hp_save_index);
        errno = old_errno;
 }
 
-static void
-restart_handler (int sig)
+MONO_SIGNAL_HANDLER_FUNC (static, restart_handler, (int sig))
 {
        SgenThreadInfo *info;
        int old_errno = errno;
 
        info = mono_thread_info_current ();
-       /*
-       If the thread info is null is means we're currently in the process of cleaning up,
-       the pthread destructor has already kicked in and it has explicitly invoked the suspend handler.
-       
-       This means this thread has been suspended, TLS is dead, so the only option we have is to
-       rely on pthread_self () and seatch over the thread list.
-       */
-       if (!info)
-               info = (SgenThreadInfo*)mono_thread_info_lookup (pthread_self ());
-
-       /*
-        * If a thread is dying there might be no thread info.  In
-        * that case we rely on info->doing_handshake.
-        */
-       if (info) {
-               info->signal = restart_signal_num;
-               DEBUG (4, fprintf (gc_debug_file, "Restart handler in %p %p\n", info, (gpointer)mono_native_thread_id_get ()));
-       }
+       info->signal = restart_signal_num;
+       SGEN_LOG (4, "Restart handler in %p %p", info, (gpointer)mono_native_thread_id_get ());
        errno = old_errno;
 }
 
@@ -201,16 +180,6 @@ sgen_wait_for_suspend_ack (int count)
        }
 }
 
-gboolean
-sgen_park_current_thread_if_doing_handshake (SgenThreadInfo *p)
-{
-    if (!p->doing_handshake)
-           return FALSE;
-
-    suspend_thread (p, NULL);
-    return TRUE;
-}
-
 int
 sgen_thread_handshake (BOOL suspend)
 {
@@ -222,9 +191,6 @@ sgen_thread_handshake (BOOL suspend)
 
        count = 0;
        FOREACH_THREAD_SAFE (info) {
-               if (info->joined_stw == suspend)
-                       continue;
-               info->joined_stw = suspend;
                if (mono_native_thread_id_equals (mono_thread_info_get_tid (info), me)) {
                        continue;
                }
@@ -232,14 +198,7 @@ sgen_thread_handshake (BOOL suspend)
                        continue;
                /*if (signum == suspend_signal_num && info->stop_count == global_stop_count)
                        continue;*/
-               if (suspend) {
-                       g_assert (!info->doing_handshake);
-                       info->doing_handshake = TRUE;
-               } else {
-                       g_assert (info->doing_handshake);
-                       info->doing_handshake = FALSE;
-               }
-               result = pthread_kill (mono_thread_info_get_tid (info), signum);
+               result = mono_threads_pthread_kill (info, signum);
                if (result == 0) {
                        count++;
                } else {
@@ -249,6 +208,8 @@ sgen_thread_handshake (BOOL suspend)
 
        sgen_wait_for_suspend_ack (count);
 
+       SGEN_LOG (4, "%s handshake for %d threads\n", suspend ? "suspend" : "resume", count);
+
        return count;
 }
 
@@ -267,7 +228,7 @@ sgen_os_init (void)
                g_error ("failed sigaction");
        }
 
-       sinfo.sa_handler = restart_handler;
+       sinfo.sa_handler = (void*) restart_handler;
        if (sigaction (restart_signal_num, &sinfo, NULL) != 0) {
                g_error ("failed sigaction");
        }
@@ -285,5 +246,11 @@ mono_gc_get_suspend_signal (void)
 {
        return suspend_signal_num;
 }
+
+int
+mono_gc_get_restart_signal (void)
+{
+       return restart_signal_num;
+}
 #endif
 #endif