1 #include "private/pthread_support.h"
3 /* This probably needs more porting work to ppc64. */
5 # if defined(GC_DARWIN_THREADS)
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."
19 # define PPC_RED_ZONE_SIZE 224
20 # elif CPP_WORDSZ == 64
21 # define PPC_RED_ZONE_SIZE 320
25 typedef struct StackFrame {
26 unsigned long savedSP;
27 unsigned long savedCR;
28 unsigned long savedLR;
29 unsigned long reserved[2];
30 unsigned long savedRTOC;
33 unsigned long FindTopOfStack(unsigned long stack_start)
37 if (stack_start == 0) {
40 __asm__ volatile("lwz %0,0(r1)" : "=r" (frame));
42 __asm__ volatile("ld %0,0(r1)" : "=r" (frame));
46 frame = (StackFrame *)stack_start;
50 /* GC_printf("FindTopOfStack start at sp = %p\n", frame); */
53 if (frame->savedSP == 0)
55 /* if there are no more stack frames, stop */
57 frame = (StackFrame*)frame->savedSP;
59 /* we do these next two checks after going to the next frame
60 because the LR for the first stack frame in the loop
61 is not set up on purpose, so we shouldn't check it. */
62 if ((frame->savedLR & ~3) == 0)
63 break; /* if the next LR is bogus, stop */
64 if ((~(frame->savedLR) & ~3) == 0)
69 /* GC_printf("FindTopOfStack finish at sp = %p\n", frame); */
72 return (unsigned long)frame;
75 #ifdef DARWIN_DONT_PARSE_STACK
76 void GC_push_all_stacks()
83 GC_THREAD_STATE_T state;
84 /* MACHINE_THREAD_STATE_COUNT doesn't seem to be defined everywhere. */
85 /* Hence we use our own version. */
86 mach_msg_type_number_t thread_state_count = GC_MACH_THREAD_STATE_COUNT;
89 if (!GC_thr_initialized)
92 for(i = 0; i < THREAD_TABLE_SZ; i++) {
93 for(p = GC_threads[i]; p != 0; p = p->next) {
94 if(p->flags & FINISHED) continue;
95 if(pthread_equal(p->id, me)) {
98 /* Get the thread state (registers, etc) */
99 r = thread_get_state(p->stop_info.mach_thread, GC_MACH_THREAD_STATE,
100 (natural_t*)&state, &thread_state_count);
102 # ifdef DEBUG_THREADS
103 GC_printf("thread_get_state return value = %d\n", r);
106 if(r != KERN_SUCCESS)
107 ABORT("thread_get_state failed");
110 lo = (void*)state . THREAD_FLD (esp);
111 GC_push_one(state . THREAD_FLD (eax));
112 GC_push_one(state . THREAD_FLD (ebx));
113 GC_push_one(state . THREAD_FLD (ecx));
114 GC_push_one(state . THREAD_FLD (edx));
115 GC_push_one(state . THREAD_FLD (edi));
116 GC_push_one(state . THREAD_FLD (esi));
117 GC_push_one(state . THREAD_FLD (ebp));
119 # elif defined(X86_64)
120 lo = (void*)state . THREAD_FLD (rsp);
121 GC_push_one(state . THREAD_FLD (rax));
122 GC_push_one(state . THREAD_FLD (rbx));
123 GC_push_one(state . THREAD_FLD (rcx));
124 GC_push_one(state . THREAD_FLD (rdx));
125 GC_push_one(state . THREAD_FLD (rdi));
126 GC_push_one(state . THREAD_FLD (rsi));
127 GC_push_one(state . THREAD_FLD (rbp));
128 GC_push_one(state . THREAD_FLD (rsp));
129 GC_push_one(state . THREAD_FLD (r8));
130 GC_push_one(state . THREAD_FLD (r9));
131 GC_push_one(state . THREAD_FLD (r10));
132 GC_push_one(state . THREAD_FLD (r11));
133 GC_push_one(state . THREAD_FLD (r12));
134 GC_push_one(state . THREAD_FLD (r13));
135 GC_push_one(state . THREAD_FLD (r14));
136 GC_push_one(state . THREAD_FLD (r15));
137 GC_push_one(state . THREAD_FLD (rip));
138 GC_push_one(state . THREAD_FLD (rflags));
139 GC_push_one(state . THREAD_FLD (cs));
140 GC_push_one(state . THREAD_FLD (fs));
141 GC_push_one(state . THREAD_FLD (gs));
143 # elif defined(POWERPC)
144 lo = (void*)(state . THREAD_FLD (r1) - PPC_RED_ZONE_SIZE);
146 GC_push_one(state . THREAD_FLD (r0));
147 GC_push_one(state . THREAD_FLD (r2));
148 GC_push_one(state . THREAD_FLD (r3));
149 GC_push_one(state . THREAD_FLD (r4));
150 GC_push_one(state . THREAD_FLD (r5));
151 GC_push_one(state . THREAD_FLD (r6));
152 GC_push_one(state . THREAD_FLD (r7));
153 GC_push_one(state . THREAD_FLD (r8));
154 GC_push_one(state . THREAD_FLD (r9));
155 GC_push_one(state . THREAD_FLD (r10));
156 GC_push_one(state . THREAD_FLD (r11));
157 GC_push_one(state . THREAD_FLD (r12));
158 GC_push_one(state . THREAD_FLD (r13));
159 GC_push_one(state . THREAD_FLD (r14));
160 GC_push_one(state . THREAD_FLD (r15));
161 GC_push_one(state . THREAD_FLD (r16));
162 GC_push_one(state . THREAD_FLD (r17));
163 GC_push_one(state . THREAD_FLD (r18));
164 GC_push_one(state . THREAD_FLD (r19));
165 GC_push_one(state . THREAD_FLD (r20));
166 GC_push_one(state . THREAD_FLD (r21));
167 GC_push_one(state . THREAD_FLD (r22));
168 GC_push_one(state . THREAD_FLD (r23));
169 GC_push_one(state . THREAD_FLD (r24));
170 GC_push_one(state . THREAD_FLD (r25));
171 GC_push_one(state . THREAD_FLD (r26));
172 GC_push_one(state . THREAD_FLD (r27));
173 GC_push_one(state . THREAD_FLD (r28));
174 GC_push_one(state . THREAD_FLD (r29));
175 GC_push_one(state . THREAD_FLD (r30));
176 GC_push_one(state . THREAD_FLD (r31));
178 # error FIXME for non-x86 || ppc architectures
181 if(p->flags & MAIN_THREAD)
186 GC_printf("Darwin: Stack for thread 0x%lx = [%lx,%lx)\n",
187 (unsigned long) p -> id, (unsigned long) lo,
190 GC_push_all_stack(lo, hi);
191 } /* for(p=GC_threads[i]...) */
192 } /* for(i=0;i<THREAD_TABLE_SZ...) */
195 #else /* !DARWIN_DONT_PARSE_STACK; Use FindTopOfStack() */
197 void GC_push_all_stacks()
204 thread_act_array_t act_list = 0;
205 mach_msg_type_number_t listcount = 0;
207 me = mach_thread_self();
208 if (!GC_thr_initialized)
211 my_task = current_task();
212 r = task_threads(my_task, &act_list, &listcount);
213 if(r != KERN_SUCCESS)
214 ABORT("task_threads failed");
215 for(i = 0; i < listcount; i++) {
216 thread_act_t thread = act_list[i];
219 hi = (ptr_t)FindTopOfStack(0);
221 # if defined(POWERPC)
222 GC_THREAD_STATE_T info;
223 mach_msg_type_number_t outCount = THREAD_STATE_MAX;
224 r = thread_get_state(thread, GC_MACH_THREAD_STATE, (natural_t *)&info,
226 if(r != KERN_SUCCESS)
227 ABORT("task_get_state failed");
229 lo = (void*)(info . THREAD_FLD (r1) - PPC_RED_ZONE_SIZE);
230 hi = (ptr_t)FindTopOfStack(info . THREAD_FLD (r1));
232 GC_push_one(info . THREAD_FLD (r0));
233 GC_push_one(info . THREAD_FLD (r2));
234 GC_push_one(info . THREAD_FLD (r3));
235 GC_push_one(info . THREAD_FLD (r4));
236 GC_push_one(info . THREAD_FLD (r5));
237 GC_push_one(info . THREAD_FLD (r6));
238 GC_push_one(info . THREAD_FLD (r7));
239 GC_push_one(info . THREAD_FLD (r8));
240 GC_push_one(info . THREAD_FLD (r9));
241 GC_push_one(info . THREAD_FLD (r10));
242 GC_push_one(info . THREAD_FLD (r11));
243 GC_push_one(info . THREAD_FLD (r12));
244 GC_push_one(info . THREAD_FLD (r13));
245 GC_push_one(info . THREAD_FLD (r14));
246 GC_push_one(info . THREAD_FLD (r15));
247 GC_push_one(info . THREAD_FLD (r16));
248 GC_push_one(info . THREAD_FLD (r17));
249 GC_push_one(info . THREAD_FLD (r18));
250 GC_push_one(info . THREAD_FLD (r19));
251 GC_push_one(info . THREAD_FLD (r20));
252 GC_push_one(info . THREAD_FLD (r21));
253 GC_push_one(info . THREAD_FLD (r22));
254 GC_push_one(info . THREAD_FLD (r23));
255 GC_push_one(info . THREAD_FLD (r24));
256 GC_push_one(info . THREAD_FLD (r25));
257 GC_push_one(info . THREAD_FLD (r26));
258 GC_push_one(info . THREAD_FLD (r27));
259 GC_push_one(info . THREAD_FLD (r28));
260 GC_push_one(info . THREAD_FLD (r29));
261 GC_push_one(info . THREAD_FLD (r30));
262 GC_push_one(info . THREAD_FLD (r31));
265 /* FIXME: Remove after testing: */
266 WARN("This is completely untested and likely will not work\n", 0);
267 GC_THREAD_STATE_T info;
268 mach_msg_type_number_t outCount = THREAD_STATE_MAX;
269 r = thread_get_state(thread, GC_MACH_THREAD_STATE, (natural_t *)&info,
271 if(r != KERN_SUCCESS)
272 ABORT("task_get_state failed");
274 lo = (void*)info . THREAD_FLD (esp);
275 hi = (ptr_t)FindTopOfStack(info . THREAD_FLD (esp));
277 GC_push_one(info . THREAD_FLD (eax));
278 GC_push_one(info . THREAD_FLD (ebx));
279 GC_push_one(info . THREAD_FLD (ecx));
280 GC_push_one(info . THREAD_FLD (edx));
281 GC_push_one(info . THREAD_FLD (edi));
282 GC_push_one(info . THREAD_FLD (esi));
283 /* GC_push_one(info . THREAD_FLD (ebp)); */
284 /* GC_push_one(info . THREAD_FLD (esp)); */
285 GC_push_one(info . THREAD_FLD (ss));
286 GC_push_one(info . THREAD_FLD (eip));
287 GC_push_one(info . THREAD_FLD (cs));
288 GC_push_one(info . THREAD_FLD (ds));
289 GC_push_one(info . THREAD_FLD (es));
290 GC_push_one(info . THREAD_FLD (fs));
291 GC_push_one(info . THREAD_FLD (gs));
293 # elif defined(X86_64)
294 GC_THREAD_STATE_T info;
295 mach_msg_type_number_t outCount = THREAD_STATE_MAX;
296 r = thread_get_state(thread, GC_MACH_THREAD_STATE, (natural_t *)&info,
298 if(r != KERN_SUCCESS)
299 ABORT("task_get_state failed");
301 lo = (void*)info . THREAD_FLD (rsp);
302 hi = (ptr_t)FindTopOfStack(info . THREAD_FLD (rsp));
304 GC_push_one(info . THREAD_FLD (rax));
305 GC_push_one(info . THREAD_FLD (rbx));
306 GC_push_one(info . THREAD_FLD (rcx));
307 GC_push_one(info . THREAD_FLD (rdx));
308 GC_push_one(info . THREAD_FLD (rdi));
309 GC_push_one(info . THREAD_FLD (rsi));
310 GC_push_one(info . THREAD_FLD (rbp));
311 GC_push_one(info . THREAD_FLD (rsp));
312 GC_push_one(info . THREAD_FLD (r8));
313 GC_push_one(info . THREAD_FLD (r9));
314 GC_push_one(info . THREAD_FLD (r10));
315 GC_push_one(info . THREAD_FLD (r11));
316 GC_push_one(info . THREAD_FLD (r12));
317 GC_push_one(info . THREAD_FLD (r13));
318 GC_push_one(info . THREAD_FLD (r14));
319 GC_push_one(info . THREAD_FLD (r15));
320 GC_push_one(info . THREAD_FLD (rip));
321 GC_push_one(info . THREAD_FLD (rflags));
322 GC_push_one(info . THREAD_FLD (cs));
323 GC_push_one(info . THREAD_FLD (fs));
324 GC_push_one(info . THREAD_FLD (gs));
327 # error FIXME for non-x86 || ppc architectures
331 GC_printf("Darwin: Stack for thread 0x%lx = [%p,%p)\n",
332 (unsigned long) thread, lo, hi);
334 GC_push_all_stack(lo, hi);
335 mach_port_deallocate(my_task, thread);
336 } /* for(p=GC_threads[i]...) */
337 vm_deallocate(my_task, (vm_address_t)act_list,
338 sizeof(thread_t) * listcount);
339 mach_port_deallocate(my_task, me);
341 #endif /* !DARWIN_DONT_PARSE_STACK */
343 static mach_port_t GC_mach_handler_thread;
344 static int GC_use_mach_handler_thread = 0;
346 static struct GC_mach_thread GC_mach_threads[THREAD_TABLE_SZ];
347 static int GC_mach_threads_count;
353 for (i = 0; i < THREAD_TABLE_SZ; i++) {
354 GC_mach_threads[i].thread = 0;
355 GC_mach_threads[i].already_suspended = 0;
357 GC_mach_threads_count = 0;
360 /* returns true if there's a thread in act_list that wasn't in old_list */
361 int GC_suspend_thread_list(thread_act_array_t act_list, int count,
362 thread_act_array_t old_list, int old_count)
364 mach_port_t my_thread = mach_thread_self();
369 for(i = 0; i < count; i++) {
370 thread_act_t thread = act_list[i];
372 GC_printf("Attempting to suspend thread %p\n", thread);
374 /* find the current thread in the old list */
376 for(j = 0; j < old_count; j++) {
377 thread_act_t old_thread = old_list[j];
378 if (old_thread == thread) {
384 /* add it to the GC_mach_threads list */
385 GC_mach_threads[GC_mach_threads_count].thread = thread;
386 /* default is not suspended */
387 GC_mach_threads[GC_mach_threads_count].already_suspended = 0;
391 if (thread != my_thread
392 && (!GC_use_mach_handler_thread
393 || (GC_use_mach_handler_thread
394 && GC_mach_handler_thread != thread))) {
395 struct thread_basic_info info;
396 mach_msg_type_number_t outCount = THREAD_INFO_MAX;
397 kern_return_t kern_result = thread_info(thread, THREAD_BASIC_INFO,
398 (thread_info_t)&info, &outCount);
399 if(kern_result != KERN_SUCCESS) {
400 /* the thread may have quit since the thread_threads () call
401 * we mark already_suspended so it's not dealt with anymore later
404 GC_mach_threads[GC_mach_threads_count].already_suspended = TRUE;
405 GC_mach_threads_count++;
410 GC_printf("Thread state for 0x%lx = %d\n", (unsigned long)thread,
414 GC_mach_threads[GC_mach_threads_count].already_suspended
415 = info.suspend_count;
417 if (info.suspend_count)
421 GC_printf("Suspending 0x%lx\n", (unsigned long)thread);
423 /* Suspend the thread */
424 kern_result = thread_suspend(thread);
425 if(kern_result != KERN_SUCCESS) {
426 /* the thread may have quit since the thread_threads () call
427 * we mark already_suspended so it's not dealt with anymore later
430 GC_mach_threads[GC_mach_threads_count].already_suspended = TRUE;
431 GC_mach_threads_count++;
436 if (!found) GC_mach_threads_count++;
438 mach_port_deallocate(current_task(), my_thread);
443 /* Caller holds allocation lock. */
446 unsigned int i, changes;
447 task_t my_task = current_task();
448 mach_port_t my_thread = mach_thread_self();
449 kern_return_t kern_result;
450 thread_act_array_t act_list, prev_list;
451 mach_msg_type_number_t listcount, prevcount;
454 GC_printf("Stopping the world from 0x%lx\n",
455 (unsigned long)mach_thread_self());
458 /* clear out the mach threads list table */
461 /* Make sure all free list construction has stopped before we start. */
462 /* No new construction can start, since free list construction is */
463 /* required to acquire and release the GC lock before it starts, */
464 /* and we have the lock. */
465 # ifdef PARALLEL_MARK
466 GC_acquire_mark_lock();
467 GC_ASSERT(GC_fl_builder_count == 0);
468 /* We should have previously waited for it to become zero. */
469 # endif /* PARALLEL_MARK */
471 /* Loop stopping threads until you have gone over the whole list
472 twice without a new one appearing. thread_create() won't
473 return (and thus the thread stop) until the new thread
474 exists, so there is no window whereby you could stop a
475 thread, recognise it is stopped, but then have a new thread
476 it created before stopping show up later.
479 /* FIXME: This seems to erroneously stop the parallel marker threads? */
486 kern_result = task_threads(my_task, &act_list, &listcount);
488 if(kern_result == KERN_SUCCESS) {
489 result = GC_suspend_thread_list(act_list, listcount, prev_list,
493 if(prev_list != NULL) {
494 for(i = 0; i < prevcount; i++)
495 mach_port_deallocate(my_task, prev_list[i]);
497 vm_deallocate(my_task, (vm_address_t)prev_list,
498 sizeof(thread_t) * prevcount);
500 prev_list = act_list;
501 prevcount = listcount;
504 GC_ASSERT(prev_list != 0);
505 for(i = 0; i < prevcount; i++)
506 mach_port_deallocate(my_task, prev_list[i]);
508 vm_deallocate(my_task, (vm_address_t)act_list,
509 sizeof(thread_t) * listcount);
513 extern void GC_mprotect_stop();
518 # ifdef PARALLEL_MARK
519 GC_release_mark_lock();
522 GC_printf("World stopped from 0x%lx\n", (unsigned long)my_thread);
525 mach_port_deallocate(my_task, my_thread);
528 /* Caller holds allocation lock, and has held it continuously since */
529 /* the world stopped. */
530 void GC_start_world()
532 task_t my_task = current_task();
533 mach_port_t my_thread = mach_thread_self();
536 kern_return_t kern_result;
537 thread_act_array_t act_list;
538 mach_msg_type_number_t listcount;
539 struct thread_basic_info info;
540 mach_msg_type_number_t outCount = THREAD_INFO_MAX;
543 GC_printf("World starting\n");
548 extern void GC_mprotect_resume();
549 GC_mprotect_resume();
553 kern_result = task_threads(my_task, &act_list, &listcount);
554 for(i = 0; i < listcount; i++) {
555 thread_act_t thread = act_list[i];
556 if (thread != my_thread
557 && (!GC_use_mach_handler_thread
558 || (GC_use_mach_handler_thread
559 && GC_mach_handler_thread != thread))) {
560 for(j = 0; j < GC_mach_threads_count; j++) {
561 if (thread == GC_mach_threads[j].thread) {
562 if (GC_mach_threads[j].already_suspended) {
564 GC_printf("Not resuming already suspended thread %p\n", thread);
568 kern_result = thread_info(thread, THREAD_BASIC_INFO,
569 (thread_info_t)&info, &outCount);
570 if(kern_result != KERN_SUCCESS)
571 ABORT("thread_info failed");
573 GC_printf("Thread state for 0x%lx = %d\n", (unsigned long)thread,
575 GC_printf("Resuming 0x%lx\n", (unsigned long)thread);
577 /* Resume the thread */
578 kern_result = thread_resume(thread);
579 if(kern_result != KERN_SUCCESS)
580 ABORT("thread_resume failed");
584 mach_port_deallocate(my_task, thread);
586 vm_deallocate(my_task, (vm_address_t)act_list,
587 sizeof(thread_t) * listcount);
589 mach_port_deallocate(my_task, my_thread);
591 GC_printf("World started\n");
595 void GC_darwin_register_mach_handler_thread(mach_port_t thread)
597 GC_mach_handler_thread = thread;
598 GC_use_mach_handler_thread = 1;