2 * sgen-os-posix.c: Simple generational GC.
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)
11 * Permission is hereby granted, free of charge, to any person obtaining
12 * a copy of this software and associated documentation files (the
13 * "Software"), to deal in the Software without restriction, including
14 * without limitation the rights to use, copy, modify, merge, publish,
15 * distribute, sublicense, and/or sell copies of the Software, and to
16 * permit persons to whom the Software is furnished to do so, subject to
17 * the following conditions:
19 * The above copyright notice and this permission notice shall be
20 * included in all copies or substantial portions of the Software.
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 #if !defined(__MACH__) && !MONO_MACH_ARCH_SUPPORTED && defined(HAVE_PTHREAD_KILL)
38 #include "metadata/sgen-gc.h"
39 #include "metadata/gc-internal.h"
40 #include "metadata/sgen-archdep.h"
41 #include "metadata/object-internals.h"
43 #if defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__)
44 const static int suspend_signal_num = SIGXFSZ;
46 const static int suspend_signal_num = SIGPWR;
48 const static int restart_signal_num = SIGXCPU;
50 static MonoSemType suspend_ack_semaphore;
51 static MonoSemType *suspend_ack_semaphore_ptr;
53 static sigset_t suspend_signal_mask;
56 suspend_thread (SgenThreadInfo *info, void *context)
62 gpointer regs [ARCH_NUM_REGS];
66 g_assert (info->doing_handshake);
68 info->stopped_domain = mono_domain_get ();
69 info->stopped_ip = context ? (gpointer) ARCH_SIGCTX_IP (context) : NULL;
70 stop_count = mono_sgen_global_stop_count;
71 /* duplicate signal */
72 if (0 && info->stop_count == stop_count)
75 mono_sgen_fill_thread_info_for_suspend (info);
77 stack_start = context ? (char*) ARCH_SIGCTX_SP (context) - REDZONE_SIZE : NULL;
78 /* If stack_start is not within the limits, then don't set it
79 in info and we will be restarted. */
80 if (stack_start >= info->stack_start_limit && info->stack_start <= info->stack_end) {
81 info->stack_start = stack_start;
85 mono_sigctx_to_monoctx (context, &monoctx);
86 info->monoctx = &monoctx;
92 ARCH_COPY_SIGCTX_REGS (regs, context);
93 info->stopped_regs = regs;
95 info->stopped_regs = NULL;
99 g_assert (!info->stack_start);
103 if (mono_gc_get_gc_callbacks ()->thread_suspend_func)
104 mono_gc_get_gc_callbacks ()->thread_suspend_func (info->runtime_data, context);
106 DEBUG (4, fprintf (gc_debug_file, "Posting suspend_ack_semaphore for suspend from %p %p\n", info, (gpointer)mono_native_thread_id_get ()));
107 /* notify the waiting thread */
108 MONO_SEM_POST (suspend_ack_semaphore_ptr);
109 info->stop_count = stop_count;
111 /* wait until we receive the restart signal */
114 sigsuspend (&suspend_signal_mask);
115 } while (info->signal != restart_signal_num && info->doing_handshake);
117 DEBUG (4, fprintf (gc_debug_file, "Posting suspend_ack_semaphore for resume from %p %p\n", info, (gpointer)mono_native_thread_id_get ()));
118 /* notify the waiting thread */
119 MONO_SEM_POST (suspend_ack_semaphore_ptr);
122 /* LOCKING: assumes the GC lock is held (by the stopping thread) */
124 suspend_handler (int sig, siginfo_t *siginfo, void *context)
126 SgenThreadInfo *info;
127 int old_errno = errno;
129 info = mono_thread_info_current ();
132 suspend_thread (info, context);
134 /* This can happen while a thread is dying */
135 //g_print ("no thread info in suspend\n");
142 restart_handler (int sig)
144 SgenThreadInfo *info;
145 int old_errno = errno;
147 info = mono_thread_info_current ();
150 * If a thread is dying there might be no thread info. In
151 * that case we rely on info->doing_handshake.
154 info->signal = restart_signal_num;
155 DEBUG (4, fprintf (gc_debug_file, "Restart handler in %p %p\n", info, (gpointer)mono_native_thread_id_get ()));
162 mono_sgen_resume_thread (SgenThreadInfo *info)
164 return mono_threads_pthread_kill (info, restart_signal_num) == 0;
168 mono_sgen_suspend_thread (SgenThreadInfo *info)
170 return mono_threads_pthread_kill (info, suspend_signal_num) == 0;
174 mono_sgen_wait_for_suspend_ack (int count)
178 for (i = 0; i < count; ++i) {
179 while ((result = MONO_SEM_WAIT (suspend_ack_semaphore_ptr)) != 0) {
180 if (errno != EINTR) {
181 g_error ("sem_wait ()");
188 mono_sgen_park_current_thread_if_doing_handshake (SgenThreadInfo *p)
190 if (!p->doing_handshake)
193 suspend_thread (p, NULL);
198 mono_sgen_thread_handshake (BOOL suspend)
201 SgenThreadInfo *info;
202 int signum = suspend ? suspend_signal_num : restart_signal_num;
204 MonoNativeThreadId me = mono_native_thread_id_get ();
207 FOREACH_THREAD_SAFE (info) {
208 if (mono_native_thread_id_equals (mono_thread_info_get_tid (info), me)) {
211 if (info->gc_disabled)
213 /*if (signum == suspend_signal_num && info->stop_count == global_stop_count)
216 g_assert (!info->doing_handshake);
217 info->doing_handshake = TRUE;
219 g_assert (info->doing_handshake);
220 info->doing_handshake = FALSE;
222 result = pthread_kill (mono_thread_info_get_tid (info), signum);
228 } END_FOREACH_THREAD_SAFE
230 mono_sgen_wait_for_suspend_ack (count);
236 mono_sgen_os_init (void)
238 struct sigaction sinfo;
240 suspend_ack_semaphore_ptr = &suspend_ack_semaphore;
241 MONO_SEM_INIT (&suspend_ack_semaphore, 0);
243 sigfillset (&sinfo.sa_mask);
244 sinfo.sa_flags = SA_RESTART | SA_SIGINFO;
245 sinfo.sa_sigaction = suspend_handler;
246 if (sigaction (suspend_signal_num, &sinfo, NULL) != 0) {
247 g_error ("failed sigaction");
250 sinfo.sa_handler = restart_handler;
251 if (sigaction (restart_signal_num, &sinfo, NULL) != 0) {
252 g_error ("failed sigaction");
255 sigfillset (&suspend_signal_mask);
256 sigdelset (&suspend_signal_mask, restart_signal_num);
260 mono_gc_get_suspend_signal (void)
262 return suspend_signal_num;