1: #include "private/pthread_support.h"
2:
3:
4:
5: # if defined(GC_DARWIN_THREADS)
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17: #ifdef POWERPC
18: # if CPP_WORDSZ == 32
19: # define PPC_RED_ZONE_SIZE 224
20: # elif CPP_WORDSZ == 64
21: # define PPC_RED_ZONE_SIZE 320
22: # endif
23: #endif
24:
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;
31: } StackFrame;
32:
33: unsigned long FindTopOfStack(unsigned int stack_start) {
34: StackFrame *frame;
35:
36: if (stack_start == 0) {
37: # ifdef POWERPC
38: # if CPP_WORDSZ == 32
39: __asm__ volatile("lwz %0,0(r1)" : "=r" (frame));
40: # else
41: __asm__ volatile("ld %0,0(r1)" : "=r" (frame));
42: # endif
43: # endif
44: } else {
45: frame = (StackFrame *)stack_start;
46: }
47:
48: # ifdef DEBUG_THREADS
49:
50: # endif
51: do {
52: if (frame->savedSP == 0) break;
53:
54:
55: frame = (StackFrame*)frame->savedSP;
56:
57:
58:
59:
60: if ((frame->savedLR & ~3) == 0) break;
61: if ((~(frame->savedLR) & ~3) == 0) break;
62: } while (1);
63:
64: # ifdef DEBUG_THREADS
65:
66: # endif
67:
68: return (unsigned long)frame;
69: }
70:
71: #ifdef DARWIN_DONT_PARSE_STACK
72: void GC_push_all_stacks() {
73: int i;
74: kern_return_t r;
75: GC_thread p;
76: pthread_t me;
77: ptr_t lo, hi;
78: #if defined(POWERPC)
79: ppc_thread_state_t state;
80: mach_msg_type_number_t thread_state_count = PPC_THREAD_STATE_COUNT;
81: #elif defined(I386)
82: i386_thread_state_t state;
83: mach_msg_type_number_t thread_state_count = i386_THREAD_STATE_COUNT;
84: #else
85: # error FIXME for non-x86 || ppc architectures
86: mach_msg_type_number_t thread_state_count = MACHINE_THREAD_STATE_COUNT;
87: #endif
88:
89: me = pthread_self();
90: if (!GC_thr_initialized) GC_thr_init();
91:
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)) {
96: lo = GC_approx_sp();
97: } else {
98:
99: r = thread_get_state(
100: p->stop_info.mach_thread,
101: GC_MACH_THREAD_STATE_FLAVOR,
102: (natural_t*)&state,
103: &thread_state_count);
104: if(r != KERN_SUCCESS) ABORT("thread_get_state failed");
105:
106: #if defined(I386)
107: lo = state.esp;
108:
109: GC_push_one(state.eax);
110: GC_push_one(state.ebx);
111: GC_push_one(state.ecx);
112: GC_push_one(state.edx);
113: GC_push_one(state.edi);
114: GC_push_one(state.esi);
115: GC_push_one(state.ebp);
116: #elif defined(POWERPC)
117: lo = (void*)(state.r1 - PPC_RED_ZONE_SIZE);
118:
119: GC_push_one(state.r0);
120: GC_push_one(state.r2);
121: GC_push_one(state.r3);
122: GC_push_one(state.r4);
123: GC_push_one(state.r5);
124: GC_push_one(state.r6);
125: GC_push_one(state.r7);
126: GC_push_one(state.r8);
127: GC_push_one(state.r9);
128: GC_push_one(state.r10);
129: GC_push_one(state.r11);
130: GC_push_one(state.r12);
131: GC_push_one(state.r13);
132: GC_push_one(state.r14);
133: GC_push_one(state.r15);
134: GC_push_one(state.r16);
135: GC_push_one(state.r17);
136: GC_push_one(state.r18);
137: GC_push_one(state.r19);
138: GC_push_one(state.r20);
139: GC_push_one(state.r21);
140: GC_push_one(state.r22);
141: GC_push_one(state.r23);
142: GC_push_one(state.r24);
143: GC_push_one(state.r25);
144: GC_push_one(state.r26);
145: GC_push_one(state.r27);
146: GC_push_one(state.r28);
147: GC_push_one(state.r29);
148: GC_push_one(state.r30);
149: GC_push_one(state.r31);
150: #else
151: # error FIXME for non-x86 || ppc architectures
152: #endif
153: }
154: if(p->flags & MAIN_THREAD)
155: hi = GC_stackbottom;
156: else
157: hi = p->stack_end;
158: #if DEBUG_THREADS
159: GC_printf3("Darwin: Stack for thread 0x%lx = [%lx,%lx)\n",
160: (unsigned long) p -> id,
161: (unsigned long) lo,
162: (unsigned long) hi
163: );
164: #endif
165: GC_push_all_stack(lo,hi);
166: }
167: }
168: }
169:
170: #else
171:
172: void GC_push_all_stacks() {
173: int i;
174: task_t my_task;
175: kern_return_t r;
176: mach_port_t me;
177: ptr_t lo, hi;
178: thread_act_array_t act_list = 0;
179: mach_msg_type_number_t listcount = 0;
180:
181: me = mach_thread_self();
182: if (!GC_thr_initialized) GC_thr_init();
183:
184: my_task = current_task();
185: r = task_threads(my_task, &act_list, &listcount);
186: if(r != KERN_SUCCESS) ABORT("task_threads failed");
187: for(i = 0; i < listcount; i++) {
188: thread_act_t thread = act_list[i];
189: if (thread == me) {
190: lo = GC_approx_sp();
191: hi = (ptr_t)FindTopOfStack(0);
192: } else {
193: # if defined(POWERPC)
194: # if CPP_WORDSZ == 32
195: ppc_thread_state_t info;
196: # else
197: ppc_thread_state64_t info;
198: # endif
199: mach_msg_type_number_t outCount = THREAD_STATE_MAX;
200: r = thread_get_state(thread, GC_MACH_THREAD_STATE_FLAVOR,
201: (natural_t *)&info, &outCount);
202: if(r != KERN_SUCCESS) ABORT("task_get_state failed");
203:
204: lo = (void*)(info.r1 - PPC_RED_ZONE_SIZE);
205: hi = (ptr_t)FindTopOfStack(info.r1);
206:
207: GC_push_one(info.r0);
208: GC_push_one(info.r2);
209: GC_push_one(info.r3);
210: GC_push_one(info.r4);
211: GC_push_one(info.r5);
212: GC_push_one(info.r6);
213: GC_push_one(info.r7);
214: GC_push_one(info.r8);
215: GC_push_one(info.r9);
216: GC_push_one(info.r10);
217: GC_push_one(info.r11);
218: GC_push_one(info.r12);
219: GC_push_one(info.r13);
220: GC_push_one(info.r14);
221: GC_push_one(info.r15);
222: GC_push_one(info.r16);
223: GC_push_one(info.r17);
224: GC_push_one(info.r18);
225: GC_push_one(info.r19);
226: GC_push_one(info.r20);
227: GC_push_one(info.r21);
228: GC_push_one(info.r22);
229: GC_push_one(info.r23);
230: GC_push_one(info.r24);
231: GC_push_one(info.r25);
232: GC_push_one(info.r26);
233: GC_push_one(info.r27);
234: GC_push_one(info.r28);
235: GC_push_one(info.r29);
236: GC_push_one(info.r30);
237: GC_push_one(info.r31);
238: # else
239:
240: WARN("This is completely untested and likely will not work\n", 0);
241: i386_thread_state_t info;
242: mach_msg_type_number_t outCount = THREAD_STATE_MAX;
243: r = thread_get_state(thread, GC_MACH_THREAD_STATE_FLAVOR,
244: (natural_t *)&info, &outCount);
245: if(r != KERN_SUCCESS) ABORT("task_get_state failed");
246:
247: lo = (void*)info.esp;
248: hi = (ptr_t)FindTopOfStack(info.esp);
249:
250: GC_push_one(info.eax);
251: GC_push_one(info.ebx);
252: GC_push_one(info.ecx);
253: GC_push_one(info.edx);
254: GC_push_one(info.edi);
255: GC_push_one(info.esi);
256:
257:
258: GC_push_one(info.ss);
259: GC_push_one(info.eip);
260: GC_push_one(info.cs);
261: GC_push_one(info.ds);
262: GC_push_one(info.es);
263: GC_push_one(info.fs);
264: GC_push_one(info.gs);
265: # endif
266: }
267: # if DEBUG_THREADS
268: GC_printf3("Darwin: Stack for thread 0x%lx = [%lx,%lx)\n",
269: (unsigned long) thread,
270: (unsigned long) lo,
271: (unsigned long) hi
272: );
273: # endif
274: GC_push_all_stack(lo, hi);
275: mach_port_deallocate(my_task, thread);
276: }
277: vm_deallocate(my_task, (vm_address_t)act_list, sizeof(thread_t) * listcount);
278: mach_port_deallocate(my_task, me);
279: }
280: #endif
281:
282: static mach_port_t GC_mach_handler_thread;
283: static int GC_use_mach_handler_thread = 0;
284:
285: static struct GC_mach_thread GC_mach_threads[THREAD_TABLE_SZ];
286: static int GC_mach_threads_count;
287:
288: void GC_stop_init() {
289: int i;
290:
291: for (i = 0; i < THREAD_TABLE_SZ; i++) {
292: GC_mach_threads[i].thread = 0;
293: GC_mach_threads[i].already_suspended = 0;
294: }
295: GC_mach_threads_count = 0;
296: }
297:
298:
299: int GC_suspend_thread_list(thread_act_array_t act_list, int count,
300: thread_act_array_t old_list, int old_count) {
301: mach_port_t my_thread = mach_thread_self();
302: int i, j;
303:
304: int changed = 0;
305:
306: for(i = 0; i < count; i++) {
307: thread_act_t thread = act_list[i];
308: # if DEBUG_THREADS
309: GC_printf1("Attempting to suspend thread %p\n", thread);
310: # endif
311:
312: int found = 0;
313: for(j = 0; j < old_count; j++) {
314: thread_act_t old_thread = old_list[j];
315: if (old_thread == thread) {
316: found = 1;
317: break;
318: }
319: }
320: if (!found) {
321:
322: GC_mach_threads[GC_mach_threads_count].thread = thread;
323:
324: GC_mach_threads[GC_mach_threads_count].already_suspended = 0;
325: changed = 1;
326: }
327:
328: if (thread != my_thread &&
329: (!GC_use_mach_handler_thread
330: || (GC_use_mach_handler_thread
331: && GC_mach_handler_thread != thread))) {
332: struct thread_basic_info info;
333: mach_msg_type_number_t outCount = THREAD_INFO_MAX;
334: kern_return_t kern_result = thread_info(thread, THREAD_BASIC_INFO,
335: (thread_info_t)&info, &outCount);
336: if(kern_result != KERN_SUCCESS) {
337:
338:
339:
340: if (!found) {
341: GC_mach_threads[GC_mach_threads_count].already_suspended = TRUE;
342: GC_mach_threads_count++;
343: }
344: continue;
345: }
346: # if DEBUG_THREADS
347: GC_printf2("Thread state for 0x%lx = %d\n", thread, info.run_state);
348: # endif
349: if (!found) {
350: GC_mach_threads[GC_mach_threads_count].already_suspended = info.suspend_count;
351: }
352: if (info.suspend_count) continue;
353:
354: # if DEBUG_THREADS
355: GC_printf1("Suspending 0x%lx\n", thread);
356: # endif
357:
358: kern_result = thread_suspend(thread);
359: if(kern_result != KERN_SUCCESS) {
360:
361:
362:
363: if (!found) {
364: GC_mach_threads[GC_mach_threads_count].already_suspended = TRUE;
365: GC_mach_threads_count++;
366: }
367: continue;
368: }
369: }
370: if (!found) GC_mach_threads_count++;
371: }
372: mach_port_deallocate(current_task(), my_thread);
373: return changed;
374: }
375:
376:
377:
378: void GC_stop_world()
379: {
380: int i, changes;
381: GC_thread p;
382: task_t my_task = current_task();
383: mach_port_t my_thread = mach_thread_self();
384: kern_return_t kern_result;
385: thread_act_array_t act_list, prev_list;
386: mach_msg_type_number_t listcount, prevcount;
387:
388: # if DEBUG_THREADS
389: GC_printf1("Stopping the world from 0x%lx\n", mach_thread_self());
390: # endif
391:
392:
393: GC_stop_init();
394:
395:
396:
397:
398:
399: # ifdef PARALLEL_MARK
400: GC_acquire_mark_lock();
401: GC_ASSERT(GC_fl_builder_count == 0);
402:
403: # endif
404:
405:
406:
407:
408:
409:
410:
411:
412:
413: changes = 1;
414: prev_list = NULL;
415: prevcount = 0;
416: do {
417: int result;
418: kern_result = task_threads(my_task, &act_list, &listcount);
419:
420: if(kern_result == KERN_SUCCESS) {
421: result = GC_suspend_thread_list(act_list, listcount,
422: prev_list, prevcount);
423: changes = result;
424:
425: if(prev_list != NULL) {
426: for(i = 0; i < prevcount; i++)
427: mach_port_deallocate(my_task, prev_list[i]);
428:
429: vm_deallocate(my_task, (vm_address_t)prev_list, sizeof(thread_t) * prevcount);
430: }
431:
432: prev_list = act_list;
433: prevcount = listcount;
434: }
435: } while (changes);
436:
437: for(i = 0; i < listcount; i++)
438: mach_port_deallocate(my_task, act_list[i]);
439:
440: vm_deallocate(my_task, (vm_address_t)act_list, sizeof(thread_t) * listcount);
441:
442:
443: # ifdef MPROTECT_VDB
444: if(GC_incremental) {
445: extern void GC_mprotect_stop();
446: GC_mprotect_stop();
447: }
448: # endif
449:
450: # ifdef PARALLEL_MARK
451: GC_release_mark_lock();
452: # endif
453: #if DEBUG_THREADS
454: GC_printf1("World stopped from 0x%lx\n", my_thread);
455: #endif
456:
457: mach_port_deallocate(my_task, my_thread);
458: }
459:
460:
461:
462: void GC_start_world()
463: {
464: task_t my_task = current_task();
465: mach_port_t my_thread = mach_thread_self();
466: int i, j;
467: GC_thread p;
468: kern_return_t kern_result;
469: thread_act_array_t act_list;
470: mach_msg_type_number_t listcount;
471: struct thread_basic_info info;
472: mach_msg_type_number_t outCount = THREAD_INFO_MAX;
473:
474: # if DEBUG_THREADS
475: GC_printf0("World starting\n");
476: # endif
477:
478: # ifdef MPROTECT_VDB
479: if(GC_incremental) {
480: extern void GC_mprotect_resume();
481: GC_mprotect_resume();
482: }
483: # endif
484:
485: kern_result = task_threads(my_task, &act_list, &listcount);
486: for(i = 0; i < listcount; i++) {
487: thread_act_t thread = act_list[i];
488: if (thread != my_thread &&
489: (!GC_use_mach_handler_thread ||
490: (GC_use_mach_handler_thread && GC_mach_handler_thread != thread))) {
491: for(j = 0; j < GC_mach_threads_count; j++) {
492: if (thread == GC_mach_threads[j].thread) {
493: if (GC_mach_threads[j].already_suspended) {
494: # if DEBUG_THREADS
495: GC_printf1("Not resuming already suspended thread %p\n", thread);
496: # endif
497: continue;
498: }
499: kern_result = thread_info(thread, THREAD_BASIC_INFO,
500: (thread_info_t)&info, &outCount);
501: if(kern_result != KERN_SUCCESS) ABORT("thread_info failed");
502: # if DEBUG_THREADS
503: GC_printf2("Thread state for 0x%lx = %d\n", thread,
504: info.run_state);
505: GC_printf1("Resuming 0x%lx\n", thread);
506: # endif
507:
508: kern_result = thread_resume(thread);
509: if(kern_result != KERN_SUCCESS) ABORT("thread_resume failed");
510: }
511: }
512: }
513:
514: mach_port_deallocate(my_task, thread);
515: }
516: vm_deallocate(my_task, (vm_address_t)act_list, sizeof(thread_t) * listcount);
517:
518: mach_port_deallocate(my_task, my_thread);
519: # if DEBUG_THREADS
520: GC_printf0("World started\n");
521: # endif
522: }
523:
524: void GC_darwin_register_mach_handler_thread(mach_port_t thread) {
525: GC_mach_handler_thread = thread;
526: GC_use_mach_handler_thread = 1;
527: }
528:
529: #endif