2 * sgen-os-posix.c: Posix support.
5 * Paolo Molaro (lupus@ximian.com)
6 * Mark Probst (mprobst@novell.com)
7 * Geoff Norton (gnorton@novell.com)
9 * Copyright 2010 Novell, Inc (http://www.novell.com)
10 * Copyright (C) 2012 Xamarin Inc
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public
14 * License 2.0 as published by the Free Software Foundation;
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Library General Public License for more details.
21 * You should have received a copy of the GNU Library General Public
22 * License 2.0 along with this library; if not, write to the Free
23 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #if !defined(__MACH__) && !MONO_MACH_ARCH_SUPPORTED && defined(HAVE_PTHREAD_KILL)
33 #include "metadata/sgen-gc.h"
34 #include "metadata/gc-internal.h"
35 #include "metadata/sgen-archdep.h"
36 #include "metadata/object-internals.h"
37 #include "utils/mono-signal-handler.h"
39 #if defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
40 const static int suspend_signal_num = SIGXFSZ;
42 const static int suspend_signal_num = SIGPWR;
44 const static int restart_signal_num = SIGXCPU;
46 static MonoSemType suspend_ack_semaphore;
47 static MonoSemType *suspend_ack_semaphore_ptr;
49 static sigset_t suspend_signal_mask;
50 static sigset_t suspend_ack_signal_mask;
53 suspend_thread (SgenThreadInfo *info, void *context)
57 gpointer regs [ARCH_NUM_REGS];
61 info->stopped_domain = mono_domain_get ();
62 info->stopped_ip = context ? (gpointer) ARCH_SIGCTX_IP (context) : NULL;
64 stop_count = sgen_global_stop_count;
65 /* duplicate signal */
66 if (0 && info->stop_count == stop_count)
69 stack_start = context ? (char*) ARCH_SIGCTX_SP (context) - REDZONE_SIZE : NULL;
70 /* If stack_start is not within the limits, then don't set it
71 in info and we will be restarted. */
72 if (stack_start >= info->stack_start_limit && info->stack_start <= info->stack_end) {
73 info->stack_start = stack_start;
77 mono_sigctx_to_monoctx (context, &info->ctx);
79 memset (&info->ctx, 0, sizeof (MonoContext));
83 ARCH_COPY_SIGCTX_REGS (regs, context);
84 memcpy (&info->regs, regs, sizeof (info->regs));
86 memset (&info->regs, 0, sizeof (info->regs));
90 g_assert (!info->stack_start);
94 if (mono_gc_get_gc_callbacks ()->thread_suspend_func)
95 mono_gc_get_gc_callbacks ()->thread_suspend_func (info->runtime_data, context, NULL);
97 SGEN_LOG (4, "Posting suspend_ack_semaphore for suspend from %p %p", info, (gpointer)mono_native_thread_id_get ());
100 Block the restart signal.
101 We need to block the restart signal while posting to the suspend_ack semaphore or we race to sigsuspend,
102 which might miss the signal and get stuck.
104 pthread_sigmask (SIG_BLOCK, &suspend_ack_signal_mask, NULL);
106 /* notify the waiting thread */
107 MONO_SEM_POST (suspend_ack_semaphore_ptr);
108 info->stop_count = stop_count;
110 /* wait until we receive the restart signal */
113 sigsuspend (&suspend_signal_mask);
114 } while (info->signal != restart_signal_num);
116 /* Unblock the restart signal. */
117 pthread_sigmask (SIG_UNBLOCK, &suspend_ack_signal_mask, NULL);
119 SGEN_LOG (4, "Posting suspend_ack_semaphore for resume from %p %p\n", info, (gpointer)mono_native_thread_id_get ());
120 /* notify the waiting thread */
121 MONO_SEM_POST (suspend_ack_semaphore_ptr);
124 /* LOCKING: assumes the GC lock is held (by the stopping thread) */
125 MONO_SIGNAL_HANDLER_FUNC (static, suspend_handler, (int sig, siginfo_t *siginfo, void *context))
128 * The suspend signal handler potentially uses syscalls that
129 * can set errno, and it calls functions that use the hazard
130 * pointer machinery. Since we're interrupting other code we
131 * must restore those to the values they had when we
135 SgenThreadInfo *info;
136 int old_errno = errno;
137 int hp_save_index = mono_hazard_pointer_save_for_signal_handler ();
139 info = mono_thread_info_current ();
140 suspend_thread (info, context);
142 mono_hazard_pointer_restore_for_signal_handler (hp_save_index);
146 MONO_SIGNAL_HANDLER_FUNC (static, restart_handler, (int sig))
148 SgenThreadInfo *info;
149 int old_errno = errno;
151 info = mono_thread_info_current ();
152 info->signal = restart_signal_num;
153 SGEN_LOG (4, "Restart handler in %p %p", info, (gpointer)mono_native_thread_id_get ());
158 sgen_resume_thread (SgenThreadInfo *info)
160 return mono_threads_pthread_kill (info, restart_signal_num) == 0;
164 sgen_suspend_thread (SgenThreadInfo *info)
166 return mono_threads_pthread_kill (info, suspend_signal_num) == 0;
170 sgen_wait_for_suspend_ack (int count)
174 for (i = 0; i < count; ++i) {
175 while ((result = MONO_SEM_WAIT (suspend_ack_semaphore_ptr)) != 0) {
176 if (errno != EINTR) {
177 g_error ("MONO_SEM_WAIT FAILED with %d errno %d (%s)", result, errno, strerror (errno));
184 sgen_thread_handshake (BOOL suspend)
187 SgenThreadInfo *info;
188 int signum = suspend ? suspend_signal_num : restart_signal_num;
190 MonoNativeThreadId me = mono_native_thread_id_get ();
193 FOREACH_THREAD_SAFE (info) {
194 if (mono_native_thread_id_equals (mono_thread_info_get_tid (info), me)) {
197 if (info->gc_disabled)
199 /*if (signum == suspend_signal_num && info->stop_count == global_stop_count)
201 result = mono_threads_pthread_kill (info, signum);
207 } END_FOREACH_THREAD_SAFE
209 sgen_wait_for_suspend_ack (count);
211 SGEN_LOG (4, "%s handshake for %d threads\n", suspend ? "suspend" : "resume", count);
219 struct sigaction sinfo;
221 suspend_ack_semaphore_ptr = &suspend_ack_semaphore;
222 MONO_SEM_INIT (&suspend_ack_semaphore, 0);
224 sigfillset (&sinfo.sa_mask);
225 sinfo.sa_flags = SA_RESTART | SA_SIGINFO;
226 sinfo.sa_sigaction = suspend_handler;
227 if (sigaction (suspend_signal_num, &sinfo, NULL) != 0) {
228 g_error ("failed sigaction");
231 sinfo.sa_handler = (void*) restart_handler;
232 if (sigaction (restart_signal_num, &sinfo, NULL) != 0) {
233 g_error ("failed sigaction");
236 sigfillset (&suspend_signal_mask);
237 sigdelset (&suspend_signal_mask, restart_signal_num);
239 sigemptyset (&suspend_ack_signal_mask);
240 sigaddset (&suspend_ack_signal_mask, restart_signal_num);
245 mono_gc_get_suspend_signal (void)
247 return suspend_signal_num;
251 mono_gc_get_restart_signal (void)
253 return restart_signal_num;