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