2 * sgen-os-mach.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 #include "metadata/gc-internal.h"
35 #include "metadata/sgen-gc.h"
36 #include "metadata/sgen-archdep.h"
37 #include "metadata/object-internals.h"
40 #include "utils/mach-support.h"
43 /* LOCKING: assumes the GC lock is held */
44 #if defined(__MACH__) && MONO_MACH_ARCH_SUPPORTED
46 mono_sgen_thread_handshake (int signum)
48 task_t task = current_task ();
49 thread_port_t cur_thread = mach_thread_self ();
50 thread_act_array_t thread_list;
51 mach_msg_type_number_t num_threads;
52 mach_msg_type_number_t num_state;
57 pthread_t exception_thread = mono_gc_get_mach_exception_thread ();
60 gpointer regs [ARCH_NUM_REGS];
65 mono_mach_get_threads (&thread_list, &num_threads);
67 for (i = 0, count = 0; i < num_threads; i++) {
68 thread_port_t t = thread_list [i];
69 pthread_t pt = pthread_from_mach_thread_np (t);
70 if (t != cur_thread && pt != exception_thread && !mono_sgen_is_worker_thread (pt)) {
71 if (signum == suspend_signal_num) {
72 ret = thread_suspend (t);
73 if (ret != KERN_SUCCESS) {
74 mach_port_deallocate (task, t);
78 state = (thread_state_t) alloca (mono_mach_arch_get_thread_state_size ());
79 ret = mono_mach_arch_get_thread_state (t, state, &num_state);
80 if (ret != KERN_SUCCESS) {
81 mach_port_deallocate (task, t);
86 info = mono_sgen_thread_info_lookup (pt);
88 /* Ensure that the runtime is aware of this thread */
90 mctx = (mcontext_t) alloca (mono_mach_arch_get_mcontext_size ());
91 mono_mach_arch_thread_state_to_mcontext (state, mctx);
92 ctx.uc_mcontext = mctx;
94 info->stopped_domain = mono_mach_arch_get_tls_value_from_thread (t, mono_pthread_key_for_tls (mono_domain_get_tls_key ()));
95 info->stopped_ip = (gpointer) mono_mach_arch_get_ip (state);
96 stack_start = (char*) mono_mach_arch_get_sp (state) - REDZONE_SIZE;
97 /* If stack_start is not within the limits, then don't set it in info and we will be restarted. */
98 if (stack_start >= info->stack_start_limit && info->stack_start <= info->stack_end) {
99 info->stack_start = stack_start;
101 ARCH_COPY_SIGCTX_REGS (regs, &ctx);
102 info->stopped_regs = regs;
104 g_assert (!info->stack_start);
108 if (mono_gc_get_gc_callbacks ()->thread_suspend_func)
109 mono_gc_get_gc_callbacks ()->thread_suspend_func (info->runtime_data, &ctx);
112 ret = thread_resume (t);
113 if (ret != KERN_SUCCESS) {
114 mach_port_deallocate (task, t);
120 mach_port_deallocate (task, t);
122 mach_port_deallocate (task, t);
126 mono_mach_free_threads (thread_list, num_threads);
128 mach_port_deallocate (task, cur_thread);