3 #include "private/pthread_support.h"
5 /* This probably needs more porting work to ppc64. */
7 # if defined(GC_DARWIN_THREADS)
9 /* From "Inside Mac OS X - Mach-O Runtime Architecture" published by Apple
11 "The space beneath the stack pointer, where a new stack frame would normally
12 be allocated, is called the red zone. This area as shown in Figure 3-2 may
13 be used for any purpose as long as a new stack frame does not need to be
16 Page 50: "If a leaf procedure's red zone usage would exceed 224 bytes, then
17 it must set up a stack frame just like routines that call other routines."
21 # define PPC_RED_ZONE_SIZE 224
22 # elif CPP_WORDSZ == 64
23 # define PPC_RED_ZONE_SIZE 320
27 typedef struct StackFrame {
28 unsigned long savedSP;
29 unsigned long savedCR;
30 unsigned long savedLR;
31 unsigned long reserved[2];
32 unsigned long savedRTOC;
35 unsigned long FindTopOfStack(unsigned long stack_start)
39 if (stack_start == 0) {
42 __asm__ volatile("lwz %0,0(r1)" : "=r" (frame));
44 __asm__ volatile("ld %0,0(r1)" : "=r" (frame));
48 frame = (StackFrame *)stack_start;
52 /* GC_printf("FindTopOfStack start at sp = %p\n", frame); */
55 if (frame->savedSP == 0)
57 /* if there are no more stack frames, stop */
59 frame = (StackFrame*)frame->savedSP;
61 /* we do these next two checks after going to the next frame
62 because the LR for the first stack frame in the loop
63 is not set up on purpose, so we shouldn't check it. */
64 if ((frame->savedLR & ~3) == 0)
65 break; /* if the next LR is bogus, stop */
66 if ((~(frame->savedLR) & ~3) == 0)
71 /* GC_printf("FindTopOfStack finish at sp = %p\n", frame); */
74 return (unsigned long)frame;
77 #ifdef DARWIN_DONT_PARSE_STACK
78 void GC_push_all_stacks()
85 GC_THREAD_STATE_T state;
86 /* MACHINE_THREAD_STATE_COUNT doesn't seem to be defined everywhere. */
87 /* Hence we use our own version. */
88 mach_msg_type_number_t thread_state_count = GC_MACH_THREAD_STATE_COUNT;
91 if (!GC_thr_initialized)
94 for(i = 0; i < THREAD_TABLE_SZ; i++) {
95 for(p = GC_threads[i]; p != 0; p = p->next) {
96 if(p->flags & FINISHED) continue;
97 if(pthread_equal(p->id, me)) {
100 /* Get the thread state (registers, etc) */
101 r = thread_get_state(p->stop_info.mach_thread, GC_MACH_THREAD_STATE,
102 (natural_t*)&state, &thread_state_count);
104 # ifdef DEBUG_THREADS
105 GC_printf("thread_get_state return value = %d\n", r);
108 if(r != KERN_SUCCESS)
109 ABORT("thread_get_state failed");
112 lo = (void*)state . THREAD_FLD (esp);
113 GC_push_one(state . THREAD_FLD (eax));
114 GC_push_one(state . THREAD_FLD (ebx));
115 GC_push_one(state . THREAD_FLD (ecx));
116 GC_push_one(state . THREAD_FLD (edx));
117 GC_push_one(state . THREAD_FLD (edi));
118 GC_push_one(state . THREAD_FLD (esi));
119 GC_push_one(state . THREAD_FLD (ebp));
121 # elif defined(X86_64)
122 lo = (void*)state . THREAD_FLD (rsp);
123 GC_push_one(state . THREAD_FLD (rax));
124 GC_push_one(state . THREAD_FLD (rbx));
125 GC_push_one(state . THREAD_FLD (rcx));
126 GC_push_one(state . THREAD_FLD (rdx));
127 GC_push_one(state . THREAD_FLD (rdi));
128 GC_push_one(state . THREAD_FLD (rsi));
129 GC_push_one(state . THREAD_FLD (rbp));
130 GC_push_one(state . THREAD_FLD (rsp));
131 GC_push_one(state . THREAD_FLD (r8));
132 GC_push_one(state . THREAD_FLD (r9));
133 GC_push_one(state . THREAD_FLD (r10));
134 GC_push_one(state . THREAD_FLD (r11));
135 GC_push_one(state . THREAD_FLD (r12));
136 GC_push_one(state . THREAD_FLD (r13));
137 GC_push_one(state . THREAD_FLD (r14));
138 GC_push_one(state . THREAD_FLD (r15));
139 GC_push_one(state . THREAD_FLD (rip));
140 GC_push_one(state . THREAD_FLD (rflags));
141 GC_push_one(state . THREAD_FLD (cs));
142 GC_push_one(state . THREAD_FLD (fs));
143 GC_push_one(state . THREAD_FLD (gs));
145 # elif defined(POWERPC)
146 lo = (void*)(state . THREAD_FLD (r1) - PPC_RED_ZONE_SIZE);
148 GC_push_one(state . THREAD_FLD (r0));
149 GC_push_one(state . THREAD_FLD (r2));
150 GC_push_one(state . THREAD_FLD (r3));
151 GC_push_one(state . THREAD_FLD (r4));
152 GC_push_one(state . THREAD_FLD (r5));
153 GC_push_one(state . THREAD_FLD (r6));
154 GC_push_one(state . THREAD_FLD (r7));
155 GC_push_one(state . THREAD_FLD (r8));
156 GC_push_one(state . THREAD_FLD (r9));
157 GC_push_one(state . THREAD_FLD (r10));
158 GC_push_one(state . THREAD_FLD (r11));
159 GC_push_one(state . THREAD_FLD (r12));
160 GC_push_one(state . THREAD_FLD (r13));
161 GC_push_one(state . THREAD_FLD (r14));
162 GC_push_one(state . THREAD_FLD (r15));
163 GC_push_one(state . THREAD_FLD (r16));
164 GC_push_one(state . THREAD_FLD (r17));
165 GC_push_one(state . THREAD_FLD (r18));
166 GC_push_one(state . THREAD_FLD (r19));
167 GC_push_one(state . THREAD_FLD (r20));
168 GC_push_one(state . THREAD_FLD (r21));
169 GC_push_one(state . THREAD_FLD (r22));
170 GC_push_one(state . THREAD_FLD (r23));
171 GC_push_one(state . THREAD_FLD (r24));
172 GC_push_one(state . THREAD_FLD (r25));
173 GC_push_one(state . THREAD_FLD (r26));
174 GC_push_one(state . THREAD_FLD (r27));
175 GC_push_one(state . THREAD_FLD (r28));
176 GC_push_one(state . THREAD_FLD (r29));
177 GC_push_one(state . THREAD_FLD (r30));
178 GC_push_one(state . THREAD_FLD (r31));
180 # error FIXME for non-x86 || ppc architectures
183 if(p->flags & MAIN_THREAD)
188 GC_printf("Darwin: Stack for thread 0x%lx = [%lx,%lx)\n",
189 (unsigned long) p -> id, (unsigned long) lo,
192 GC_push_all_stack(lo, hi);
193 } /* for(p=GC_threads[i]...) */
194 } /* for(i=0;i<THREAD_TABLE_SZ...) */
197 #else /* !DARWIN_DONT_PARSE_STACK; Use FindTopOfStack() */
199 void GC_push_all_stacks()
206 thread_act_array_t act_list = 0;
207 mach_msg_type_number_t listcount = 0;
209 me = mach_thread_self();
210 if (!GC_thr_initialized)
213 my_task = current_task();
214 r = task_threads(my_task, &act_list, &listcount);
215 if(r != KERN_SUCCESS)
216 ABORT("task_threads failed");
217 for(i = 0; i < listcount; i++) {
218 thread_act_t thread = act_list[i];
221 hi = (ptr_t)FindTopOfStack(0);
223 # if defined(POWERPC)
224 GC_THREAD_STATE_T info;
225 mach_msg_type_number_t outCount = THREAD_STATE_MAX;
226 r = thread_get_state(thread, GC_MACH_THREAD_STATE, (natural_t *)&info,
228 if(r != KERN_SUCCESS)
229 ABORT("task_get_state failed");
231 lo = (void*)(info . THREAD_FLD (r1) - PPC_RED_ZONE_SIZE);
232 hi = (ptr_t)FindTopOfStack(info . THREAD_FLD (r1));
234 GC_push_one(info . THREAD_FLD (r0));
235 GC_push_one(info . THREAD_FLD (r2));
236 GC_push_one(info . THREAD_FLD (r3));
237 GC_push_one(info . THREAD_FLD (r4));
238 GC_push_one(info . THREAD_FLD (r5));
239 GC_push_one(info . THREAD_FLD (r6));
240 GC_push_one(info . THREAD_FLD (r7));
241 GC_push_one(info . THREAD_FLD (r8));
242 GC_push_one(info . THREAD_FLD (r9));
243 GC_push_one(info . THREAD_FLD (r10));
244 GC_push_one(info . THREAD_FLD (r11));
245 GC_push_one(info . THREAD_FLD (r12));
246 GC_push_one(info . THREAD_FLD (r13));
247 GC_push_one(info . THREAD_FLD (r14));
248 GC_push_one(info . THREAD_FLD (r15));
249 GC_push_one(info . THREAD_FLD (r16));
250 GC_push_one(info . THREAD_FLD (r17));
251 GC_push_one(info . THREAD_FLD (r18));
252 GC_push_one(info . THREAD_FLD (r19));
253 GC_push_one(info . THREAD_FLD (r20));
254 GC_push_one(info . THREAD_FLD (r21));
255 GC_push_one(info . THREAD_FLD (r22));
256 GC_push_one(info . THREAD_FLD (r23));
257 GC_push_one(info . THREAD_FLD (r24));
258 GC_push_one(info . THREAD_FLD (r25));
259 GC_push_one(info . THREAD_FLD (r26));
260 GC_push_one(info . THREAD_FLD (r27));
261 GC_push_one(info . THREAD_FLD (r28));
262 GC_push_one(info . THREAD_FLD (r29));
263 GC_push_one(info . THREAD_FLD (r30));
264 GC_push_one(info . THREAD_FLD (r31));
267 /* FIXME: Remove after testing: */
268 WARN("This is completely untested and likely will not work\n", 0);
269 GC_THREAD_STATE_T info;
270 mach_msg_type_number_t outCount = THREAD_STATE_MAX;
271 r = thread_get_state(thread, GC_MACH_THREAD_STATE, (natural_t *)&info,
273 if(r != KERN_SUCCESS)
274 ABORT("task_get_state failed");
276 lo = (void*)info . THREAD_FLD (esp);
277 hi = (ptr_t)FindTopOfStack(info . THREAD_FLD (esp));
279 GC_push_one(info . THREAD_FLD (eax));
280 GC_push_one(info . THREAD_FLD (ebx));
281 GC_push_one(info . THREAD_FLD (ecx));
282 GC_push_one(info . THREAD_FLD (edx));
283 GC_push_one(info . THREAD_FLD (edi));
284 GC_push_one(info . THREAD_FLD (esi));
285 /* GC_push_one(info . THREAD_FLD (ebp)); */
286 /* GC_push_one(info . THREAD_FLD (esp)); */
287 GC_push_one(info . THREAD_FLD (ss));
288 GC_push_one(info . THREAD_FLD (eip));
289 GC_push_one(info . THREAD_FLD (cs));
290 GC_push_one(info . THREAD_FLD (ds));
291 GC_push_one(info . THREAD_FLD (es));
292 GC_push_one(info . THREAD_FLD (fs));
293 GC_push_one(info . THREAD_FLD (gs));
295 # elif defined(X86_64)
296 GC_THREAD_STATE_T info;
297 mach_msg_type_number_t outCount = THREAD_STATE_MAX;
298 r = thread_get_state(thread, GC_MACH_THREAD_STATE, (natural_t *)&info,
300 if(r != KERN_SUCCESS)
301 ABORT("task_get_state failed");
303 lo = (void*)info . THREAD_FLD (rsp);
304 hi = (ptr_t)FindTopOfStack(info . THREAD_FLD (rsp));
306 GC_push_one(info . THREAD_FLD (rax));
307 GC_push_one(info . THREAD_FLD (rbx));
308 GC_push_one(info . THREAD_FLD (rcx));
309 GC_push_one(info . THREAD_FLD (rdx));
310 GC_push_one(info . THREAD_FLD (rdi));
311 GC_push_one(info . THREAD_FLD (rsi));
312 GC_push_one(info . THREAD_FLD (rbp));
313 GC_push_one(info . THREAD_FLD (rsp));
314 GC_push_one(info . THREAD_FLD (r8));
315 GC_push_one(info . THREAD_FLD (r9));
316 GC_push_one(info . THREAD_FLD (r10));
317 GC_push_one(info . THREAD_FLD (r11));
318 GC_push_one(info . THREAD_FLD (r12));
319 GC_push_one(info . THREAD_FLD (r13));
320 GC_push_one(info . THREAD_FLD (r14));
321 GC_push_one(info . THREAD_FLD (r15));
322 GC_push_one(info . THREAD_FLD (rip));
323 GC_push_one(info . THREAD_FLD (rflags));
324 GC_push_one(info . THREAD_FLD (cs));
325 GC_push_one(info . THREAD_FLD (fs));
326 GC_push_one(info . THREAD_FLD (gs));
329 # error FIXME for non-x86 || ppc architectures
333 GC_printf("Darwin: Stack for thread 0x%lx = [%p,%p)\n",
334 (unsigned long) thread, lo, hi);
336 GC_push_all_stack(lo, hi);
337 mach_port_deallocate(my_task, thread);
338 } /* for(p=GC_threads[i]...) */
339 vm_deallocate(my_task, (vm_address_t)act_list,
340 sizeof(thread_t) * listcount);
341 mach_port_deallocate(my_task, me);
343 #endif /* !DARWIN_DONT_PARSE_STACK */
345 static mach_port_t GC_mach_handler_thread;
346 static int GC_use_mach_handler_thread = 0;
348 static struct GC_mach_thread GC_mach_threads[THREAD_TABLE_SZ];
349 static int GC_mach_threads_count;
355 for (i = 0; i < THREAD_TABLE_SZ; i++) {
356 GC_mach_threads[i].thread = 0;
357 GC_mach_threads[i].already_suspended = 0;
359 GC_mach_threads_count = 0;
362 /* returns true if there's a thread in act_list that wasn't in old_list */
363 int GC_suspend_thread_list(thread_act_array_t act_list, int count,
364 thread_act_array_t old_list, int old_count)
366 mach_port_t my_thread = mach_thread_self();
371 for(i = 0; i < count; i++) {
372 thread_act_t thread = act_list[i];
374 GC_printf("Attempting to suspend thread %p\n", thread);
376 /* find the current thread in the old list */
378 for(j = 0; j < old_count; j++) {
379 thread_act_t old_thread = old_list[j];
380 if (old_thread == thread) {
386 /* add it to the GC_mach_threads list */
387 GC_mach_threads[GC_mach_threads_count].thread = thread;
388 /* default is not suspended */
389 GC_mach_threads[GC_mach_threads_count].already_suspended = 0;
393 if (thread != my_thread
394 && (!GC_use_mach_handler_thread
395 || (GC_use_mach_handler_thread
396 && GC_mach_handler_thread != thread))) {
397 struct thread_basic_info info;
398 mach_msg_type_number_t outCount = THREAD_INFO_MAX;
399 kern_return_t kern_result = thread_info(thread, THREAD_BASIC_INFO,
400 (thread_info_t)&info, &outCount);
401 if(kern_result != KERN_SUCCESS) {
402 /* the thread may have quit since the thread_threads () call
403 * we mark already_suspended so it's not dealt with anymore later
406 GC_mach_threads[GC_mach_threads_count].already_suspended = TRUE;
407 GC_mach_threads_count++;
412 GC_printf("Thread state for 0x%lx = %d\n", (unsigned long)thread,
416 GC_mach_threads[GC_mach_threads_count].already_suspended
417 = info.suspend_count;
419 if (info.suspend_count)
423 GC_printf("Suspending 0x%lx\n", (unsigned long)thread);
425 /* Suspend the thread */
426 kern_result = thread_suspend(thread);
427 if(kern_result != KERN_SUCCESS) {
428 /* the thread may have quit since the thread_threads () call
429 * we mark already_suspended so it's not dealt with anymore later
432 GC_mach_threads[GC_mach_threads_count].already_suspended = TRUE;
433 GC_mach_threads_count++;
438 if (!found) GC_mach_threads_count++;
440 mach_port_deallocate(current_task(), my_thread);
445 /* Caller holds allocation lock. */
448 unsigned int i, changes;
449 task_t my_task = current_task();
450 mach_port_t my_thread = mach_thread_self();
451 kern_return_t kern_result;
452 thread_act_array_t act_list, prev_list;
453 mach_msg_type_number_t listcount, prevcount;
456 GC_printf("Stopping the world from 0x%lx\n",
457 (unsigned long)mach_thread_self());
460 /* clear out the mach threads list table */
463 /* Make sure all free list construction has stopped before we start. */
464 /* No new construction can start, since free list construction is */
465 /* required to acquire and release the GC lock before it starts, */
466 /* and we have the lock. */
467 # ifdef PARALLEL_MARK
468 GC_acquire_mark_lock();
469 GC_ASSERT(GC_fl_builder_count == 0);
470 /* We should have previously waited for it to become zero. */
471 # endif /* PARALLEL_MARK */
473 /* Loop stopping threads until you have gone over the whole list
474 twice without a new one appearing. thread_create() won't
475 return (and thus the thread stop) until the new thread
476 exists, so there is no window whereby you could stop a
477 thread, recognise it is stopped, but then have a new thread
478 it created before stopping show up later.
481 /* FIXME: This seems to erroneously stop the parallel marker threads? */
488 kern_result = task_threads(my_task, &act_list, &listcount);
490 if(kern_result == KERN_SUCCESS) {
491 result = GC_suspend_thread_list(act_list, listcount, prev_list,
495 if(prev_list != NULL) {
496 for(i = 0; i < prevcount; i++)
497 mach_port_deallocate(my_task, prev_list[i]);
499 vm_deallocate(my_task, (vm_address_t)prev_list,
500 sizeof(thread_t) * prevcount);
502 prev_list = act_list;
503 prevcount = listcount;
506 GC_ASSERT(prev_list != 0);
507 for(i = 0; i < prevcount; i++)
508 mach_port_deallocate(my_task, prev_list[i]);
510 vm_deallocate(my_task, (vm_address_t)act_list,
511 sizeof(thread_t) * listcount);
515 extern void GC_mprotect_stop();
520 # ifdef PARALLEL_MARK
521 GC_release_mark_lock();
524 GC_printf("World stopped from 0x%lx\n", (unsigned long)my_thread);
527 mach_port_deallocate(my_task, my_thread);
530 /* Caller holds allocation lock, and has held it continuously since */
531 /* the world stopped. */
532 void GC_start_world()
534 task_t my_task = current_task();
535 mach_port_t my_thread = mach_thread_self();
538 kern_return_t kern_result;
539 thread_act_array_t act_list;
540 mach_msg_type_number_t listcount;
541 struct thread_basic_info info;
542 mach_msg_type_number_t outCount = THREAD_INFO_MAX;
545 GC_printf("World starting\n");
550 extern void GC_mprotect_resume();
551 GC_mprotect_resume();
555 kern_result = task_threads(my_task, &act_list, &listcount);
556 for(i = 0; i < listcount; i++) {
557 thread_act_t thread = act_list[i];
558 if (thread != my_thread
559 && (!GC_use_mach_handler_thread
560 || (GC_use_mach_handler_thread
561 && GC_mach_handler_thread != thread))) {
562 for(j = 0; j < GC_mach_threads_count; j++) {
563 if (thread == GC_mach_threads[j].thread) {
564 if (GC_mach_threads[j].already_suspended) {
566 GC_printf("Not resuming already suspended thread %p\n", thread);
570 kern_result = thread_info(thread, THREAD_BASIC_INFO,
571 (thread_info_t)&info, &outCount);
572 if(kern_result != KERN_SUCCESS)
573 ABORT("thread_info failed");
575 GC_printf("Thread state for 0x%lx = %d\n", (unsigned long)thread,
577 GC_printf("Resuming 0x%lx\n", (unsigned long)thread);
579 /* Resume the thread */
580 kern_result = thread_resume(thread);
581 if(kern_result != KERN_SUCCESS)
582 ABORT("thread_resume failed");
586 mach_port_deallocate(my_task, thread);
588 vm_deallocate(my_task, (vm_address_t)act_list,
589 sizeof(thread_t) * listcount);
591 mach_port_deallocate(my_task, my_thread);
593 GC_printf("World started\n");
597 void GC_darwin_register_mach_handler_thread(mach_port_t thread)
599 GC_mach_handler_thread = thread;
600 GC_use_mach_handler_thread = 1;