1
#include "private/pthread_support.h"
3
# if defined(GC_DARWIN_THREADS)
5
/* From "Inside Mac OS X - Mach-O Runtime Architecture" published by Apple
7
"The space beneath the stack pointer, where a new stack frame would normally
8
be allocated, is called the red zone. This area as shown in Figure 3-2 may
9
be used for any purpose as long as a new stack frame does not need to be
12
Page 50: "If a leaf procedure's red zone usage would exceed 224 bytes, then
13
it must set up a stack frame just like routines that call other routines."
17
# define PPC_RED_ZONE_SIZE 224
18
# elif CPP_WORDSZ == 64
19
# define PPC_RED_ZONE_SIZE 320
23
typedef struct StackFrame {
24
unsigned long savedSP;
25
unsigned long savedCR;
26
unsigned long savedLR;
27
unsigned long reserved[2];
28
unsigned long savedRTOC;
31
unsigned long FindTopOfStack(unsigned int stack_start) {
34
if (stack_start == 0) {
37
__asm__ volatile("lwz %0,0(r1)" : "=r" (frame));
39
__asm__ volatile("ldz %0,0(r1)" : "=r" (frame));
43
frame = (StackFrame *)stack_start;
47
/* GC_printf1("FindTopOfStack start at sp = %p\n", frame); */
50
if (frame->savedSP == 0) break;
51
/* if there are no more stack frames, stop */
53
frame = (StackFrame*)frame->savedSP;
55
/* we do these next two checks after going to the next frame
56
because the LR for the first stack frame in the loop
57
is not set up on purpose, so we shouldn't check it. */
58
if ((frame->savedLR & ~3) == 0) break; /* if the next LR is bogus, stop */
59
if ((~(frame->savedLR) & ~3) == 0) break; /* ditto */
63
/* GC_printf1("FindTopOfStack finish at sp = %p\n", frame); */
66
return (unsigned long)frame;
69
#ifdef DARWIN_DONT_PARSE_STACK
70
void GC_push_all_stacks() {
76
ppc_thread_state_t state;
77
mach_msg_type_number_t thread_state_count = MACHINE_THREAD_STATE_COUNT;
80
if (!GC_thr_initialized) GC_thr_init();
82
for(i=0;i<THREAD_TABLE_SZ;i++) {
83
for(p=GC_threads[i];p!=0;p=p->next) {
84
if(p -> flags & FINISHED) continue;
85
if(pthread_equal(p->id,me)) {
88
/* Get the thread state (registers, etc) */
90
p->stop_info.mach_thread,
94
if(r != KERN_SUCCESS) ABORT("thread_get_state failed");
96
lo = (void*)(state.r1 - PPC_RED_ZONE_SIZE);
98
GC_push_one(state.r0);
99
GC_push_one(state.r2);
100
GC_push_one(state.r3);
101
GC_push_one(state.r4);
102
GC_push_one(state.r5);
103
GC_push_one(state.r6);
104
GC_push_one(state.r7);
105
GC_push_one(state.r8);
106
GC_push_one(state.r9);
107
GC_push_one(state.r10);
108
GC_push_one(state.r11);
109
GC_push_one(state.r12);
110
GC_push_one(state.r13);
111
GC_push_one(state.r14);
112
GC_push_one(state.r15);
113
GC_push_one(state.r16);
114
GC_push_one(state.r17);
115
GC_push_one(state.r18);
116
GC_push_one(state.r19);
117
GC_push_one(state.r20);
118
GC_push_one(state.r21);
119
GC_push_one(state.r22);
120
GC_push_one(state.r23);
121
GC_push_one(state.r24);
122
GC_push_one(state.r25);
123
GC_push_one(state.r26);
124
GC_push_one(state.r27);
125
GC_push_one(state.r28);
126
GC_push_one(state.r29);
127
GC_push_one(state.r30);
128
GC_push_one(state.r31);
130
if(p->flags & MAIN_THREAD)
135
GC_printf3("Darwin: Stack for thread 0x%lx = [%lx,%lx)\n",
136
(unsigned long) p -> id,
141
GC_push_all_stack(lo,hi);
142
} /* for(p=GC_threads[i]...) */
143
} /* for(i=0;i<THREAD_TABLE_SZ...) */
146
#else /* !DARWIN_DONT_PARSE_STACK; Use FindTopOfStack() */
148
void GC_push_all_stacks() {
153
thread_act_array_t act_list = 0;
154
mach_msg_type_number_t listcount = 0;
156
me = mach_thread_self();
157
if (!GC_thr_initialized) GC_thr_init();
159
r = task_threads(current_task(), &act_list, &listcount);
160
if(r != KERN_SUCCESS) ABORT("task_threads failed");
161
for(i = 0; i < listcount; i++) {
162
thread_act_t thread = act_list[i];
165
hi = (ptr_t)FindTopOfStack(0);
167
# if defined(POWERPC)
168
# if CPP_WORDSZ == 32
169
ppc_thread_state_t info;
171
ppc_thread_state64_t info;
173
mach_msg_type_number_t outCount = THREAD_STATE_MAX;
174
r = thread_get_state(thread, MACHINE_THREAD_STATE,
175
(natural_t *)&info, &outCount);
176
if(r != KERN_SUCCESS) ABORT("task_get_state failed");
178
lo = (void*)(info.r1 - PPC_RED_ZONE_SIZE);
179
hi = (ptr_t)FindTopOfStack(info.r1);
181
GC_push_one(info.r0);
182
GC_push_one(info.r2);
183
GC_push_one(info.r3);
184
GC_push_one(info.r4);
185
GC_push_one(info.r5);
186
GC_push_one(info.r6);
187
GC_push_one(info.r7);
188
GC_push_one(info.r8);
189
GC_push_one(info.r9);
190
GC_push_one(info.r10);
191
GC_push_one(info.r11);
192
GC_push_one(info.r12);
193
GC_push_one(info.r13);
194
GC_push_one(info.r14);
195
GC_push_one(info.r15);
196
GC_push_one(info.r16);
197
GC_push_one(info.r17);
198
GC_push_one(info.r18);
199
GC_push_one(info.r19);
200
GC_push_one(info.r20);
201
GC_push_one(info.r21);
202
GC_push_one(info.r22);
203
GC_push_one(info.r23);
204
GC_push_one(info.r24);
205
GC_push_one(info.r25);
206
GC_push_one(info.r26);
207
GC_push_one(info.r27);
208
GC_push_one(info.r28);
209
GC_push_one(info.r29);
210
GC_push_one(info.r30);
211
GC_push_one(info.r31);
213
/* FIXME: Remove after testing: */
214
WARN("This is completely untested and likely will not work\n", 0);
215
i386_thread_state_t info;
216
mach_msg_type_number_t outCount = THREAD_STATE_MAX;
217
r = thread_get_state(thread, MACHINE_THREAD_STATE,
218
(natural_t *)&info, &outCount);
219
if(r != KERN_SUCCESS) ABORT("task_get_state failed");
221
lo = (void*)info.esp;
222
hi = (ptr_t)FindTopOfStack(info.esp);
224
GC_push_one(info.eax);
225
GC_push_one(info.ebx);
226
GC_push_one(info.ecx);
227
GC_push_one(info.edx);
228
GC_push_one(info.edi);
229
GC_push_one(info.esi);
230
/* GC_push_one(info.ebp); */
231
/* GC_push_one(info.esp); */
232
GC_push_one(info.ss);
233
GC_push_one(info.eip);
234
GC_push_one(info.cs);
235
GC_push_one(info.ds);
236
GC_push_one(info.es);
237
GC_push_one(info.fs);
238
GC_push_one(info.gs);
239
# endif /* !POWERPC */
242
GC_printf3("Darwin: Stack for thread 0x%lx = [%lx,%lx)\n",
243
(unsigned long) thread,
248
GC_push_all_stack(lo, hi);
249
} /* for(p=GC_threads[i]...) */
251
#endif /* !DARWIN_DONT_PARSE_STACK */
253
static mach_port_t GC_mach_handler_thread;
254
static int GC_use_mach_handler_thread = 0;
256
static struct GC_mach_thread GC_mach_threads[THREAD_TABLE_SZ];
257
static int GC_mach_threads_count;
259
void GC_stop_init() {
262
for (i = 0; i < THREAD_TABLE_SZ; i++) {
263
GC_mach_threads[i].thread = 0;
264
GC_mach_threads[i].already_suspended = 0;
266
GC_mach_threads_count = 0;
269
/* returns true if there's a thread in act_list that wasn't in old_list */
270
int GC_suspend_thread_list(thread_act_array_t act_list, int count,
271
thread_act_array_t old_list, int old_count) {
272
mach_port_t my_thread = mach_thread_self();
277
for(i = 0; i < count; i++) {
278
thread_act_t thread = act_list[i];
280
GC_printf1("Attempting to suspend thread %p\n", thread);
282
/* find the current thread in the old list */
284
for(j = 0; j < old_count; j++) {
285
thread_act_t old_thread = old_list[j];
286
if (old_thread == thread) {
292
/* add it to the GC_mach_threads list */
293
GC_mach_threads[GC_mach_threads_count].thread = thread;
294
/* default is not suspended */
295
GC_mach_threads[GC_mach_threads_count].already_suspended = 0;
299
if (thread != my_thread &&
300
(!GC_use_mach_handler_thread
301
|| (GC_use_mach_handler_thread
302
&& GC_mach_handler_thread != thread))) {
303
struct thread_basic_info info;
304
mach_msg_type_number_t outCount = THREAD_INFO_MAX;
305
kern_return_t kern_result = thread_info(thread, THREAD_BASIC_INFO,
306
(thread_info_t)&info, &outCount);
307
if(kern_result != KERN_SUCCESS) {
308
/* the thread may have quit since the thread_threads () call
309
* we mark already_suspended so it's not dealt with anymore later
312
GC_mach_threads[GC_mach_threads_count].already_suspended = TRUE;
313
GC_mach_threads_count++;
318
GC_printf2("Thread state for 0x%lx = %d\n", thread, info.run_state);
321
GC_mach_threads[GC_mach_threads_count].already_suspended = info.suspend_count;
323
if (info.suspend_count) continue;
326
GC_printf1("Suspending 0x%lx\n", thread);
328
/* Suspend the thread */
329
kern_result = thread_suspend(thread);
330
if(kern_result != KERN_SUCCESS) {
331
/* the thread may have quit since the thread_threads () call
332
* we mark already_suspended so it's not dealt with anymore later
335
GC_mach_threads[GC_mach_threads_count].already_suspended = TRUE;
336
GC_mach_threads_count++;
341
if (!found) GC_mach_threads_count++;
347
/* Caller holds allocation lock. */
352
mach_port_t my_thread = mach_thread_self();
353
kern_return_t kern_result;
354
thread_act_array_t act_list, prev_list;
355
mach_msg_type_number_t listcount, prevcount;
358
GC_printf1("Stopping the world from 0x%lx\n", mach_thread_self());
361
/* clear out the mach threads list table */
364
/* Make sure all free list construction has stopped before we start. */
365
/* No new construction can start, since free list construction is */
366
/* required to acquire and release the GC lock before it starts, */
367
/* and we have the lock. */
368
# ifdef PARALLEL_MARK
369
GC_acquire_mark_lock();
370
GC_ASSERT(GC_fl_builder_count == 0);
371
/* We should have previously waited for it to become zero. */
372
# endif /* PARALLEL_MARK */
374
/* Loop stopping threads until you have gone over the whole list
375
twice without a new one appearing. thread_create() won't
376
return (and thus the thread stop) until the new thread
377
exists, so there is no window whereby you could stop a
378
thread, recognise it is stopped, but then have a new thread
379
it created before stopping show up later.
387
kern_result = task_threads(current_task(), &act_list, &listcount);
388
result = GC_suspend_thread_list(act_list, listcount,
389
prev_list, prevcount);
391
prev_list = act_list;
392
prevcount = listcount;
398
extern void GC_mprotect_stop();
403
# ifdef PARALLEL_MARK
404
GC_release_mark_lock();
407
GC_printf1("World stopped from 0x%lx\n", my_thread);
411
/* Caller holds allocation lock, and has held it continuously since */
412
/* the world stopped. */
413
void GC_start_world()
415
mach_port_t my_thread = mach_thread_self();
418
kern_return_t kern_result;
419
thread_act_array_t act_list;
420
mach_msg_type_number_t listcount;
421
struct thread_basic_info info;
422
mach_msg_type_number_t outCount = THREAD_INFO_MAX;
425
GC_printf0("World starting\n");
430
extern void GC_mprotect_resume();
431
GC_mprotect_resume();
435
kern_result = task_threads(current_task(), &act_list, &listcount);
436
for(i = 0; i < listcount; i++) {
437
thread_act_t thread = act_list[i];
438
if (thread != my_thread &&
439
(!GC_use_mach_handler_thread ||
440
(GC_use_mach_handler_thread && GC_mach_handler_thread != thread))) {
441
for(j = 0; j < GC_mach_threads_count; j++) {
442
if (thread == GC_mach_threads[j].thread) {
443
if (GC_mach_threads[j].already_suspended) {
445
GC_printf1("Not resuming already suspended thread %p\n", thread);
449
kern_result = thread_info(thread, THREAD_BASIC_INFO,
450
(thread_info_t)&info, &outCount);
451
if(kern_result != KERN_SUCCESS) ABORT("thread_info failed");
453
GC_printf2("Thread state for 0x%lx = %d\n", thread,
455
GC_printf1("Resuming 0x%lx\n", thread);
457
/* Resume the thread */
458
kern_result = thread_resume(thread);
459
if(kern_result != KERN_SUCCESS) ABORT("thread_resume failed");
465
GC_printf0("World started\n");
469
void GC_darwin_register_mach_handler_thread(mach_port_t thread) {
470
GC_mach_handler_thread = thread;
471
GC_use_mach_handler_thread = 1;