* src/sh/sysv.S: Fix register numbers in the FDE for
[official-gcc.git] / boehm-gc / darwin_stop_world.c
blob3c0c3710afbf6f653a0bea9053a4975470b247ad
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
8 Page 49:
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
12 added to the stack."
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."
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
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;
33 unsigned long FindTopOfStack(unsigned int stack_start) {
34 StackFrame *frame;
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;
48 # ifdef DEBUG_THREADS
49 /* GC_printf1("FindTopOfStack start at sp = %p\n", frame); */
50 # endif
51 do {
52 if (frame->savedSP == 0) break;
53 /* if there are no more stack frames, stop */
55 frame = (StackFrame*)frame->savedSP;
57 /* we do these next two checks after going to the next frame
58 because the LR for the first stack frame in the loop
59 is not set up on purpose, so we shouldn't check it. */
60 if ((frame->savedLR & ~3) == 0) break; /* if the next LR is bogus, stop */
61 if ((~(frame->savedLR) & ~3) == 0) break; /* ditto */
62 } while (1);
64 # ifdef DEBUG_THREADS
65 /* GC_printf1("FindTopOfStack finish at sp = %p\n", frame); */
66 # endif
68 return (unsigned long)frame;
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 ppc_thread_state_t state;
79 mach_msg_type_number_t thread_state_count = MACHINE_THREAD_STATE_COUNT;
81 me = pthread_self();
82 if (!GC_thr_initialized) GC_thr_init();
84 for(i=0;i<THREAD_TABLE_SZ;i++) {
85 for(p=GC_threads[i];p!=0;p=p->next) {
86 if(p -> flags & FINISHED) continue;
87 if(pthread_equal(p->id,me)) {
88 lo = GC_approx_sp();
89 } else {
90 /* Get the thread state (registers, etc) */
91 r = thread_get_state(
92 p->stop_info.mach_thread,
93 MACHINE_THREAD_STATE,
94 (natural_t*)&state,
95 &thread_state_count);
96 if(r != KERN_SUCCESS) ABORT("thread_get_state failed");
98 lo = (void*)(state.r1 - PPC_RED_ZONE_SIZE);
100 GC_push_one(state.r0);
101 GC_push_one(state.r2);
102 GC_push_one(state.r3);
103 GC_push_one(state.r4);
104 GC_push_one(state.r5);
105 GC_push_one(state.r6);
106 GC_push_one(state.r7);
107 GC_push_one(state.r8);
108 GC_push_one(state.r9);
109 GC_push_one(state.r10);
110 GC_push_one(state.r11);
111 GC_push_one(state.r12);
112 GC_push_one(state.r13);
113 GC_push_one(state.r14);
114 GC_push_one(state.r15);
115 GC_push_one(state.r16);
116 GC_push_one(state.r17);
117 GC_push_one(state.r18);
118 GC_push_one(state.r19);
119 GC_push_one(state.r20);
120 GC_push_one(state.r21);
121 GC_push_one(state.r22);
122 GC_push_one(state.r23);
123 GC_push_one(state.r24);
124 GC_push_one(state.r25);
125 GC_push_one(state.r26);
126 GC_push_one(state.r27);
127 GC_push_one(state.r28);
128 GC_push_one(state.r29);
129 GC_push_one(state.r30);
130 GC_push_one(state.r31);
131 } /* p != me */
132 if(p->flags & MAIN_THREAD)
133 hi = GC_stackbottom;
134 else
135 hi = p->stack_end;
136 #if DEBUG_THREADS
137 GC_printf3("Darwin: Stack for thread 0x%lx = [%lx,%lx)\n",
138 (unsigned long) p -> id,
139 (unsigned long) lo,
140 (unsigned long) hi
142 #endif
143 GC_push_all_stack(lo,hi);
144 } /* for(p=GC_threads[i]...) */
145 } /* for(i=0;i<THREAD_TABLE_SZ...) */
148 #else /* !DARWIN_DONT_PARSE_STACK; Use FindTopOfStack() */
150 void GC_push_all_stacks() {
151 int i;
152 kern_return_t r;
153 mach_port_t me;
154 ptr_t lo, hi;
155 thread_act_array_t act_list = 0;
156 mach_msg_type_number_t listcount = 0;
158 me = mach_thread_self();
159 if (!GC_thr_initialized) GC_thr_init();
161 r = task_threads(current_task(), &act_list, &listcount);
162 if(r != KERN_SUCCESS) ABORT("task_threads failed");
163 for(i = 0; i < listcount; i++) {
164 thread_act_t thread = act_list[i];
165 if (thread == me) {
166 lo = GC_approx_sp();
167 hi = (ptr_t)FindTopOfStack(0);
168 } else {
169 # if defined(POWERPC)
170 # if CPP_WORDSZ == 32
171 ppc_thread_state_t info;
172 # else
173 ppc_thread_state64_t info;
174 # endif
175 mach_msg_type_number_t outCount = THREAD_STATE_MAX;
176 r = thread_get_state(thread, MACHINE_THREAD_STATE,
177 (natural_t *)&info, &outCount);
178 if(r != KERN_SUCCESS) ABORT("task_get_state failed");
180 lo = (void*)(info.r1 - PPC_RED_ZONE_SIZE);
181 hi = (ptr_t)FindTopOfStack(info.r1);
183 GC_push_one(info.r0);
184 GC_push_one(info.r2);
185 GC_push_one(info.r3);
186 GC_push_one(info.r4);
187 GC_push_one(info.r5);
188 GC_push_one(info.r6);
189 GC_push_one(info.r7);
190 GC_push_one(info.r8);
191 GC_push_one(info.r9);
192 GC_push_one(info.r10);
193 GC_push_one(info.r11);
194 GC_push_one(info.r12);
195 GC_push_one(info.r13);
196 GC_push_one(info.r14);
197 GC_push_one(info.r15);
198 GC_push_one(info.r16);
199 GC_push_one(info.r17);
200 GC_push_one(info.r18);
201 GC_push_one(info.r19);
202 GC_push_one(info.r20);
203 GC_push_one(info.r21);
204 GC_push_one(info.r22);
205 GC_push_one(info.r23);
206 GC_push_one(info.r24);
207 GC_push_one(info.r25);
208 GC_push_one(info.r26);
209 GC_push_one(info.r27);
210 GC_push_one(info.r28);
211 GC_push_one(info.r29);
212 GC_push_one(info.r30);
213 GC_push_one(info.r31);
214 # else
215 /* FIXME: Remove after testing: */
216 WARN("This is completely untested and likely will not work\n", 0);
217 i386_thread_state_t info;
218 mach_msg_type_number_t outCount = THREAD_STATE_MAX;
219 r = thread_get_state(thread, MACHINE_THREAD_STATE,
220 (natural_t *)&info, &outCount);
221 if(r != KERN_SUCCESS) ABORT("task_get_state failed");
223 lo = (void*)info.esp;
224 hi = (ptr_t)FindTopOfStack(info.esp);
226 GC_push_one(info.eax);
227 GC_push_one(info.ebx);
228 GC_push_one(info.ecx);
229 GC_push_one(info.edx);
230 GC_push_one(info.edi);
231 GC_push_one(info.esi);
232 /* GC_push_one(info.ebp); */
233 /* GC_push_one(info.esp); */
234 GC_push_one(info.ss);
235 GC_push_one(info.eip);
236 GC_push_one(info.cs);
237 GC_push_one(info.ds);
238 GC_push_one(info.es);
239 GC_push_one(info.fs);
240 GC_push_one(info.gs);
241 # endif /* !POWERPC */
243 # if DEBUG_THREADS
244 GC_printf3("Darwin: Stack for thread 0x%lx = [%lx,%lx)\n",
245 (unsigned long) thread,
246 (unsigned long) lo,
247 (unsigned long) hi
249 # endif
250 GC_push_all_stack(lo, hi);
251 } /* for(p=GC_threads[i]...) */
253 #endif /* !DARWIN_DONT_PARSE_STACK */
255 static mach_port_t GC_mach_handler_thread;
256 static int GC_use_mach_handler_thread = 0;
258 static struct GC_mach_thread GC_mach_threads[THREAD_TABLE_SZ];
259 static int GC_mach_threads_count;
261 void GC_stop_init() {
262 int i;
264 for (i = 0; i < THREAD_TABLE_SZ; i++) {
265 GC_mach_threads[i].thread = 0;
266 GC_mach_threads[i].already_suspended = 0;
268 GC_mach_threads_count = 0;
271 /* returns true if there's a thread in act_list that wasn't in old_list */
272 int GC_suspend_thread_list(thread_act_array_t act_list, int count,
273 thread_act_array_t old_list, int old_count) {
274 mach_port_t my_thread = mach_thread_self();
275 int i, j;
277 int changed = 0;
279 for(i = 0; i < count; i++) {
280 thread_act_t thread = act_list[i];
281 # if DEBUG_THREADS
282 GC_printf1("Attempting to suspend thread %p\n", thread);
283 # endif
284 /* find the current thread in the old list */
285 int found = 0;
286 for(j = 0; j < old_count; j++) {
287 thread_act_t old_thread = old_list[j];
288 if (old_thread == thread) {
289 found = 1;
290 break;
293 if (!found) {
294 /* add it to the GC_mach_threads list */
295 GC_mach_threads[GC_mach_threads_count].thread = thread;
296 /* default is not suspended */
297 GC_mach_threads[GC_mach_threads_count].already_suspended = 0;
298 changed = 1;
301 if (thread != my_thread &&
302 (!GC_use_mach_handler_thread
303 || (GC_use_mach_handler_thread
304 && GC_mach_handler_thread != thread))) {
305 struct thread_basic_info info;
306 mach_msg_type_number_t outCount = THREAD_INFO_MAX;
307 kern_return_t kern_result = thread_info(thread, THREAD_BASIC_INFO,
308 (thread_info_t)&info, &outCount);
309 if(kern_result != KERN_SUCCESS) {
310 /* the thread may have quit since the thread_threads () call
311 * we mark already_suspended so it's not dealt with anymore later
313 if (!found) {
314 GC_mach_threads[GC_mach_threads_count].already_suspended = TRUE;
315 GC_mach_threads_count++;
317 continue;
319 # if DEBUG_THREADS
320 GC_printf2("Thread state for 0x%lx = %d\n", thread, info.run_state);
321 # endif
322 if (!found) {
323 GC_mach_threads[GC_mach_threads_count].already_suspended = info.suspend_count;
325 if (info.suspend_count) continue;
327 # if DEBUG_THREADS
328 GC_printf1("Suspending 0x%lx\n", thread);
329 # endif
330 /* Suspend the thread */
331 kern_result = thread_suspend(thread);
332 if(kern_result != KERN_SUCCESS) {
333 /* the thread may have quit since the thread_threads () call
334 * we mark already_suspended so it's not dealt with anymore later
336 if (!found) {
337 GC_mach_threads[GC_mach_threads_count].already_suspended = TRUE;
338 GC_mach_threads_count++;
340 continue;
343 if (!found) GC_mach_threads_count++;
345 return changed;
349 /* Caller holds allocation lock. */
350 void GC_stop_world()
352 int i, changes;
353 GC_thread p;
354 mach_port_t my_thread = mach_thread_self();
355 kern_return_t kern_result;
356 thread_act_array_t act_list, prev_list;
357 mach_msg_type_number_t listcount, prevcount;
359 # if DEBUG_THREADS
360 GC_printf1("Stopping the world from 0x%lx\n", mach_thread_self());
361 # endif
363 /* clear out the mach threads list table */
364 GC_stop_init();
366 /* Make sure all free list construction has stopped before we start. */
367 /* No new construction can start, since free list construction is */
368 /* required to acquire and release the GC lock before it starts, */
369 /* and we have the lock. */
370 # ifdef PARALLEL_MARK
371 GC_acquire_mark_lock();
372 GC_ASSERT(GC_fl_builder_count == 0);
373 /* We should have previously waited for it to become zero. */
374 # endif /* PARALLEL_MARK */
376 /* Loop stopping threads until you have gone over the whole list
377 twice without a new one appearing. thread_create() won't
378 return (and thus the thread stop) until the new thread
379 exists, so there is no window whereby you could stop a
380 thread, recognise it is stopped, but then have a new thread
381 it created before stopping show up later.
384 changes = 1;
385 prev_list = NULL;
386 prevcount = 0;
387 do {
388 int result;
389 kern_result = task_threads(current_task(), &act_list, &listcount);
390 result = GC_suspend_thread_list(act_list, listcount,
391 prev_list, prevcount);
392 changes = result;
393 prev_list = act_list;
394 prevcount = listcount;
395 } while (changes);
398 # ifdef MPROTECT_VDB
399 if(GC_incremental) {
400 extern void GC_mprotect_stop();
401 GC_mprotect_stop();
403 # endif
405 # ifdef PARALLEL_MARK
406 GC_release_mark_lock();
407 # endif
408 #if DEBUG_THREADS
409 GC_printf1("World stopped from 0x%lx\n", my_thread);
410 #endif
413 /* Caller holds allocation lock, and has held it continuously since */
414 /* the world stopped. */
415 void GC_start_world()
417 mach_port_t my_thread = mach_thread_self();
418 int i, j;
419 GC_thread p;
420 kern_return_t kern_result;
421 thread_act_array_t act_list;
422 mach_msg_type_number_t listcount;
423 struct thread_basic_info info;
424 mach_msg_type_number_t outCount = THREAD_INFO_MAX;
426 # if DEBUG_THREADS
427 GC_printf0("World starting\n");
428 # endif
430 # ifdef MPROTECT_VDB
431 if(GC_incremental) {
432 extern void GC_mprotect_resume();
433 GC_mprotect_resume();
435 # endif
437 kern_result = task_threads(current_task(), &act_list, &listcount);
438 for(i = 0; i < listcount; i++) {
439 thread_act_t thread = act_list[i];
440 if (thread != my_thread &&
441 (!GC_use_mach_handler_thread ||
442 (GC_use_mach_handler_thread && GC_mach_handler_thread != thread))) {
443 for(j = 0; j < GC_mach_threads_count; j++) {
444 if (thread == GC_mach_threads[j].thread) {
445 if (GC_mach_threads[j].already_suspended) {
446 # if DEBUG_THREADS
447 GC_printf1("Not resuming already suspended thread %p\n", thread);
448 # endif
449 continue;
451 kern_result = thread_info(thread, THREAD_BASIC_INFO,
452 (thread_info_t)&info, &outCount);
453 if(kern_result != KERN_SUCCESS) ABORT("thread_info failed");
454 # if DEBUG_THREADS
455 GC_printf2("Thread state for 0x%lx = %d\n", thread,
456 info.run_state);
457 GC_printf1("Resuming 0x%lx\n", thread);
458 # endif
459 /* Resume the thread */
460 kern_result = thread_resume(thread);
461 if(kern_result != KERN_SUCCESS) ABORT("thread_resume failed");
466 # if DEBUG_THREADS
467 GC_printf0("World started\n");
468 # endif
471 void GC_darwin_register_mach_handler_thread(mach_port_t thread) {
472 GC_mach_handler_thread = thread;
473 GC_use_mach_handler_thread = 1;
476 #endif