New tests.
[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;
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.__rsp);
150           GC_push_one(state.__r8);
151           GC_push_one(state.__r9);
152           GC_push_one(state.__r10);
153           GC_push_one(state.__r11);
154           GC_push_one(state.__r12);
155           GC_push_one(state.__r13);
156           GC_push_one(state.__r14);
157           GC_push_one(state.__r15);
158           GC_push_one(state.__rip);
159           GC_push_one(state.__rflags);
160           GC_push_one(state.__cs);
161           GC_push_one(state.__fs);
162           GC_push_one(state.__gs);
163 #elif defined(POWERPC)
164 #if defined(_STRUCT_PPC_EXCEPTION_STATE)
165         lo = (void*)(state.__r1 - PPC_RED_ZONE_SIZE);
166         
167         GC_push_one(state.__r0); 
168         GC_push_one(state.__r2); 
169         GC_push_one(state.__r3); 
170         GC_push_one(state.__r4); 
171         GC_push_one(state.__r5); 
172         GC_push_one(state.__r6); 
173         GC_push_one(state.__r7); 
174         GC_push_one(state.__r8); 
175         GC_push_one(state.__r9); 
176         GC_push_one(state.__r10); 
177         GC_push_one(state.__r11); 
178         GC_push_one(state.__r12); 
179         GC_push_one(state.__r13); 
180         GC_push_one(state.__r14); 
181         GC_push_one(state.__r15); 
182         GC_push_one(state.__r16); 
183         GC_push_one(state.__r17); 
184         GC_push_one(state.__r18); 
185         GC_push_one(state.__r19); 
186         GC_push_one(state.__r20); 
187         GC_push_one(state.__r21); 
188         GC_push_one(state.__r22); 
189         GC_push_one(state.__r23); 
190         GC_push_one(state.__r24); 
191         GC_push_one(state.__r25); 
192         GC_push_one(state.__r26); 
193         GC_push_one(state.__r27); 
194         GC_push_one(state.__r28); 
195         GC_push_one(state.__r29); 
196         GC_push_one(state.__r30); 
197         GC_push_one(state.__r31);
198 #else
199         lo = (void*)(state.r1 - PPC_RED_ZONE_SIZE);
200         
201         GC_push_one(state.r0); 
202         GC_push_one(state.r2); 
203         GC_push_one(state.r3); 
204         GC_push_one(state.r4); 
205         GC_push_one(state.r5); 
206         GC_push_one(state.r6); 
207         GC_push_one(state.r7); 
208         GC_push_one(state.r8); 
209         GC_push_one(state.r9); 
210         GC_push_one(state.r10); 
211         GC_push_one(state.r11); 
212         GC_push_one(state.r12); 
213         GC_push_one(state.r13); 
214         GC_push_one(state.r14); 
215         GC_push_one(state.r15); 
216         GC_push_one(state.r16); 
217         GC_push_one(state.r17); 
218         GC_push_one(state.r18); 
219         GC_push_one(state.r19); 
220         GC_push_one(state.r20); 
221         GC_push_one(state.r21); 
222         GC_push_one(state.r22); 
223         GC_push_one(state.r23); 
224         GC_push_one(state.r24); 
225         GC_push_one(state.r25); 
226         GC_push_one(state.r26); 
227         GC_push_one(state.r27); 
228         GC_push_one(state.r28); 
229         GC_push_one(state.r29); 
230         GC_push_one(state.r30); 
231         GC_push_one(state.r31);
232 #endif
233 #elif defined(ARM)
234         lo = (void*)state.__sp;
235
236         GC_push_one(state.__r[0]);
237         GC_push_one(state.__r[1]);
238         GC_push_one(state.__r[2]);
239         GC_push_one(state.__r[3]);
240         GC_push_one(state.__r[4]);
241         GC_push_one(state.__r[5]);
242         GC_push_one(state.__r[6]);
243         GC_push_one(state.__r[7]);
244         GC_push_one(state.__r[8]);
245         GC_push_one(state.__r[9]);
246         GC_push_one(state.__r[10]);
247         GC_push_one(state.__r[11]);
248         GC_push_one(state.__r[12]);
249         /* GC_push_one(state.__sp);  */
250         GC_push_one(state.__lr);
251         GC_push_one(state.__pc);
252         GC_push_one(state.__cpsr);
253 #else
254 # error FIXME for non-x86 || ppc architectures
255 #endif
256       } /* p != me */
257       if(p->flags & MAIN_THREAD)
258         hi = GC_stackbottom;
259       else
260         hi = p->stack_end;
261 #if DEBUG_THREADS
262       GC_printf3("Darwin: Stack for thread 0x%lx = [%lx,%lx)\n",
263                  (unsigned long) p -> id,
264                  (unsigned long) lo,
265                  (unsigned long) hi
266                  );
267 #endif
268       GC_push_all_stack(lo,hi);
269     } /* for(p=GC_threads[i]...) */
270   } /* for(i=0;i<THREAD_TABLE_SZ...) */
271 }
272
273 #else /* !DARWIN_DONT_PARSE_STACK; Use FindTopOfStack() */
274
275 void GC_push_all_stacks() {
276     int i;
277         task_t my_task;
278     kern_return_t r;
279     mach_port_t me;
280     ptr_t lo, hi;
281     thread_act_array_t act_list = 0;
282     mach_msg_type_number_t listcount = 0;
283
284     me = mach_thread_self();
285     if (!GC_thr_initialized) GC_thr_init();
286     
287         my_task = current_task();
288     r = task_threads(my_task, &act_list, &listcount);
289     if(r != KERN_SUCCESS) ABORT("task_threads failed");
290     for(i = 0; i < listcount; i++) {
291       thread_act_t thread = act_list[i];
292       if (thread == me) {
293         lo = GC_approx_sp();
294         hi = (ptr_t)FindTopOfStack(0);
295       } else {
296 #     if defined(POWERPC)
297 #      if CPP_WORDSZ == 32
298         ppc_thread_state_t info;
299 #      else
300         ppc_thread_state64_t info;
301 #      endif
302         mach_msg_type_number_t outCount = THREAD_STATE_MAX;
303         r = thread_get_state(thread, GC_MACH_THREAD_STATE_FLAVOR,
304                              (natural_t *)&info, &outCount);
305         if(r != KERN_SUCCESS) continue;
306
307 #if defined(_STRUCT_PPC_EXCEPTION_STATE)
308         lo = (void*)(info.__r1 - PPC_RED_ZONE_SIZE);
309         hi = (ptr_t)FindTopOfStack(info.__r1);
310
311         GC_push_one(info.__r0); 
312         GC_push_one(info.__r2); 
313         GC_push_one(info.__r3); 
314         GC_push_one(info.__r4); 
315         GC_push_one(info.__r5); 
316         GC_push_one(info.__r6); 
317         GC_push_one(info.__r7); 
318         GC_push_one(info.__r8); 
319         GC_push_one(info.__r9); 
320         GC_push_one(info.__r10); 
321         GC_push_one(info.__r11); 
322         GC_push_one(info.__r12); 
323         GC_push_one(info.__r13); 
324         GC_push_one(info.__r14); 
325         GC_push_one(info.__r15); 
326         GC_push_one(info.__r16); 
327         GC_push_one(info.__r17); 
328         GC_push_one(info.__r18); 
329         GC_push_one(info.__r19); 
330         GC_push_one(info.__r20); 
331         GC_push_one(info.__r21); 
332         GC_push_one(info.__r22); 
333         GC_push_one(info.__r23); 
334         GC_push_one(info.__r24); 
335         GC_push_one(info.__r25); 
336         GC_push_one(info.__r26); 
337         GC_push_one(info.__r27); 
338         GC_push_one(info.__r28); 
339         GC_push_one(info.__r29); 
340         GC_push_one(info.__r30); 
341         GC_push_one(info.__r31);
342 #else
343         lo = (void*)(info.r1 - PPC_RED_ZONE_SIZE);
344         hi = (ptr_t)FindTopOfStack(info.r1);
345
346         GC_push_one(info.r0); 
347         GC_push_one(info.r2); 
348         GC_push_one(info.r3); 
349         GC_push_one(info.r4); 
350         GC_push_one(info.r5); 
351         GC_push_one(info.r6); 
352         GC_push_one(info.r7); 
353         GC_push_one(info.r8); 
354         GC_push_one(info.r9); 
355         GC_push_one(info.r10); 
356         GC_push_one(info.r11); 
357         GC_push_one(info.r12); 
358         GC_push_one(info.r13); 
359         GC_push_one(info.r14); 
360         GC_push_one(info.r15); 
361         GC_push_one(info.r16); 
362         GC_push_one(info.r17); 
363         GC_push_one(info.r18); 
364         GC_push_one(info.r19); 
365         GC_push_one(info.r20); 
366         GC_push_one(info.r21); 
367         GC_push_one(info.r22); 
368         GC_push_one(info.r23); 
369         GC_push_one(info.r24); 
370         GC_push_one(info.r25); 
371         GC_push_one(info.r26); 
372         GC_push_one(info.r27); 
373         GC_push_one(info.r28); 
374         GC_push_one(info.r29); 
375         GC_push_one(info.r30); 
376         GC_push_one(info.r31);
377 #endif
378 #      elif defined(I386) /* !POWERPC */
379         /* FIXME: Remove after testing: */
380         WARN("This is completely untested and likely will not work\n", 0);
381         i386_thread_state_t info;
382         mach_msg_type_number_t outCount = THREAD_STATE_MAX;
383         r = thread_get_state(thread, GC_MACH_THREAD_STATE_FLAVOR,
384                              (natural_t *)&info, &outCount);
385         if(r != KERN_SUCCESS) continue;
386
387 #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
388         lo = (void*)info.__esp;
389         hi = (ptr_t)FindTopOfStack(info.__esp);
390
391         GC_push_one(info.__eax); 
392         GC_push_one(info.__ebx); 
393         GC_push_one(info.__ecx); 
394         GC_push_one(info.__edx); 
395         GC_push_one(info.__edi); 
396         GC_push_one(info.__esi); 
397         GC_push_one(info.__ebp);
398         /* GC_push_one(info.__esp);  */
399         GC_push_one(info.__ss); 
400         GC_push_one(info.__eip); 
401         GC_push_one(info.__cs); 
402         GC_push_one(info.__ds); 
403         GC_push_one(info.__es); 
404         GC_push_one(info.__fs); 
405         GC_push_one(info.__gs); 
406 #else
407         lo = (void*)info.esp;
408         hi = (ptr_t)FindTopOfStack(info.esp);
409
410         GC_push_one(info.eax); 
411         GC_push_one(info.ebx); 
412         GC_push_one(info.ecx); 
413         GC_push_one(info.edx); 
414         GC_push_one(info.edi); 
415         GC_push_one(info.esi); 
416         GC_push_one(info.ebp);
417         /* GC_push_one(info.esp);  */
418         GC_push_one(info.ss); 
419         GC_push_one(info.eip); 
420         GC_push_one(info.cs); 
421         GC_push_one(info.ds); 
422         GC_push_one(info.es); 
423         GC_push_one(info.fs); 
424         GC_push_one(info.gs); 
425 #endif
426 #      elif defined(ARM) /* !I386 */
427         arm_thread_state_t info;
428         mach_msg_type_number_t outCount = THREAD_STATE_MAX;
429         r = thread_get_state(thread, GC_MACH_THREAD_STATE_FLAVOR,
430                              (natural_t *)&info, &outCount);
431         if(r != KERN_SUCCESS) continue;
432
433         lo = (void*)info.__sp;
434         hi = (ptr_t)FindTopOfStack(info.__sp);
435
436         GC_push_one(info.__r[0]); 
437         GC_push_one(info.__r[1]); 
438         GC_push_one(info.__r[2]); 
439         GC_push_one(info.__r[3]); 
440         GC_push_one(info.__r[4]); 
441         GC_push_one(info.__r[5]); 
442         GC_push_one(info.__r[6]); 
443         GC_push_one(info.__r[7]); 
444         GC_push_one(info.__r[8]); 
445         GC_push_one(info.__r[9]); 
446         GC_push_one(info.__r[10]); 
447         GC_push_one(info.__r[11]); 
448         GC_push_one(info.__r[12]); 
449         /* GC_push_one(info.__sp);  */
450         GC_push_one(info.__lr); 
451         GC_push_one(info.__pc); 
452         GC_push_one(info.__cpsr); 
453 #      endif /* !ARM */
454       }
455 #     if DEBUG_THREADS
456        GC_printf3("Darwin: Stack for thread 0x%lx = [%lx,%lx)\n",
457                   (unsigned long) thread,
458                   (unsigned long) lo,
459                   (unsigned long) hi
460                  );
461 #     endif
462       GC_push_all_stack(lo, hi);
463           mach_port_deallocate(my_task, thread);
464     } /* for(p=GC_threads[i]...) */
465     vm_deallocate(my_task, (vm_address_t)act_list, sizeof(thread_t) * listcount);
466         mach_port_deallocate(my_task, me);
467 }
468 #endif /* !DARWIN_DONT_PARSE_STACK */
469
470 static mach_port_t GC_mach_handler_thread;
471 static int GC_use_mach_handler_thread = 0;
472
473 #define SUSPEND_THREADS_SIZE 2048
474 static struct GC_mach_thread GC_mach_threads[SUSPEND_THREADS_SIZE];
475 static int GC_mach_threads_count;
476
477 void GC_stop_init() {
478   int i;
479
480   for (i = 0; i < SUSPEND_THREADS_SIZE; i++) {
481     GC_mach_threads[i].thread = 0;
482     GC_mach_threads[i].already_suspended = 0;
483   }
484   GC_mach_threads_count = 0;
485 }
486
487 /* returns true if there's a thread in act_list that wasn't in old_list */
488 int GC_suspend_thread_list(thread_act_array_t act_list, int count, 
489                            thread_act_array_t old_list, int old_count) {
490   mach_port_t my_thread = mach_thread_self();
491   int i, j;
492
493   int changed = 0;
494
495   for(i = 0; i < count; i++) {
496     thread_act_t thread = act_list[i];
497 #   if DEBUG_THREADS 
498       GC_printf1("Attempting to suspend thread %p\n", thread);
499 #   endif
500     /* find the current thread in the old list */
501     int found = 0;
502     for(j = 0; j < old_count; j++) {
503       thread_act_t old_thread = old_list[j];
504       if (old_thread == thread) {
505         found = 1;
506         break;
507       }
508     }
509     if (!found) {
510       /* add it to the GC_mach_threads list */
511       GC_mach_threads[GC_mach_threads_count].thread = thread;
512       /* default is not suspended */
513       GC_mach_threads[GC_mach_threads_count].already_suspended = 0;
514       changed = 1;
515     }      
516
517     if (thread != my_thread &&
518         (!GC_use_mach_handler_thread
519          || (GC_use_mach_handler_thread
520              && GC_mach_handler_thread != thread))) {
521       struct thread_basic_info info;
522       mach_msg_type_number_t outCount = THREAD_INFO_MAX;
523       kern_return_t kern_result = thread_info(thread, THREAD_BASIC_INFO,
524                                 (thread_info_t)&info, &outCount);
525       if(kern_result != KERN_SUCCESS) {
526         /* the thread may have quit since the thread_threads () call 
527          * we mark already_suspended so it's not dealt with anymore later
528          */
529         if (!found) {
530           GC_mach_threads[GC_mach_threads_count].already_suspended = TRUE;
531           GC_mach_threads_count++;
532         }
533         continue;
534       }
535 #     if DEBUG_THREADS
536         GC_printf2("Thread state for 0x%lx = %d\n", thread, info.run_state);
537 #     endif
538       if (!found) {
539         GC_mach_threads[GC_mach_threads_count].already_suspended = info.suspend_count;
540       }
541       if (info.suspend_count) continue;
542       
543 #     if DEBUG_THREADS
544         GC_printf1("Suspending 0x%lx\n", thread);
545 #     endif
546       /* Suspend the thread */
547       kern_result = thread_suspend(thread);
548       if(kern_result != KERN_SUCCESS) {
549         /* the thread may have quit since the thread_threads () call 
550          * we mark already_suspended so it's not dealt with anymore later
551          */
552         if (!found) {
553           GC_mach_threads[GC_mach_threads_count].already_suspended = TRUE;
554           GC_mach_threads_count++;
555         }
556         continue;
557       }
558     } 
559     if (!found) GC_mach_threads_count++;
560   }
561   
562   mach_port_deallocate(current_task(), my_thread);
563   return changed;
564 }
565
566
567 /* Caller holds allocation lock.        */
568 void GC_stop_world()
569 {
570   int i, changes;
571     GC_thread p;
572         task_t my_task = current_task();
573     mach_port_t my_thread = mach_thread_self();
574     kern_return_t kern_result;
575     thread_act_array_t act_list, prev_list;
576     mach_msg_type_number_t listcount, prevcount;
577     
578 #   if DEBUG_THREADS
579       GC_printf1("Stopping the world from 0x%lx\n", mach_thread_self());
580 #   endif
581
582     /* clear out the mach threads list table */
583     GC_stop_init(); 
584        
585     /* Make sure all free list construction has stopped before we start. */
586     /* No new construction can start, since free list construction is   */
587     /* required to acquire and release the GC lock before it starts,    */
588     /* and we have the lock.                                            */
589 #   ifdef PARALLEL_MARK
590       GC_acquire_mark_lock();
591       GC_ASSERT(GC_fl_builder_count == 0);
592       /* We should have previously waited for it to become zero. */
593 #   endif /* PARALLEL_MARK */
594
595       /* Loop stopping threads until you have gone over the whole list
596          twice without a new one appearing. thread_create() won't
597          return (and thus the thread stop) until the new thread
598          exists, so there is no window whereby you could stop a
599          thread, recognise it is stopped, but then have a new thread
600          it created before stopping show up later.
601       */
602       
603       changes = 1;
604       prev_list = NULL;
605       prevcount = 0;
606       do {
607         int result;               
608         kern_result = task_threads(my_task, &act_list, &listcount);
609         
610         if(kern_result == KERN_SUCCESS) {       
611                 result = GC_suspend_thread_list(act_list, listcount,
612                                                                                 prev_list, prevcount);
613                 changes = result;
614                 
615                 if(prev_list != NULL) {
616                         for(i = 0; i < prevcount; i++)
617                                 mach_port_deallocate(my_task, prev_list[i]);
618                         
619                         vm_deallocate(my_task, (vm_address_t)prev_list, sizeof(thread_t) * prevcount);
620                 }
621                 
622                 prev_list = act_list;
623                 prevcount = listcount;
624         }               
625       } while (changes);
626      
627           for(i = 0; i < listcount; i++)
628                   mach_port_deallocate(my_task, act_list[i]);
629           
630           vm_deallocate(my_task, (vm_address_t)act_list, sizeof(thread_t) * listcount);
631           
632  
633 #   ifdef MPROTECT_VDB
634       if(GC_incremental) {
635         extern void GC_mprotect_stop();
636         GC_mprotect_stop();
637       }
638 #   endif
639     
640 #   ifdef PARALLEL_MARK
641       GC_release_mark_lock();
642 #   endif
643     #if DEBUG_THREADS
644       GC_printf1("World stopped from 0x%lx\n", my_thread);
645     #endif
646           
647           mach_port_deallocate(my_task, my_thread);
648 }
649
650 /* Caller holds allocation lock, and has held it continuously since     */
651 /* the world stopped.                                                   */
652 void GC_start_world()
653 {
654   task_t my_task = current_task();
655   mach_port_t my_thread = mach_thread_self();
656   int i, j;
657   GC_thread p;
658   kern_return_t kern_result;
659   thread_act_array_t act_list;
660   mach_msg_type_number_t listcount;
661   struct thread_basic_info info;
662   mach_msg_type_number_t outCount = THREAD_INFO_MAX;
663   
664 #   if DEBUG_THREADS
665       GC_printf0("World starting\n");
666 #   endif
667
668 #   ifdef MPROTECT_VDB
669       if(GC_incremental) {
670         extern void GC_mprotect_resume();
671         GC_mprotect_resume();
672       }
673 #   endif
674
675     kern_result = task_threads(my_task, &act_list, &listcount);
676     for(i = 0; i < listcount; i++) {
677       thread_act_t thread = act_list[i];
678       if (thread != my_thread &&
679           (!GC_use_mach_handler_thread ||
680            (GC_use_mach_handler_thread && GC_mach_handler_thread != thread))) {
681         for(j = 0; j < GC_mach_threads_count; j++) {
682           if (thread == GC_mach_threads[j].thread) {
683             if (GC_mach_threads[j].already_suspended) {
684 #             if DEBUG_THREADS
685                 GC_printf1("Not resuming already suspended thread %p\n", thread);
686 #             endif
687               continue;
688             }
689             kern_result = thread_info(thread, THREAD_BASIC_INFO,
690                                       (thread_info_t)&info, &outCount);
691             if(kern_result != KERN_SUCCESS) continue;
692 #           if DEBUG_THREADS
693               GC_printf2("Thread state for 0x%lx = %d\n", thread,
694                          info.run_state);
695               GC_printf1("Resuming 0x%lx\n", thread);
696 #           endif
697             /* Resume the thread */
698             kern_result = thread_resume(thread);
699             if(kern_result != KERN_SUCCESS) continue;
700           } 
701         }
702       }
703           
704           mach_port_deallocate(my_task, thread);
705     }
706     vm_deallocate(my_task, (vm_address_t)act_list, sizeof(thread_t) * listcount);
707         
708         mach_port_deallocate(my_task, my_thread);
709 #   if DEBUG_THREADS
710      GC_printf0("World started\n");
711 #   endif
712 }
713
714 void GC_darwin_register_mach_handler_thread(mach_port_t thread) {
715   GC_mach_handler_thread = thread;
716   GC_use_mach_handler_thread = 1;
717 }
718
719 #ifdef MONO_DEBUGGER_SUPPORTED
720 GCThreadFunctions *gc_thread_vtable = NULL;
721
722 void *
723 GC_mono_debugger_get_stack_ptr (void)
724 {
725         GC_thread me;
726
727         me = GC_lookup_thread (pthread_self ());
728         return &me->stop_info.stack_ptr;
729 }
730 #endif
731
732 #endif