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