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 void GC_thr_init(void);
77 #ifdef DARWIN_DONT_PARSE_STACK
79 void GC_push_all_stacks(void)
86 GC_THREAD_STATE_T state;
87 /* MACHINE_THREAD_STATE_COUNT doesn't seem to be defined everywhere. */
88 /* Hence we use our own version. */
89 mach_msg_type_number_t thread_state_count = GC_MACH_THREAD_STATE_COUNT;
92 if (!GC_thr_initialized)
95 for(i = 0; i < THREAD_TABLE_SZ; i++) {
96 for(p = GC_threads[i]; p != 0; p = p->next) {
97 if(p->flags & FINISHED) continue;
98 if(pthread_equal(p->id, me)) {
101 /* Get the thread state (registers, etc) */
102 r = thread_get_state(p->stop_info.mach_thread, GC_MACH_THREAD_STATE,
103 (natural_t*)&state, &thread_state_count);
105 # ifdef DEBUG_THREADS
106 GC_printf("thread_get_state return value = %d\n", r);
109 if(r != KERN_SUCCESS)
110 ABORT("thread_get_state failed");
113 lo = (void*)state . THREAD_FLD (esp);
114 GC_push_one(state . THREAD_FLD (eax));
115 GC_push_one(state . THREAD_FLD (ebx));
116 GC_push_one(state . THREAD_FLD (ecx));
117 GC_push_one(state . THREAD_FLD (edx));
118 GC_push_one(state . THREAD_FLD (edi));
119 GC_push_one(state . THREAD_FLD (esi));
120 GC_push_one(state . THREAD_FLD (ebp));
122 # elif defined(X86_64)
123 lo = (void*)state . THREAD_FLD (rsp);
124 GC_push_one(state . THREAD_FLD (rax));
125 GC_push_one(state . THREAD_FLD (rbx));
126 GC_push_one(state . THREAD_FLD (rcx));
127 GC_push_one(state . THREAD_FLD (rdx));
128 GC_push_one(state . THREAD_FLD (rdi));
129 GC_push_one(state . THREAD_FLD (rsi));
130 GC_push_one(state . THREAD_FLD (rbp));
131 GC_push_one(state . THREAD_FLD (rsp));
132 GC_push_one(state . THREAD_FLD (r8));
133 GC_push_one(state . THREAD_FLD (r9));
134 GC_push_one(state . THREAD_FLD (r10));
135 GC_push_one(state . THREAD_FLD (r11));
136 GC_push_one(state . THREAD_FLD (r12));
137 GC_push_one(state . THREAD_FLD (r13));
138 GC_push_one(state . THREAD_FLD (r14));
139 GC_push_one(state . THREAD_FLD (r15));
140 GC_push_one(state . THREAD_FLD (rip));
141 GC_push_one(state . THREAD_FLD (rflags));
142 GC_push_one(state . THREAD_FLD (cs));
143 GC_push_one(state . THREAD_FLD (fs));
144 GC_push_one(state . THREAD_FLD (gs));
146 # elif defined(POWERPC)
147 lo = (void*)(state . THREAD_FLD (r1) - PPC_RED_ZONE_SIZE);
149 GC_push_one(state . THREAD_FLD (r0));
150 GC_push_one(state . THREAD_FLD (r2));
151 GC_push_one(state . THREAD_FLD (r3));
152 GC_push_one(state . THREAD_FLD (r4));
153 GC_push_one(state . THREAD_FLD (r5));
154 GC_push_one(state . THREAD_FLD (r6));
155 GC_push_one(state . THREAD_FLD (r7));
156 GC_push_one(state . THREAD_FLD (r8));
157 GC_push_one(state . THREAD_FLD (r9));
158 GC_push_one(state . THREAD_FLD (r10));
159 GC_push_one(state . THREAD_FLD (r11));
160 GC_push_one(state . THREAD_FLD (r12));
161 GC_push_one(state . THREAD_FLD (r13));
162 GC_push_one(state . THREAD_FLD (r14));
163 GC_push_one(state . THREAD_FLD (r15));
164 GC_push_one(state . THREAD_FLD (r16));
165 GC_push_one(state . THREAD_FLD (r17));
166 GC_push_one(state . THREAD_FLD (r18));
167 GC_push_one(state . THREAD_FLD (r19));
168 GC_push_one(state . THREAD_FLD (r20));
169 GC_push_one(state . THREAD_FLD (r21));
170 GC_push_one(state . THREAD_FLD (r22));
171 GC_push_one(state . THREAD_FLD (r23));
172 GC_push_one(state . THREAD_FLD (r24));
173 GC_push_one(state . THREAD_FLD (r25));
174 GC_push_one(state . THREAD_FLD (r26));
175 GC_push_one(state . THREAD_FLD (r27));
176 GC_push_one(state . THREAD_FLD (r28));
177 GC_push_one(state . THREAD_FLD (r29));
178 GC_push_one(state . THREAD_FLD (r30));
179 GC_push_one(state . THREAD_FLD (r31));
181 # elif defined(ARM32)
182 lo = (void*)state.__sp;
184 GC_push_one(state.__r[0]);
185 GC_push_one(state.__r[1]);
186 GC_push_one(state.__r[2]);
187 GC_push_one(state.__r[3]);
188 GC_push_one(state.__r[4]);
189 GC_push_one(state.__r[5]);
190 GC_push_one(state.__r[6]);
191 GC_push_one(state.__r[7]);
192 GC_push_one(state.__r[8]);
193 GC_push_one(state.__r[9]);
194 GC_push_one(state.__r[10]);
195 GC_push_one(state.__r[11]);
196 GC_push_one(state.__r[12]);
197 /* GC_push_one(state.__sp); */
198 GC_push_one(state.__lr);
199 GC_push_one(state.__pc);
200 GC_push_one(state.__cpsr);
203 # error FIXME for non-x86 || ppc || arm architectures
206 if(p->flags & MAIN_THREAD)
211 GC_printf("Darwin: Stack for thread 0x%lx = [%lx,%lx)\n",
212 (unsigned long) p -> id, (unsigned long) lo,
215 GC_push_all_stack(lo, hi);
216 } /* for(p=GC_threads[i]...) */
217 } /* for(i=0;i<THREAD_TABLE_SZ...) */
220 #else /* !DARWIN_DONT_PARSE_STACK; Use FindTopOfStack() */
222 void GC_push_all_stacks(void)
229 thread_act_array_t act_list = 0;
230 mach_msg_type_number_t listcount = 0;
232 me = mach_thread_self();
233 if (!GC_thr_initialized)
236 my_task = current_task();
237 r = task_threads(my_task, &act_list, &listcount);
238 if(r != KERN_SUCCESS)
239 ABORT("task_threads failed");
240 for(i = 0; i < listcount; i++) {
241 thread_act_t thread = act_list[i];
244 hi = (ptr_t)FindTopOfStack(0);
246 # if defined(POWERPC)
247 GC_THREAD_STATE_T info;
248 mach_msg_type_number_t outCount = THREAD_STATE_MAX;
249 r = thread_get_state(thread, GC_MACH_THREAD_STATE, (natural_t *)&info,
251 if(r != KERN_SUCCESS)
252 ABORT("task_get_state failed");
254 lo = (void*)(info . THREAD_FLD (r1) - PPC_RED_ZONE_SIZE);
255 hi = (ptr_t)FindTopOfStack(info . THREAD_FLD (r1));
257 GC_push_one(info . THREAD_FLD (r0));
258 GC_push_one(info . THREAD_FLD (r2));
259 GC_push_one(info . THREAD_FLD (r3));
260 GC_push_one(info . THREAD_FLD (r4));
261 GC_push_one(info . THREAD_FLD (r5));
262 GC_push_one(info . THREAD_FLD (r6));
263 GC_push_one(info . THREAD_FLD (r7));
264 GC_push_one(info . THREAD_FLD (r8));
265 GC_push_one(info . THREAD_FLD (r9));
266 GC_push_one(info . THREAD_FLD (r10));
267 GC_push_one(info . THREAD_FLD (r11));
268 GC_push_one(info . THREAD_FLD (r12));
269 GC_push_one(info . THREAD_FLD (r13));
270 GC_push_one(info . THREAD_FLD (r14));
271 GC_push_one(info . THREAD_FLD (r15));
272 GC_push_one(info . THREAD_FLD (r16));
273 GC_push_one(info . THREAD_FLD (r17));
274 GC_push_one(info . THREAD_FLD (r18));
275 GC_push_one(info . THREAD_FLD (r19));
276 GC_push_one(info . THREAD_FLD (r20));
277 GC_push_one(info . THREAD_FLD (r21));
278 GC_push_one(info . THREAD_FLD (r22));
279 GC_push_one(info . THREAD_FLD (r23));
280 GC_push_one(info . THREAD_FLD (r24));
281 GC_push_one(info . THREAD_FLD (r25));
282 GC_push_one(info . THREAD_FLD (r26));
283 GC_push_one(info . THREAD_FLD (r27));
284 GC_push_one(info . THREAD_FLD (r28));
285 GC_push_one(info . THREAD_FLD (r29));
286 GC_push_one(info . THREAD_FLD (r30));
287 GC_push_one(info . THREAD_FLD (r31));
290 /* FIXME: Remove after testing: */
291 WARN("This is completely untested and likely will not work\n", 0);
292 GC_THREAD_STATE_T info;
293 mach_msg_type_number_t outCount = THREAD_STATE_MAX;
294 r = thread_get_state(thread, GC_MACH_THREAD_STATE, (natural_t *)&info,
296 if(r != KERN_SUCCESS)
297 ABORT("task_get_state failed");
299 lo = (void*)info . THREAD_FLD (esp);
300 hi = (ptr_t)FindTopOfStack(info . THREAD_FLD (esp));
302 GC_push_one(info . THREAD_FLD (eax));
303 GC_push_one(info . THREAD_FLD (ebx));
304 GC_push_one(info . THREAD_FLD (ecx));
305 GC_push_one(info . THREAD_FLD (edx));
306 GC_push_one(info . THREAD_FLD (edi));
307 GC_push_one(info . THREAD_FLD (esi));
308 /* GC_push_one(info . THREAD_FLD (ebp)); */
309 /* GC_push_one(info . THREAD_FLD (esp)); */
310 GC_push_one(info . THREAD_FLD (ss));
311 GC_push_one(info . THREAD_FLD (eip));
312 GC_push_one(info . THREAD_FLD (cs));
313 GC_push_one(info . THREAD_FLD (ds));
314 GC_push_one(info . THREAD_FLD (es));
315 GC_push_one(info . THREAD_FLD (fs));
316 GC_push_one(info . THREAD_FLD (gs));
318 # elif defined(X86_64)
319 GC_THREAD_STATE_T info;
320 mach_msg_type_number_t outCount = THREAD_STATE_MAX;
321 r = thread_get_state(thread, GC_MACH_THREAD_STATE, (natural_t *)&info,
323 if(r != KERN_SUCCESS)
324 ABORT("task_get_state failed");
326 lo = (void*)info . THREAD_FLD (rsp);
327 hi = (ptr_t)FindTopOfStack(info . THREAD_FLD (rsp));
329 GC_push_one(info . THREAD_FLD (rax));
330 GC_push_one(info . THREAD_FLD (rbx));
331 GC_push_one(info . THREAD_FLD (rcx));
332 GC_push_one(info . THREAD_FLD (rdx));
333 GC_push_one(info . THREAD_FLD (rdi));
334 GC_push_one(info . THREAD_FLD (rsi));
335 GC_push_one(info . THREAD_FLD (rbp));
336 GC_push_one(info . THREAD_FLD (rsp));
337 GC_push_one(info . THREAD_FLD (r8));
338 GC_push_one(info . THREAD_FLD (r9));
339 GC_push_one(info . THREAD_FLD (r10));
340 GC_push_one(info . THREAD_FLD (r11));
341 GC_push_one(info . THREAD_FLD (r12));
342 GC_push_one(info . THREAD_FLD (r13));
343 GC_push_one(info . THREAD_FLD (r14));
344 GC_push_one(info . THREAD_FLD (r15));
345 GC_push_one(info . THREAD_FLD (rip));
346 GC_push_one(info . THREAD_FLD (rflags));
347 GC_push_one(info . THREAD_FLD (cs));
348 GC_push_one(info . THREAD_FLD (fs));
349 GC_push_one(info . THREAD_FLD (gs));
351 # elif defined(ARM32)
352 GC_THREAD_STATE_T info;
353 mach_msg_type_number_t outCount = THREAD_STATE_MAX;
354 r = thread_get_state(thread, GC_MACH_THREAD_STATE, (natural_t *)&info,
356 if(r != KERN_SUCCESS)
357 ABORT("task_get_state failed");
359 hi = (ptr_t)FindTopOfStack(info . __sp);
361 lo = (void*)info.__sp;
363 GC_push_one(info.__r[0]);
364 GC_push_one(info.__r[1]);
365 GC_push_one(info.__r[2]);
366 GC_push_one(info.__r[3]);
367 GC_push_one(info.__r[4]);
368 GC_push_one(info.__r[5]);
369 GC_push_one(info.__r[6]);
370 GC_push_one(info.__r[7]);
371 GC_push_one(info.__r[8]);
372 GC_push_one(info.__r[9]);
373 GC_push_one(info.__r[10]);
374 GC_push_one(info.__r[11]);
375 GC_push_one(info.__r[12]);
376 /* GC_push_one(info.__sp); */
377 GC_push_one(info.__lr);
378 GC_push_one(info.__pc);
379 GC_push_one(info.__cpsr);
382 # error FIXME for non-x86 || ppc || arm architectures
386 GC_printf("Darwin: Stack for thread 0x%lx = [%p,%p)\n",
387 (unsigned long) thread, lo, hi);
389 GC_push_all_stack(lo, hi);
390 mach_port_deallocate(my_task, thread);
391 } /* for(p=GC_threads[i]...) */
392 vm_deallocate(my_task, (vm_address_t)act_list,
393 sizeof(thread_t) * listcount);
394 mach_port_deallocate(my_task, me);
396 #endif /* !DARWIN_DONT_PARSE_STACK */
398 static mach_port_t GC_mach_handler_thread;
399 static int GC_use_mach_handler_thread = 0;
401 static struct GC_mach_thread GC_mach_threads[THREAD_TABLE_SZ];
402 static int GC_mach_threads_count;
404 void GC_stop_init(void)
408 for (i = 0; i < THREAD_TABLE_SZ; i++) {
409 GC_mach_threads[i].thread = 0;
410 GC_mach_threads[i].already_suspended = 0;
412 GC_mach_threads_count = 0;
415 /* returns true if there's a thread in act_list that wasn't in old_list */
416 STATIC int GC_suspend_thread_list(thread_act_array_t act_list, int count,
417 thread_act_array_t old_list, int old_count)
419 mach_port_t my_thread = mach_thread_self();
424 for(i = 0; i < count; i++) {
425 thread_act_t thread = act_list[i];
427 GC_printf("Attempting to suspend thread %p\n", thread);
429 /* find the current thread in the old list */
431 for(j = 0; j < old_count; j++) {
432 thread_act_t old_thread = old_list[j];
433 if (old_thread == thread) {
439 /* add it to the GC_mach_threads list */
440 GC_mach_threads[GC_mach_threads_count].thread = thread;
441 /* default is not suspended */
442 GC_mach_threads[GC_mach_threads_count].already_suspended = 0;
446 if (thread != my_thread
447 && (!GC_use_mach_handler_thread
448 || (GC_use_mach_handler_thread
449 && GC_mach_handler_thread != thread))) {
450 struct thread_basic_info info;
451 mach_msg_type_number_t outCount = THREAD_INFO_MAX;
452 kern_return_t kern_result = thread_info(thread, THREAD_BASIC_INFO,
453 (thread_info_t)&info, &outCount);
454 if(kern_result != KERN_SUCCESS) {
455 /* the thread may have quit since the thread_threads () call
456 * we mark already_suspended so it's not dealt with anymore later
459 GC_mach_threads[GC_mach_threads_count].already_suspended = TRUE;
460 GC_mach_threads_count++;
465 GC_printf("Thread state for 0x%lx = %d\n", (unsigned long)thread,
469 GC_mach_threads[GC_mach_threads_count].already_suspended
470 = info.suspend_count;
472 if (info.suspend_count)
476 GC_printf("Suspending 0x%lx\n", (unsigned long)thread);
478 /* Suspend the thread */
479 kern_result = thread_suspend(thread);
480 if(kern_result != KERN_SUCCESS) {
481 /* the thread may have quit since the thread_threads () call
482 * we mark already_suspended so it's not dealt with anymore later
485 GC_mach_threads[GC_mach_threads_count].already_suspended = TRUE;
486 GC_mach_threads_count++;
491 if (!found) GC_mach_threads_count++;
493 mach_port_deallocate(current_task(), my_thread);
498 /* Caller holds allocation lock. */
499 void GC_stop_world(void)
501 unsigned int i, changes;
502 task_t my_task = current_task();
503 mach_port_t my_thread = mach_thread_self();
504 kern_return_t kern_result;
505 thread_act_array_t act_list, prev_list;
506 mach_msg_type_number_t listcount, prevcount;
509 GC_printf("Stopping the world from 0x%lx\n",
510 (unsigned long)mach_thread_self());
513 /* clear out the mach threads list table */
516 /* Make sure all free list construction has stopped before we start. */
517 /* No new construction can start, since free list construction is */
518 /* required to acquire and release the GC lock before it starts, */
519 /* and we have the lock. */
520 # ifdef PARALLEL_MARK
522 GC_acquire_mark_lock();
523 GC_ASSERT(GC_fl_builder_count == 0);
524 /* We should have previously waited for it to become zero. */
526 # endif /* PARALLEL_MARK */
528 /* Loop stopping threads until you have gone over the whole list
529 twice without a new one appearing. thread_create() won't
530 return (and thus the thread stop) until the new thread
531 exists, so there is no window whereby you could stop a
532 thread, recognise it is stopped, but then have a new thread
533 it created before stopping show up later.
536 /* FIXME: This seems to erroneously stop the parallel marker threads? */
543 kern_result = task_threads(my_task, &act_list, &listcount);
545 if(kern_result == KERN_SUCCESS) {
546 result = GC_suspend_thread_list(act_list, listcount, prev_list,
550 if(prev_list != NULL) {
551 for(i = 0; i < prevcount; i++)
552 mach_port_deallocate(my_task, prev_list[i]);
554 vm_deallocate(my_task, (vm_address_t)prev_list,
555 sizeof(thread_t) * prevcount);
557 prev_list = act_list;
558 prevcount = listcount;
561 GC_ASSERT(prev_list != 0);
562 for(i = 0; i < prevcount; i++)
563 mach_port_deallocate(my_task, prev_list[i]);
565 vm_deallocate(my_task, (vm_address_t)act_list,
566 sizeof(thread_t) * listcount);
570 extern void GC_mprotect_stop();
575 # ifdef PARALLEL_MARK
577 GC_release_mark_lock();
580 GC_printf("World stopped from 0x%lx\n", (unsigned long)my_thread);
583 mach_port_deallocate(my_task, my_thread);
586 /* Caller holds allocation lock, and has held it continuously since */
587 /* the world stopped. */
588 void GC_start_world(void)
590 task_t my_task = current_task();
591 mach_port_t my_thread = mach_thread_self();
594 kern_return_t kern_result;
595 thread_act_array_t act_list;
596 mach_msg_type_number_t listcount;
597 struct thread_basic_info info;
598 mach_msg_type_number_t outCount = THREAD_INFO_MAX;
601 GC_printf("World starting\n");
606 extern void GC_mprotect_resume();
607 GC_mprotect_resume();
611 kern_result = task_threads(my_task, &act_list, &listcount);
612 for(i = 0; i < listcount; i++) {
613 thread_act_t thread = act_list[i];
614 if (thread != my_thread
615 && (!GC_use_mach_handler_thread
616 || (GC_use_mach_handler_thread
617 && GC_mach_handler_thread != thread))) {
618 for(j = 0; j < GC_mach_threads_count; j++) {
619 if (thread == GC_mach_threads[j].thread) {
620 if (GC_mach_threads[j].already_suspended) {
622 GC_printf("Not resuming already suspended thread %p\n", thread);
626 kern_result = thread_info(thread, THREAD_BASIC_INFO,
627 (thread_info_t)&info, &outCount);
628 if(kern_result != KERN_SUCCESS)
629 ABORT("thread_info failed");
631 GC_printf("Thread state for 0x%lx = %d\n", (unsigned long)thread,
633 GC_printf("Resuming 0x%lx\n", (unsigned long)thread);
635 /* Resume the thread */
636 kern_result = thread_resume(thread);
637 if(kern_result != KERN_SUCCESS)
638 ABORT("thread_resume failed");
642 mach_port_deallocate(my_task, thread);
644 vm_deallocate(my_task, (vm_address_t)act_list,
645 sizeof(thread_t) * listcount);
647 mach_port_deallocate(my_task, my_thread);
649 GC_printf("World started\n");
653 void GC_darwin_register_mach_handler_thread(mach_port_t thread)
655 GC_mach_handler_thread = thread;
656 GC_use_mach_handler_thread = 1;