OSDN Git Service

* configure.ac: Fix x86 darwin builds.
[pf3gnuchains/gcc-fork.git] / boehm-gc / darwin_stop_world.c
1 #include "private/pthread_support.h"
2
3 /* This probably needs more porting work to ppc64. */
4
5 # if defined(GC_DARWIN_THREADS)
6
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."
13    
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."
16 */
17 #if defined(__ppc__)
18 # define PPC_RED_ZONE_SIZE 224
19 #elif defined(__ppc64__)
20 # define PPC_RED_ZONE_SIZE 320
21 #endif
22
23 /* Try to work out the right way to access thread state structure members.
24    The structure has changed its definition in different Darwin versions.  */
25 #if defined(__ppc__)
26 # define THREAD_STATE ppc_thread_state_t
27 # if defined (HAS_PPC_THREAD_STATE_R0)
28 #  define THREAD_FLD(x) x
29 # elif defined (HAS_PPC_THREAD_STATE___R0)
30 #  define THREAD_FLD(x) __ ## x
31 # else
32 #  error can not work out how to access fields of ppc_thread_state_t
33 # endif
34 #elif defined(__ppc64__)
35 # define THREAD_STATE ppc_thread_state64_t
36 # if defined (HAS_PPC_THREAD_STATE64_R0)
37 #  define THREAD_FLD(x) x
38 # elif defined (HAS_PPC_THREAD_STATE64___R0)
39 #  define THREAD_FLD(x) __ ## x
40 # else
41 #  error can not work out how to access fields of ppc_thread_state64_t
42 # endif
43 #elif defined(__i386__)
44 # define THREAD_STATE i386_thread_state_t
45 # if defined (HAS_I386_THREAD_STATE_EAX)
46 #  define THREAD_FLD(x) x
47 # elif defined (HAS_I386_THREAD_STATE___EAX)
48 #  define THREAD_FLD(x) __ ## x
49 # else
50 #  error can not work out how to access fields of i386_thread_state_t
51 # endif
52 #elif defined(__x86_64__)
53 # define THREAD_STATE i386_thread_state_t
54 # if defined (HAS_I386_THREAD_STATE_EAX)
55 #  define THREAD_FLD(x) x
56 # elif defined (HAS_I386_THREAD_STATE___EAX)
57 #  define THREAD_FLD(x) __ ## x
58 # else
59 #  error can not work out how to access fields of i386_thread_state_t
60 # endif
61 #else
62 # error unknown architecture
63 #endif
64
65 typedef struct StackFrame {
66   unsigned long savedSP;
67   unsigned long savedCR;
68   unsigned long savedLR;
69   unsigned long reserved[2];
70   unsigned long savedRTOC;
71 } StackFrame;
72
73 unsigned long FindTopOfStack(unsigned long stack_start) {
74   StackFrame    *frame;
75   
76   if (stack_start == 0) {
77 # ifdef POWERPC
78 #   if CPP_WORDSZ == 32
79       __asm__ volatile("lwz     %0,0(r1)" : "=r" (frame));
80 #   else
81       __asm__ volatile("ld      %0,0(r1)" : "=r" (frame));
82 #   endif
83 # endif
84   } else {
85     frame = (StackFrame *)stack_start;
86   }
87
88 # ifdef DEBUG_THREADS
89     /* GC_printf1("FindTopOfStack start at sp = %p\n", frame); */
90 # endif
91   do {
92     if (frame->savedSP == 0) break;
93                 /* if there are no more stack frames, stop */
94
95     frame = (StackFrame*)frame->savedSP;
96
97     /* we do these next two checks after going to the next frame
98        because the LR for the first stack frame in the loop
99        is not set up on purpose, so we shouldn't check it. */
100     if ((frame->savedLR & ~3) == 0) break; /* if the next LR is bogus, stop */
101     if ((~(frame->savedLR) & ~3) == 0) break; /* ditto */
102   } while (1); 
103
104 # ifdef DEBUG_THREADS
105     /* GC_printf1("FindTopOfStack finish at sp = %p\n", frame); */
106 # endif
107
108   return (unsigned long)frame;
109 }       
110
111 #ifdef DARWIN_DONT_PARSE_STACK
112 void GC_push_all_stacks() {
113   int i;
114   kern_return_t r;
115   GC_thread p;
116   pthread_t me;
117   ptr_t lo, hi;
118   THREAD_STATE state;
119   mach_msg_type_number_t thread_state_count = MACHINE_THREAD_STATE_COUNT;
120   
121   me = pthread_self();
122   if (!GC_thr_initialized) GC_thr_init();
123   
124   for(i=0;i<THREAD_TABLE_SZ;i++) {
125     for(p=GC_threads[i];p!=0;p=p->next) {
126       if(p -> flags & FINISHED) continue;
127       if(pthread_equal(p->id,me)) {
128         lo = GC_approx_sp();
129       } else {
130         /* Get the thread state (registers, etc) */
131         r = thread_get_state(
132                              p->stop_info.mach_thread,
133                              MACHINE_THREAD_STATE,
134                              (natural_t*)&state,
135                              &thread_state_count);
136         if(r != KERN_SUCCESS) ABORT("thread_get_state failed");
137
138 #if defined(I386)
139         lo = (void*)state . THREAD_FLD (esp);
140
141         GC_push_one(state . THREAD_FLD (eax)); 
142         GC_push_one(state . THREAD_FLD (ebx)); 
143         GC_push_one(state . THREAD_FLD (ecx)); 
144         GC_push_one(state . THREAD_FLD (edx)); 
145         GC_push_one(state . THREAD_FLD (edi)); 
146         GC_push_one(state . THREAD_FLD (esi)); 
147         GC_push_one(state . THREAD_FLD (ebp)); 
148 #elif defined(POWERPC)
149         lo = (void*)(state . THREAD_FLD (r1) - PPC_RED_ZONE_SIZE);
150         
151         GC_push_one(state . THREAD_FLD (r0)); 
152         GC_push_one(state . THREAD_FLD (r2)); 
153         GC_push_one(state . THREAD_FLD (r3)); 
154         GC_push_one(state . THREAD_FLD (r4)); 
155         GC_push_one(state . THREAD_FLD (r5)); 
156         GC_push_one(state . THREAD_FLD (r6)); 
157         GC_push_one(state . THREAD_FLD (r7)); 
158         GC_push_one(state . THREAD_FLD (r8)); 
159         GC_push_one(state . THREAD_FLD (r9)); 
160         GC_push_one(state . THREAD_FLD (r10)); 
161         GC_push_one(state . THREAD_FLD (r11)); 
162         GC_push_one(state . THREAD_FLD (r12)); 
163         GC_push_one(state . THREAD_FLD (r13)); 
164         GC_push_one(state . THREAD_FLD (r14)); 
165         GC_push_one(state . THREAD_FLD (r15)); 
166         GC_push_one(state . THREAD_FLD (r16)); 
167         GC_push_one(state . THREAD_FLD (r17)); 
168         GC_push_one(state . THREAD_FLD (r18)); 
169         GC_push_one(state . THREAD_FLD (r19)); 
170         GC_push_one(state . THREAD_FLD (r20)); 
171         GC_push_one(state . THREAD_FLD (r21)); 
172         GC_push_one(state . THREAD_FLD (r22)); 
173         GC_push_one(state . THREAD_FLD (r23)); 
174         GC_push_one(state . THREAD_FLD (r24)); 
175         GC_push_one(state . THREAD_FLD (r25)); 
176         GC_push_one(state . THREAD_FLD (r26)); 
177         GC_push_one(state . THREAD_FLD (r27)); 
178         GC_push_one(state . THREAD_FLD (r28)); 
179         GC_push_one(state . THREAD_FLD (r29)); 
180         GC_push_one(state . THREAD_FLD (r30)); 
181         GC_push_one(state . THREAD_FLD (r31));
182 #else
183 # error FIXME for non-x86 || ppc architectures
184 #endif
185       } /* p != me */
186       if(p->flags & MAIN_THREAD)
187         hi = GC_stackbottom;
188       else
189         hi = p->stack_end;
190 #if DEBUG_THREADS
191       GC_printf3("Darwin: Stack for thread 0x%lx = [%lx,%lx)\n",
192                  (unsigned long) p -> id,
193                  (unsigned long) lo,
194                  (unsigned long) hi
195                  );
196 #endif
197       GC_push_all_stack(lo,hi);
198     } /* for(p=GC_threads[i]...) */
199   } /* for(i=0;i<THREAD_TABLE_SZ...) */
200 }
201
202 #else /* !DARWIN_DONT_PARSE_STACK; Use FindTopOfStack() */
203
204 void GC_push_all_stacks() {
205     int i;
206     kern_return_t r;
207     mach_port_t me;
208     ptr_t lo, hi;
209     thread_act_array_t act_list = 0;
210     mach_msg_type_number_t listcount = 0;
211
212     me = mach_thread_self();
213     if (!GC_thr_initialized) GC_thr_init();
214     
215     r = task_threads(current_task(), &act_list, &listcount);
216     if(r != KERN_SUCCESS) ABORT("task_threads failed");
217     for(i = 0; i < listcount; i++) {
218       thread_act_t thread = act_list[i];
219       if (thread == me) {
220         lo = GC_approx_sp();
221         hi = (ptr_t)FindTopOfStack(0);
222       } else {
223 #     if defined(__ppc__) || defined(__ppc64__)
224         THREAD_STATE info;
225         mach_msg_type_number_t outCount = THREAD_STATE_MAX;
226         r = thread_get_state(thread, MACHINE_THREAD_STATE,
227                              (natural_t *)&info, &outCount);
228         if(r != KERN_SUCCESS) ABORT("task_get_state failed");
229
230         lo = (void*)(info . THREAD_FLD (r1) - PPC_RED_ZONE_SIZE);
231         hi = (ptr_t)FindTopOfStack(info . THREAD_FLD (r1));
232
233         GC_push_one(info . THREAD_FLD (r0)); 
234         GC_push_one(info . THREAD_FLD (r2)); 
235         GC_push_one(info . THREAD_FLD (r3)); 
236         GC_push_one(info . THREAD_FLD (r4)); 
237         GC_push_one(info . THREAD_FLD (r5)); 
238         GC_push_one(info . THREAD_FLD (r6)); 
239         GC_push_one(info . THREAD_FLD (r7)); 
240         GC_push_one(info . THREAD_FLD (r8)); 
241         GC_push_one(info . THREAD_FLD (r9)); 
242         GC_push_one(info . THREAD_FLD (r10)); 
243         GC_push_one(info . THREAD_FLD (r11)); 
244         GC_push_one(info . THREAD_FLD (r12)); 
245         GC_push_one(info . THREAD_FLD (r13)); 
246         GC_push_one(info . THREAD_FLD (r14)); 
247         GC_push_one(info . THREAD_FLD (r15)); 
248         GC_push_one(info . THREAD_FLD (r16)); 
249         GC_push_one(info . THREAD_FLD (r17)); 
250         GC_push_one(info . THREAD_FLD (r18)); 
251         GC_push_one(info . THREAD_FLD (r19)); 
252         GC_push_one(info . THREAD_FLD (r20)); 
253         GC_push_one(info . THREAD_FLD (r21)); 
254         GC_push_one(info . THREAD_FLD (r22)); 
255         GC_push_one(info . THREAD_FLD (r23)); 
256         GC_push_one(info . THREAD_FLD (r24)); 
257         GC_push_one(info . THREAD_FLD (r25)); 
258         GC_push_one(info . THREAD_FLD (r26)); 
259         GC_push_one(info . THREAD_FLD (r27)); 
260         GC_push_one(info . THREAD_FLD (r28)); 
261         GC_push_one(info . THREAD_FLD (r29)); 
262         GC_push_one(info . THREAD_FLD (r30)); 
263         GC_push_one(info . THREAD_FLD (r31));
264 #      else
265         /* FIXME: Remove after testing: */
266         WARN("This is completely untested and likely will not work\n", 0);
267         THREAD_STATE info;
268         mach_msg_type_number_t outCount = THREAD_STATE_MAX;
269         r = thread_get_state(thread, MACHINE_THREAD_STATE,
270                              (natural_t *)&info, &outCount);
271         if(r != KERN_SUCCESS) ABORT("task_get_state failed");
272
273         lo = (void*)info . THREAD_FLD (esp);
274         hi = (ptr_t)FindTopOfStack(info . THREAD_FLD (esp));
275
276         GC_push_one(info . THREAD_FLD (eax)); 
277         GC_push_one(info . THREAD_FLD (ebx)); 
278         GC_push_one(info . THREAD_FLD (ecx)); 
279         GC_push_one(info . THREAD_FLD (edx)); 
280         GC_push_one(info . THREAD_FLD (edi)); 
281         GC_push_one(info . THREAD_FLD (esi)); 
282         /* GC_push_one(info . THREAD_FLD (ebp));  */
283         /* GC_push_one(info . THREAD_FLD (esp));  */
284         GC_push_one(info . THREAD_FLD (ss)); 
285         GC_push_one(info . THREAD_FLD (eip)); 
286         GC_push_one(info . THREAD_FLD (cs)); 
287         GC_push_one(info . THREAD_FLD (ds)); 
288         GC_push_one(info . THREAD_FLD (es)); 
289         GC_push_one(info . THREAD_FLD (fs)); 
290         GC_push_one(info . THREAD_FLD (gs)); 
291 #      endif /* !POWERPC */
292       }
293 #     if DEBUG_THREADS
294        GC_printf3("Darwin: Stack for thread 0x%lx = [%lx,%lx)\n",
295                   (unsigned long) thread,
296                   (unsigned long) lo,
297                   (unsigned long) hi
298                  );
299 #     endif
300       GC_push_all_stack(lo, hi); 
301     } /* for(p=GC_threads[i]...) */
302     vm_deallocate(current_task(), (vm_address_t)act_list, sizeof(thread_t) * listcount);
303 }
304 #endif /* !DARWIN_DONT_PARSE_STACK */
305
306 static mach_port_t GC_mach_handler_thread;
307 static int GC_use_mach_handler_thread = 0;
308
309 static struct GC_mach_thread GC_mach_threads[THREAD_TABLE_SZ];
310 static int GC_mach_threads_count;
311
312 void GC_stop_init() {
313   int i;
314
315   for (i = 0; i < THREAD_TABLE_SZ; i++) {
316     GC_mach_threads[i].thread = 0;
317     GC_mach_threads[i].already_suspended = 0;
318   }
319   GC_mach_threads_count = 0;
320 }
321
322 /* returns true if there's a thread in act_list that wasn't in old_list */
323 int GC_suspend_thread_list(thread_act_array_t act_list, int count, 
324                            thread_act_array_t old_list, int old_count) {
325   mach_port_t my_thread = mach_thread_self();
326   int i, j;
327
328   int changed = 0;
329
330   for(i = 0; i < count; i++) {
331     thread_act_t thread = act_list[i];
332 #   if DEBUG_THREADS 
333       GC_printf1("Attempting to suspend thread %p\n", thread);
334 #   endif
335     /* find the current thread in the old list */
336     int found = 0;
337     for(j = 0; j < old_count; j++) {
338       thread_act_t old_thread = old_list[j];
339       if (old_thread == thread) {
340         found = 1;
341         break;
342       }
343     }
344     if (!found) {
345       /* add it to the GC_mach_threads list */
346       GC_mach_threads[GC_mach_threads_count].thread = thread;
347       /* default is not suspended */
348       GC_mach_threads[GC_mach_threads_count].already_suspended = 0;
349       changed = 1;
350     }      
351
352     if (thread != my_thread &&
353         (!GC_use_mach_handler_thread
354          || (GC_use_mach_handler_thread
355              && GC_mach_handler_thread != thread))) {
356       struct thread_basic_info info;
357       mach_msg_type_number_t outCount = THREAD_INFO_MAX;
358       kern_return_t kern_result = thread_info(thread, THREAD_BASIC_INFO,
359                                 (thread_info_t)&info, &outCount);
360       if(kern_result != KERN_SUCCESS) {
361         /* the thread may have quit since the thread_threads () call 
362          * we mark already_suspended so it's not dealt with anymore later
363          */
364         if (!found) {
365           GC_mach_threads[GC_mach_threads_count].already_suspended = TRUE;
366           GC_mach_threads_count++;
367         }
368         continue;
369       }
370 #     if DEBUG_THREADS
371         GC_printf2("Thread state for 0x%lx = %d\n", thread, info.run_state);
372 #     endif
373       if (!found) {
374         GC_mach_threads[GC_mach_threads_count].already_suspended = info.suspend_count;
375       }
376       if (info.suspend_count) continue;
377       
378 #     if DEBUG_THREADS
379         GC_printf1("Suspending 0x%lx\n", thread);
380 #     endif
381       /* Suspend the thread */
382       kern_result = thread_suspend(thread);
383       if(kern_result != KERN_SUCCESS) {
384         /* the thread may have quit since the thread_threads () call 
385          * we mark already_suspended so it's not dealt with anymore later
386          */
387         if (!found) {
388           GC_mach_threads[GC_mach_threads_count].already_suspended = TRUE;
389           GC_mach_threads_count++;
390         }
391         continue;
392       }
393     } 
394     if (!found) GC_mach_threads_count++;
395   }
396   return changed;
397 }
398
399
400 /* Caller holds allocation lock.        */
401 void GC_stop_world()
402 {
403   int i, changes;
404     GC_thread p;
405     mach_port_t my_thread = mach_thread_self();
406     kern_return_t kern_result;
407     thread_act_array_t act_list, prev_list;
408     mach_msg_type_number_t listcount, prevcount;
409     
410 #   if DEBUG_THREADS
411       GC_printf1("Stopping the world from 0x%lx\n", mach_thread_self());
412 #   endif
413
414     /* clear out the mach threads list table */
415     GC_stop_init(); 
416        
417     /* Make sure all free list construction has stopped before we start. */
418     /* No new construction can start, since free list construction is   */
419     /* required to acquire and release the GC lock before it starts,    */
420     /* and we have the lock.                                            */
421 #   ifdef PARALLEL_MARK
422       GC_acquire_mark_lock();
423       GC_ASSERT(GC_fl_builder_count == 0);
424       /* We should have previously waited for it to become zero. */
425 #   endif /* PARALLEL_MARK */
426
427       /* Loop stopping threads until you have gone over the whole list
428          twice without a new one appearing. thread_create() won't
429          return (and thus the thread stop) until the new thread
430          exists, so there is no window whereby you could stop a
431          thread, recognise it is stopped, but then have a new thread
432          it created before stopping show up later.
433       */
434       
435       changes = 1;
436       prev_list = NULL;
437       prevcount = 0;
438       do {
439         int result;
440         kern_result = task_threads(current_task(), &act_list, &listcount);
441         result = GC_suspend_thread_list(act_list, listcount,
442                                         prev_list, prevcount);
443         changes = result;
444         prev_list = act_list;
445         prevcount = listcount;
446         vm_deallocate(current_task(), (vm_address_t)act_list, sizeof(thread_t) * listcount);
447       } while (changes);
448       
449  
450 #   ifdef MPROTECT_VDB
451       if(GC_incremental) {
452         extern void GC_mprotect_stop();
453         GC_mprotect_stop();
454       }
455 #   endif
456     
457 #   ifdef PARALLEL_MARK
458       GC_release_mark_lock();
459 #   endif
460     #if DEBUG_THREADS
461       GC_printf1("World stopped from 0x%lx\n", my_thread);
462     #endif
463 }
464
465 /* Caller holds allocation lock, and has held it continuously since     */
466 /* the world stopped.                                                   */
467 void GC_start_world()
468 {
469   mach_port_t my_thread = mach_thread_self();
470   int i, j;
471   GC_thread p;
472   kern_return_t kern_result;
473   thread_act_array_t act_list;
474   mach_msg_type_number_t listcount;
475   struct thread_basic_info info;
476   mach_msg_type_number_t outCount = THREAD_INFO_MAX;
477   
478 #   if DEBUG_THREADS
479       GC_printf0("World starting\n");
480 #   endif
481
482 #   ifdef MPROTECT_VDB
483       if(GC_incremental) {
484         extern void GC_mprotect_resume();
485         GC_mprotect_resume();
486       }
487 #   endif
488
489     kern_result = task_threads(current_task(), &act_list, &listcount);
490     for(i = 0; i < listcount; i++) {
491       thread_act_t thread = act_list[i];
492       if (thread != my_thread &&
493           (!GC_use_mach_handler_thread ||
494            (GC_use_mach_handler_thread && GC_mach_handler_thread != thread))) {
495         for(j = 0; j < GC_mach_threads_count; j++) {
496           if (thread == GC_mach_threads[j].thread) {
497             if (GC_mach_threads[j].already_suspended) {
498 #             if DEBUG_THREADS
499                 GC_printf1("Not resuming already suspended thread %p\n", thread);
500 #             endif
501               continue;
502             }
503             kern_result = thread_info(thread, THREAD_BASIC_INFO,
504                                       (thread_info_t)&info, &outCount);
505             if(kern_result != KERN_SUCCESS) ABORT("thread_info failed");
506 #           if DEBUG_THREADS
507               GC_printf2("Thread state for 0x%lx = %d\n", thread,
508                          info.run_state);
509               GC_printf1("Resuming 0x%lx\n", thread);
510 #           endif
511             /* Resume the thread */
512             kern_result = thread_resume(thread);
513             if(kern_result != KERN_SUCCESS) ABORT("thread_resume failed");
514           } 
515         }
516       }
517     }
518     vm_deallocate(current_task(), (vm_address_t)act_list, sizeof(thread_t) * listcount);
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