Merge pull request #298 from ermshiperete/4921
[mono.git] / libgc / darwin_stop_world.c
1 #include "private/pthread_support.h"
2
3 # if defined(GC_DARWIN_THREADS)
4
5 #include <AvailabilityMacros.h>
6 #include "mono/utils/mono-compiler.h"
7
8 #ifdef MONO_DEBUGGER_SUPPORTED
9 #include "include/libgc-mono-debugger.h"
10 #endif
11
12 /* From "Inside Mac OS X - Mach-O Runtime Architecture" published by Apple
13    Page 49:
14    "The space beneath the stack pointer, where a new stack frame would normally
15    be allocated, is called the red zone. This area as shown in Figure 3-2 may
16    be used for any purpose as long as a new stack frame does not need to be
17    added to the stack."
18    
19    Page 50: "If a leaf procedure's red zone usage would exceed 224 bytes, then
20    it must set up a stack frame just like routines that call other routines."
21 */
22 #ifdef POWERPC
23 # if CPP_WORDSZ == 32
24 #   define PPC_RED_ZONE_SIZE 224
25 # elif CPP_WORDSZ == 64
26 #   define PPC_RED_ZONE_SIZE 320
27 # endif
28 #endif
29
30 typedef struct StackFrame {
31   unsigned long savedSP;
32   unsigned long savedCR;
33   unsigned long savedLR;
34   unsigned long reserved[2];
35   unsigned long savedRTOC;
36 } StackFrame;
37
38 unsigned long FindTopOfStack(unsigned int stack_start) {
39   StackFrame    *frame;
40   
41   if (stack_start == 0) {
42 # ifdef POWERPC
43 #   if CPP_WORDSZ == 32
44       __asm__ volatile("lwz     %0,0(r1)" : "=r" (frame));
45 #   else
46       __asm__ volatile("ldz     %0,0(r1)" : "=r" (frame));
47 #   endif
48 # endif
49   } else {
50     frame = (StackFrame *)stack_start;
51   }
52
53 # ifdef DEBUG_THREADS
54     /* GC_printf1("FindTopOfStack start at sp = %p\n", frame); */
55 # endif
56   do {
57     if (frame->savedSP == 0) break;
58                 /* if there are no more stack frames, stop */
59
60     frame = (StackFrame*)frame->savedSP;
61
62     /* we do these next two checks after going to the next frame
63        because the LR for the first stack frame in the loop
64        is not set up on purpose, so we shouldn't check it. */
65     if ((frame->savedLR & ~3) == 0) break; /* if the next LR is bogus, stop */
66     if ((~(frame->savedLR) & ~3) == 0) break; /* ditto */
67   } while (1); 
68
69 # ifdef DEBUG_THREADS
70     /* GC_printf1("FindTopOfStack finish at sp = %p\n", frame); */
71 # endif
72
73   return (unsigned long)frame;
74 }       
75
76 #ifdef DARWIN_DONT_PARSE_STACK
77 void GC_push_all_stacks() {
78   int i;
79   kern_return_t r;
80   GC_thread p;
81   pthread_t me;
82   ptr_t lo, hi, altstack_lo, altstack_hi;
83 #if defined(POWERPC)
84   ppc_thread_state_t state;
85   mach_msg_type_number_t thread_state_count = PPC_THREAD_STATE_COUNT;
86 #elif defined(I386)
87   i386_thread_state_t state;
88   mach_msg_type_number_t thread_state_count = i386_THREAD_STATE_COUNT;
89 #elif defined(ARM)
90   arm_thread_state_t state;
91   mach_msg_type_number_t thread_state_count = ARM_THREAD_STATE_COUNT;
92 #elif defined(X86_64)
93   x86_thread_state64_t state;
94   mach_msg_type_number_t thread_state_count = x86_THREAD_STATE64_COUNT;
95 #else
96 # error FIXME for non-x86 || ppc architectures
97   mach_msg_type_number_t thread_state_count = MACHINE_THREAD_STATE_COUNT;
98 #endif
99   
100   me = pthread_self();
101   if (!GC_thr_initialized) GC_thr_init();
102   
103   for(i=0;i<THREAD_TABLE_SZ;i++) {
104     for(p=GC_threads[i];p!=0;p=p->next) {
105       if(p -> flags & FINISHED) continue;
106       if(pthread_equal(p->id,me)) {
107         lo = GC_approx_sp();
108       } else {
109         /* Get the thread state (registers, etc) */
110         r = thread_get_state(
111                              p->stop_info.mach_thread,
112                              GC_MACH_THREAD_STATE_FLAVOR,
113                              (natural_t*)&state,
114                              &thread_state_count);
115         if(r != KERN_SUCCESS) continue;
116         
117 #if defined(I386)
118 #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
119
120         lo = state.__esp;
121
122         GC_push_one(state.__eax); 
123         GC_push_one(state.__ebx); 
124         GC_push_one(state.__ecx); 
125         GC_push_one(state.__edx); 
126         GC_push_one(state.__edi); 
127         GC_push_one(state.__esi); 
128         GC_push_one(state.__ebp); 
129 #else
130         lo = state.esp;
131
132         GC_push_one(state.eax); 
133         GC_push_one(state.ebx); 
134         GC_push_one(state.ecx); 
135         GC_push_one(state.edx); 
136         GC_push_one(state.edi); 
137         GC_push_one(state.esi); 
138         GC_push_one(state.ebp); 
139 #endif
140 #elif defined(X86_64)
141           lo = state.__rsp;
142           GC_push_one(state.__rax);
143           GC_push_one(state.__rbx);
144           GC_push_one(state.__rcx);
145           GC_push_one(state.__rdx);
146           GC_push_one(state.__rdi);
147           GC_push_one(state.__rsi);
148           GC_push_one(state.__rbp);
149           GC_push_one(state.__r8);
150           GC_push_one(state.__r9);
151           GC_push_one(state.__r10);
152           GC_push_one(state.__r11);
153           GC_push_one(state.__r12);
154           GC_push_one(state.__r13);
155           GC_push_one(state.__r14);
156           GC_push_one(state.__r15);
157 #elif defined(POWERPC)
158 #if defined(_STRUCT_PPC_EXCEPTION_STATE) && defined(__DARWIN_UNIX03)
159         lo = (void*)(state.__r1 - PPC_RED_ZONE_SIZE);
160         
161         GC_push_one(state.__r0); 
162         GC_push_one(state.__r2); 
163         GC_push_one(state.__r3); 
164         GC_push_one(state.__r4); 
165         GC_push_one(state.__r5); 
166         GC_push_one(state.__r6); 
167         GC_push_one(state.__r7); 
168         GC_push_one(state.__r8); 
169         GC_push_one(state.__r9); 
170         GC_push_one(state.__r10); 
171         GC_push_one(state.__r11); 
172         GC_push_one(state.__r12); 
173         GC_push_one(state.__r13); 
174         GC_push_one(state.__r14); 
175         GC_push_one(state.__r15); 
176         GC_push_one(state.__r16); 
177         GC_push_one(state.__r17); 
178         GC_push_one(state.__r18); 
179         GC_push_one(state.__r19); 
180         GC_push_one(state.__r20); 
181         GC_push_one(state.__r21); 
182         GC_push_one(state.__r22); 
183         GC_push_one(state.__r23); 
184         GC_push_one(state.__r24); 
185         GC_push_one(state.__r25); 
186         GC_push_one(state.__r26); 
187         GC_push_one(state.__r27); 
188         GC_push_one(state.__r28); 
189         GC_push_one(state.__r29); 
190         GC_push_one(state.__r30); 
191         GC_push_one(state.__r31);
192 #else
193         lo = (void*)(state.r1 - PPC_RED_ZONE_SIZE);
194         
195         GC_push_one(state.r0); 
196         GC_push_one(state.r2); 
197         GC_push_one(state.r3); 
198         GC_push_one(state.r4); 
199         GC_push_one(state.r5); 
200         GC_push_one(state.r6); 
201         GC_push_one(state.r7); 
202         GC_push_one(state.r8); 
203         GC_push_one(state.r9); 
204         GC_push_one(state.r10); 
205         GC_push_one(state.r11); 
206         GC_push_one(state.r12); 
207         GC_push_one(state.r13); 
208         GC_push_one(state.r14); 
209         GC_push_one(state.r15); 
210         GC_push_one(state.r16); 
211         GC_push_one(state.r17); 
212         GC_push_one(state.r18); 
213         GC_push_one(state.r19); 
214         GC_push_one(state.r20); 
215         GC_push_one(state.r21); 
216         GC_push_one(state.r22); 
217         GC_push_one(state.r23); 
218         GC_push_one(state.r24); 
219         GC_push_one(state.r25); 
220         GC_push_one(state.r26); 
221         GC_push_one(state.r27); 
222         GC_push_one(state.r28); 
223         GC_push_one(state.r29); 
224         GC_push_one(state.r30); 
225         GC_push_one(state.r31);
226 #endif
227 #elif defined(ARM)
228         lo = (void*)state.__sp;
229
230         GC_push_one(state.__r[0]);
231         GC_push_one(state.__r[1]);
232         GC_push_one(state.__r[2]);
233         GC_push_one(state.__r[3]);
234         GC_push_one(state.__r[4]);
235         GC_push_one(state.__r[5]);
236         GC_push_one(state.__r[6]);
237         GC_push_one(state.__r[7]);
238         GC_push_one(state.__r[8]);
239         GC_push_one(state.__r[9]);
240         GC_push_one(state.__r[10]);
241         GC_push_one(state.__r[11]);
242         GC_push_one(state.__r[12]);
243         /* GC_push_one(state.__sp);  */
244         GC_push_one(state.__lr);
245         GC_push_one(state.__pc);
246         GC_push_one(state.__cpsr);
247 #else
248 # error FIXME for non-x86 || ppc architectures
249 #endif
250       } /* p != me */
251       if(p->flags & MAIN_THREAD)
252         hi = GC_stackbottom;
253       else
254         hi = p->stack_end;
255
256           if (p->altstack && lo >= p->altstack && lo <= p->altstack + p->altstack_size) {
257                   altstack_lo = lo;
258                   altstack_hi = p->altstack + p->altstack_size;
259                   lo = (char*)p->stack;
260                   hi = (char*)p->stack + p->stack_size;
261           }     else {
262                   altstack_lo = NULL;
263           }
264
265 #if DEBUG_THREADS
266       GC_printf3("Darwin: Stack for thread 0x%lx = [%lx,%lx)\n",
267                  (unsigned long) p -> id,
268                  (unsigned long) lo,
269                  (unsigned long) hi
270                  );
271 #endif
272           if (lo)
273                   GC_push_all_stack(lo,hi);
274           if (altstack_lo)
275                   GC_push_all_stack(altstack_lo,altstack_hi);
276     } /* for(p=GC_threads[i]...) */
277   } /* for(i=0;i<THREAD_TABLE_SZ...) */
278 }
279
280 #else /* !DARWIN_DONT_PARSE_STACK; Use FindTopOfStack() */
281
282 void GC_push_all_stacks() {
283     int i;
284         task_t my_task;
285     kern_return_t r;
286     mach_port_t me;
287     ptr_t lo, hi;
288     thread_act_array_t act_list = 0;
289     mach_msg_type_number_t listcount = 0;
290
291     me = mach_thread_self();
292     if (!GC_thr_initialized) GC_thr_init();
293     
294         my_task = current_task();
295     r = task_threads(my_task, &act_list, &listcount);
296     if(r != KERN_SUCCESS) ABORT("task_threads failed");
297     for(i = 0; i < listcount; i++) {
298       thread_act_t thread = act_list[i];
299       if (thread == me) {
300         lo = GC_approx_sp();
301         hi = (ptr_t)FindTopOfStack(0);
302       } else {
303 #     if defined(POWERPC)
304 #      if CPP_WORDSZ == 32
305         ppc_thread_state_t info;
306 #      else
307         ppc_thread_state64_t info;
308 #      endif
309         mach_msg_type_number_t outCount = THREAD_STATE_MAX;
310         r = thread_get_state(thread, GC_MACH_THREAD_STATE_FLAVOR,
311                              (natural_t *)&info, &outCount);
312         if(r != KERN_SUCCESS) continue;
313
314 #if defined(_STRUCT_PPC_EXCEPTION_STATE)
315         lo = (void*)(info.__r1 - PPC_RED_ZONE_SIZE);
316         hi = (ptr_t)FindTopOfStack(info.__r1);
317
318         GC_push_one(info.__r0); 
319         GC_push_one(info.__r2); 
320         GC_push_one(info.__r3); 
321         GC_push_one(info.__r4); 
322         GC_push_one(info.__r5); 
323         GC_push_one(info.__r6); 
324         GC_push_one(info.__r7); 
325         GC_push_one(info.__r8); 
326         GC_push_one(info.__r9); 
327         GC_push_one(info.__r10); 
328         GC_push_one(info.__r11); 
329         GC_push_one(info.__r12); 
330         GC_push_one(info.__r13); 
331         GC_push_one(info.__r14); 
332         GC_push_one(info.__r15); 
333         GC_push_one(info.__r16); 
334         GC_push_one(info.__r17); 
335         GC_push_one(info.__r18); 
336         GC_push_one(info.__r19); 
337         GC_push_one(info.__r20); 
338         GC_push_one(info.__r21); 
339         GC_push_one(info.__r22); 
340         GC_push_one(info.__r23); 
341         GC_push_one(info.__r24); 
342         GC_push_one(info.__r25); 
343         GC_push_one(info.__r26); 
344         GC_push_one(info.__r27); 
345         GC_push_one(info.__r28); 
346         GC_push_one(info.__r29); 
347         GC_push_one(info.__r30); 
348         GC_push_one(info.__r31);
349 #else
350         lo = (void*)(info.r1 - PPC_RED_ZONE_SIZE);
351         hi = (ptr_t)FindTopOfStack(info.r1);
352
353         GC_push_one(info.r0); 
354         GC_push_one(info.r2); 
355         GC_push_one(info.r3); 
356         GC_push_one(info.r4); 
357         GC_push_one(info.r5); 
358         GC_push_one(info.r6); 
359         GC_push_one(info.r7); 
360         GC_push_one(info.r8); 
361         GC_push_one(info.r9); 
362         GC_push_one(info.r10); 
363         GC_push_one(info.r11); 
364         GC_push_one(info.r12); 
365         GC_push_one(info.r13); 
366         GC_push_one(info.r14); 
367         GC_push_one(info.r15); 
368         GC_push_one(info.r16); 
369         GC_push_one(info.r17); 
370         GC_push_one(info.r18); 
371         GC_push_one(info.r19); 
372         GC_push_one(info.r20); 
373         GC_push_one(info.r21); 
374         GC_push_one(info.r22); 
375         GC_push_one(info.r23); 
376         GC_push_one(info.r24); 
377         GC_push_one(info.r25); 
378         GC_push_one(info.r26); 
379         GC_push_one(info.r27); 
380         GC_push_one(info.r28); 
381         GC_push_one(info.r29); 
382         GC_push_one(info.r30); 
383         GC_push_one(info.r31);
384 #endif
385 #      elif defined(I386) /* !POWERPC */
386         /* FIXME: Remove after testing: */
387         WARN("This is completely untested and likely will not work\n", 0);
388         i386_thread_state_t info;
389         mach_msg_type_number_t outCount = THREAD_STATE_MAX;
390         r = thread_get_state(thread, GC_MACH_THREAD_STATE_FLAVOR,
391                              (natural_t *)&info, &outCount);
392         if(r != KERN_SUCCESS) continue;
393
394 #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
395         lo = (void*)info.__esp;
396         hi = (ptr_t)FindTopOfStack(info.__esp);
397
398         GC_push_one(info.__eax); 
399         GC_push_one(info.__ebx); 
400         GC_push_one(info.__ecx); 
401         GC_push_one(info.__edx); 
402         GC_push_one(info.__edi); 
403         GC_push_one(info.__esi); 
404         GC_push_one(info.__ebp);
405         /* GC_push_one(info.__esp);  */
406         GC_push_one(info.__ss); 
407         GC_push_one(info.__eip); 
408         GC_push_one(info.__cs); 
409         GC_push_one(info.__ds); 
410         GC_push_one(info.__es); 
411         GC_push_one(info.__fs); 
412         GC_push_one(info.__gs); 
413 #else
414         lo = (void*)info.esp;
415         hi = (ptr_t)FindTopOfStack(info.esp);
416
417         GC_push_one(info.eax); 
418         GC_push_one(info.ebx); 
419         GC_push_one(info.ecx); 
420         GC_push_one(info.edx); 
421         GC_push_one(info.edi); 
422         GC_push_one(info.esi); 
423         GC_push_one(info.ebp);
424         /* GC_push_one(info.esp);  */
425         GC_push_one(info.ss); 
426         GC_push_one(info.eip); 
427         GC_push_one(info.cs); 
428         GC_push_one(info.ds); 
429         GC_push_one(info.es); 
430         GC_push_one(info.fs); 
431         GC_push_one(info.gs); 
432 #endif
433 #      elif defined(ARM) /* !I386 */
434         arm_thread_state_t info;
435         mach_msg_type_number_t outCount = THREAD_STATE_MAX;
436         r = thread_get_state(thread, GC_MACH_THREAD_STATE_FLAVOR,
437                              (natural_t *)&info, &outCount);
438         if(r != KERN_SUCCESS) continue;
439
440         lo = (void*)info.__sp;
441         hi = (ptr_t)FindTopOfStack(info.__sp);
442
443         GC_push_one(info.__r[0]); 
444         GC_push_one(info.__r[1]); 
445         GC_push_one(info.__r[2]); 
446         GC_push_one(info.__r[3]); 
447         GC_push_one(info.__r[4]); 
448         GC_push_one(info.__r[5]); 
449         GC_push_one(info.__r[6]); 
450         GC_push_one(info.__r[7]); 
451         GC_push_one(info.__r[8]); 
452         GC_push_one(info.__r[9]); 
453         GC_push_one(info.__r[10]); 
454         GC_push_one(info.__r[11]); 
455         GC_push_one(info.__r[12]); 
456         /* GC_push_one(info.__sp);  */
457         GC_push_one(info.__lr); 
458         GC_push_one(info.__pc); 
459         GC_push_one(info.__cpsr); 
460 #      endif /* !ARM */
461       }
462 #     if DEBUG_THREADS
463        GC_printf3("Darwin: Stack for thread 0x%lx = [%lx,%lx)\n",
464                   (unsigned long) thread,
465                   (unsigned long) lo,
466                   (unsigned long) hi
467                  );
468 #     endif
469       GC_push_all_stack(lo, hi);
470           mach_port_deallocate(my_task, thread);
471     } /* for(p=GC_threads[i]...) */
472     vm_deallocate(my_task, (vm_address_t)act_list, sizeof(thread_t) * listcount);
473         mach_port_deallocate(my_task, me);
474 }
475 #endif /* !DARWIN_DONT_PARSE_STACK */
476
477 static mach_port_t GC_mach_handler_thread;
478 static int GC_use_mach_handler_thread = 0;
479
480 #define SUSPEND_THREADS_SIZE 2048
481 static struct GC_mach_thread GC_mach_threads[SUSPEND_THREADS_SIZE];
482 static int GC_mach_threads_count;
483
484 void GC_stop_init() {
485   int i;
486
487   for (i = 0; i < SUSPEND_THREADS_SIZE; i++) {
488     GC_mach_threads[i].thread = 0;
489     GC_mach_threads[i].already_suspended = 0;
490   }
491   GC_mach_threads_count = 0;
492 }
493
494 /* returns true if there's a thread in act_list that wasn't in old_list */
495 int GC_suspend_thread_list(thread_act_array_t act_list, int count, 
496                            thread_act_array_t old_list, int old_count) {
497   mach_port_t my_thread = mach_thread_self();
498   int i, j;
499
500   int changed = 0;
501
502   for(i = 0; i < count; i++) {
503     thread_act_t thread = act_list[i];
504 #   if DEBUG_THREADS 
505       GC_printf1("Attempting to suspend thread %p\n", thread);
506 #   endif
507     /* find the current thread in the old list */
508     int found = 0;
509     for(j = 0; j < old_count; j++) {
510       thread_act_t old_thread = old_list[j];
511       if (old_thread == thread) {
512         found = 1;
513         break;
514       }
515     }
516     if (!found) {
517       /* add it to the GC_mach_threads list */
518       GC_mach_threads[GC_mach_threads_count].thread = thread;
519       /* default is not suspended */
520       GC_mach_threads[GC_mach_threads_count].already_suspended = 0;
521       changed = 1;
522     }      
523
524     if (thread != my_thread &&
525         (!GC_use_mach_handler_thread
526          || (GC_use_mach_handler_thread
527              && GC_mach_handler_thread != thread))) {
528       struct thread_basic_info info;
529       mach_msg_type_number_t outCount = THREAD_INFO_MAX;
530       kern_return_t kern_result = thread_info(thread, THREAD_BASIC_INFO,
531                                 (thread_info_t)&info, &outCount);
532       if(kern_result != KERN_SUCCESS) {
533         /* the thread may have quit since the thread_threads () call 
534          * we mark already_suspended so it's not dealt with anymore later
535          */
536         if (!found) {
537           GC_mach_threads[GC_mach_threads_count].already_suspended = TRUE;
538           GC_mach_threads_count++;
539         }
540         continue;
541       }
542 #     if DEBUG_THREADS
543         GC_printf2("Thread state for 0x%lx = %d\n", thread, info.run_state);
544 #     endif
545       if (!found) {
546         GC_mach_threads[GC_mach_threads_count].already_suspended = info.suspend_count;
547       }
548       if (info.suspend_count) continue;
549       
550 #     if DEBUG_THREADS
551         GC_printf1("Suspending 0x%lx\n", thread);
552 #     endif
553       /* Suspend the thread */
554       kern_result = thread_suspend(thread);
555       if(kern_result != KERN_SUCCESS) {
556         /* the thread may have quit since the thread_threads () call 
557          * we mark already_suspended so it's not dealt with anymore later
558          */
559         if (!found) {
560           GC_mach_threads[GC_mach_threads_count].already_suspended = TRUE;
561           GC_mach_threads_count++;
562         }
563         continue;
564       }
565     } 
566     if (!found) GC_mach_threads_count++;
567   }
568   
569   mach_port_deallocate(current_task(), my_thread);
570   return changed;
571 }
572
573
574 /* Caller holds allocation lock.        */
575 void GC_stop_world()
576 {
577   int i, changes;
578     GC_thread p;
579         task_t my_task = current_task();
580     mach_port_t my_thread = mach_thread_self();
581     kern_return_t kern_result;
582     thread_act_array_t act_list, prev_list;
583     mach_msg_type_number_t listcount, prevcount;
584     
585     if (GC_notify_event)
586         GC_notify_event (GC_EVENT_PRE_STOP_WORLD);
587
588 #   if DEBUG_THREADS
589       GC_printf1("Stopping the world from 0x%lx\n", mach_thread_self());
590 #   endif
591
592     /* clear out the mach threads list table */
593     GC_stop_init(); 
594        
595     /* Make sure all free list construction has stopped before we start. */
596     /* No new construction can start, since free list construction is   */
597     /* required to acquire and release the GC lock before it starts,    */
598     /* and we have the lock.                                            */
599 #   ifdef PARALLEL_MARK
600       GC_acquire_mark_lock();
601       GC_ASSERT(GC_fl_builder_count == 0);
602       /* We should have previously waited for it to become zero. */
603 #   endif /* PARALLEL_MARK */
604
605       /* Loop stopping threads until you have gone over the whole list
606          twice without a new one appearing. thread_create() won't
607          return (and thus the thread stop) until the new thread
608          exists, so there is no window whereby you could stop a
609          thread, recognise it is stopped, but then have a new thread
610          it created before stopping show up later.
611       */
612       
613       changes = 1;
614       prev_list = NULL;
615       prevcount = 0;
616       do {
617         int result;               
618         kern_result = task_threads(my_task, &act_list, &listcount);
619         
620         if(kern_result == KERN_SUCCESS) {       
621                 result = GC_suspend_thread_list(act_list, listcount,
622                                                                                 prev_list, prevcount);
623                 changes = result;
624                 
625                 if(prev_list != NULL) {
626                         for(i = 0; i < prevcount; i++)
627                                 mach_port_deallocate(my_task, prev_list[i]);
628                         
629                         vm_deallocate(my_task, (vm_address_t)prev_list, sizeof(thread_t) * prevcount);
630                 }
631                 
632                 prev_list = act_list;
633                 prevcount = listcount;
634         }               
635       } while (changes);
636      
637           for(i = 0; i < listcount; i++)
638                   mach_port_deallocate(my_task, act_list[i]);
639           
640           vm_deallocate(my_task, (vm_address_t)act_list, sizeof(thread_t) * listcount);
641           
642  
643 #   ifdef MPROTECT_VDB
644       if(GC_incremental) {
645         extern void GC_mprotect_stop();
646         GC_mprotect_stop();
647       }
648 #   endif
649     
650 #   ifdef PARALLEL_MARK
651       GC_release_mark_lock();
652 #   endif
653     #if DEBUG_THREADS
654       GC_printf1("World stopped from 0x%lx\n", my_thread);
655     #endif
656           
657           mach_port_deallocate(my_task, my_thread);
658
659     if (GC_notify_event)
660         GC_notify_event (GC_EVENT_POST_STOP_WORLD);
661 }
662
663 /* Caller holds allocation lock, and has held it continuously since     */
664 /* the world stopped.                                                   */
665 void GC_start_world()
666 {
667   task_t my_task = current_task();
668   mach_port_t my_thread = mach_thread_self();
669   int i, j;
670   GC_thread p;
671   kern_return_t kern_result;
672   thread_act_array_t act_list;
673   mach_msg_type_number_t listcount;
674   struct thread_basic_info info;
675   mach_msg_type_number_t outCount = THREAD_INFO_MAX;
676
677   if (GC_notify_event)
678       GC_notify_event (GC_EVENT_PRE_START_WORLD);
679   
680 #   if DEBUG_THREADS
681       GC_printf0("World starting\n");
682 #   endif
683
684 #   ifdef MPROTECT_VDB
685       if(GC_incremental) {
686         extern void GC_mprotect_resume();
687         GC_mprotect_resume();
688       }
689 #   endif
690
691     kern_result = task_threads(my_task, &act_list, &listcount);
692     for(i = 0; i < listcount; i++) {
693       thread_act_t thread = act_list[i];
694       if (thread != my_thread &&
695           (!GC_use_mach_handler_thread ||
696            (GC_use_mach_handler_thread && GC_mach_handler_thread != thread))) {
697         for(j = 0; j < GC_mach_threads_count; j++) {
698           if (thread == GC_mach_threads[j].thread) {
699             if (GC_mach_threads[j].already_suspended) {
700 #             if DEBUG_THREADS
701                 GC_printf1("Not resuming already suspended thread %p\n", thread);
702 #             endif
703               continue;
704             }
705             kern_result = thread_info(thread, THREAD_BASIC_INFO,
706                                       (thread_info_t)&info, &outCount);
707             if(kern_result != KERN_SUCCESS) continue;
708 #           if DEBUG_THREADS
709               GC_printf2("Thread state for 0x%lx = %d\n", thread,
710                          info.run_state);
711               GC_printf1("Resuming 0x%lx\n", thread);
712 #           endif
713             /* Resume the thread */
714             kern_result = thread_resume(thread);
715             if(kern_result != KERN_SUCCESS) continue;
716           } 
717         }
718       }
719           
720           mach_port_deallocate(my_task, thread);
721     }
722     vm_deallocate(my_task, (vm_address_t)act_list, sizeof(thread_t) * listcount);
723         
724         mach_port_deallocate(my_task, my_thread);
725
726     if (GC_notify_event)
727         GC_notify_event (GC_EVENT_POST_START_WORLD);
728
729 #   if DEBUG_THREADS
730      GC_printf0("World started\n");
731 #   endif
732 }
733
734 void GC_darwin_register_mach_handler_thread(mach_port_t thread) {
735   GC_mach_handler_thread = thread;
736   GC_use_mach_handler_thread = 1;
737 }
738
739 #ifdef MONO_DEBUGGER_SUPPORTED
740 GCThreadFunctions *gc_thread_vtable = NULL;
741
742 void *
743 GC_mono_debugger_get_stack_ptr (void)
744 {
745         GC_thread me;
746
747         me = GC_lookup_thread (pthread_self ());
748         return &me->stop_info.stack_ptr;
749 }
750 #endif
751
752 #endif