/*
- * sgen-os-posix.c: Simple generational GC.
+ * sgen-os-posix.c: Posix support.
*
* Author:
* Paolo Molaro (lupus@ximian.com)
* 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"
#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;
#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. */
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.
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;
}
}
}
-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)
{
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;
}
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 {
sgen_wait_for_suspend_ack (count);
+ SGEN_LOG (4, "%s handshake for %d threads\n", suspend ? "suspend" : "resume", count);
+
return count;
}
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");
}
{
return suspend_signal_num;
}
+
+int
+mono_gc_get_restart_signal (void)
+{
+ return restart_signal_num;
+}
#endif
#endif