1 #include "private/pthread_support.h"
3 # if defined(GC_DARWIN_THREADS)
5 #define DEBUG_THREADS 0
7 /* From "Inside Mac OS X - Mach-O Runtime Architecture" published by Apple
9 "The space beneath the stack pointer, where a new stack frame would normally
10 be allocated, is called the red zone. This area as shown in Figure 3-2 may
11 be used for any purpose as long as a new stack frame does not need to be
14 Page 50: "If a leaf procedure's red zone usage would exceed 224 bytes, then
15 it must set up a stack frame just like routines that call other routines."
17 #define PPC_RED_ZONE_SIZE 224
19 void GC_push_all_stacks() {
26 ppc_thread_state_t state;
28 # error FIXME for non-ppc OS X
30 mach_msg_type_number_t thread_state_count = MACHINE_THREAD_STATE_COUNT;
33 if (!GC_thr_initialized) GC_thr_init();
35 for(i=0;i<THREAD_TABLE_SZ;i++) {
36 for(p=GC_threads[i];p!=0;p=p->next) {
37 if(p -> flags & FINISHED) continue;
38 if(pthread_equal(p->id,me)) {
41 /* Get the thread state (registers, etc) */
43 p->stop_info.mach_thread,
47 if(r != KERN_SUCCESS) ABORT("thread_get_state failed");
50 lo = (void*)(state.r1 - PPC_RED_ZONE_SIZE);
52 GC_push_one(state.r0);
53 GC_push_one(state.r2);
54 GC_push_one(state.r3);
55 GC_push_one(state.r4);
56 GC_push_one(state.r5);
57 GC_push_one(state.r6);
58 GC_push_one(state.r7);
59 GC_push_one(state.r8);
60 GC_push_one(state.r9);
61 GC_push_one(state.r10);
62 GC_push_one(state.r11);
63 GC_push_one(state.r12);
64 GC_push_one(state.r13);
65 GC_push_one(state.r14);
66 GC_push_one(state.r15);
67 GC_push_one(state.r16);
68 GC_push_one(state.r17);
69 GC_push_one(state.r18);
70 GC_push_one(state.r19);
71 GC_push_one(state.r20);
72 GC_push_one(state.r21);
73 GC_push_one(state.r22);
74 GC_push_one(state.r23);
75 GC_push_one(state.r24);
76 GC_push_one(state.r25);
77 GC_push_one(state.r26);
78 GC_push_one(state.r27);
79 GC_push_one(state.r28);
80 GC_push_one(state.r29);
81 GC_push_one(state.r30);
82 GC_push_one(state.r31);
84 # error FIXME for non-PPC darwin
87 if(p->flags & MAIN_THREAD)
92 GC_printf3("Darwin: Stack for thread 0x%lx = [%lx,%lx)\n",
93 (unsigned long) p -> id,
98 GC_push_all_stack(lo,hi);
99 } /* for(p=GC_threads[i]...) */
100 } /* for(i=0;i<THREAD_TABLE_SZ...) */
103 /* Caller holds allocation lock. */
108 pthread_t my_thread = pthread_self();
109 kern_return_t kern_result;
112 GC_printf1("Stopping the world from 0x%lx\n", pthread_self());
115 /* Make sure all free list construction has stopped before we start. */
116 /* No new construction can start, since free list construction is */
117 /* required to acquire and release the GC lock before it starts, */
118 /* and we have the lock. */
119 # ifdef PARALLEL_MARK
120 GC_acquire_mark_lock();
121 GC_ASSERT(GC_fl_builder_count == 0);
122 /* We should have previously waited for it to become zero. */
123 # endif /* PARALLEL_MARK */
125 for (i = 0; i < THREAD_TABLE_SZ; i++) {
126 for (p = GC_threads[i]; p != 0; p = p -> next) {
127 if (p -> id == my_thread) continue;
128 if (p -> flags & FINISHED) continue;
129 if (p -> thread_blocked) /* Will wait */ continue;
132 GC_printf1("Suspending thread 0x%lx\n", p -> id);
135 /* Suspend the thread */
136 kern_result = thread_suspend(p->stop_info.mach_thread);
137 if(kern_result != KERN_SUCCESS) ABORT("thread_suspend failed");
139 /* This is only needed if we are modifying the threads
140 state. thread_abort_safely should also be used
141 if this code is ever added in again.
143 kern_result = thread_abort(p->stop_info.mach_thread);
144 if(kern_result != KERN_SUCCESS)
145 ABORT("thread_abort failed (%ul)",kern_result);
152 extern void GC_mprotect_stop();
157 # ifdef PARALLEL_MARK
158 GC_release_mark_lock();
161 GC_printf1("World stopped from 0x%lx\n", pthread_self());
165 /* Caller holds allocation lock, and has held it continuously since */
166 /* the world stopped. */
167 void GC_start_world()
169 pthread_t my_thread = pthread_self();
172 kern_return_t kern_result;
175 GC_printf0("World starting\n");
180 extern void GC_mprotect_resume();
181 GC_mprotect_resume();
185 for (i = 0; i < THREAD_TABLE_SZ; i++) {
186 for (p = GC_threads[i]; p != 0; p = p -> next) {
187 if (p -> id == my_thread) continue;
188 if (p -> flags & FINISHED) continue;
189 if (p -> thread_blocked) continue;
192 GC_printf1("Resuming 0x%lx\n", p -> id);
195 /* Resume the thread */
196 kern_result = thread_resume(p->stop_info.mach_thread);
197 if(kern_result != KERN_SUCCESS) ABORT("thread_resume failed");
201 GC_printf0("World started\n");
205 void GC_stop_init() {