Merge pull request #572 from jack-pappas/sockets-ipproto
[mono.git] / libgc / pthread_stop_world.c
1 #include "private/pthread_support.h"
2
3 #if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
4      && !defined(GC_IRIX_THREADS) && !defined(GC_WIN32_THREADS) \
5      && !defined(GC_DARWIN_THREADS) && !defined(GC_AIX_THREADS) \
6      && !defined(GC_OPENBSD_THREADS)
7
8 #include <signal.h>
9 #include <semaphore.h>
10 #include <errno.h>
11 #include <unistd.h>
12 #include <sys/time.h>
13
14 /* work around a dlopen issue (bug #75390), undefs to avoid warnings with redefinitions */
15 #undef PACKAGE_BUGREPORT
16 #undef PACKAGE_NAME
17 #undef PACKAGE_STRING
18 #undef PACKAGE_TARNAME
19 #undef PACKAGE_VERSION
20 #include "mono/utils/mono-compiler.h"
21
22 #ifdef MONO_DEBUGGER_SUPPORTED
23 #include "include/libgc-mono-debugger.h"
24 #endif
25
26 #ifdef NACL
27 volatile int __nacl_thread_suspension_needed = 0;
28 pthread_t nacl_thread_parker = -1;
29
30 volatile int nacl_thread_parked[MAX_NACL_GC_THREADS];
31 volatile int nacl_thread_used[MAX_NACL_GC_THREADS];
32 volatile int nacl_thread_parking_inited = 0;
33 volatile int nacl_num_gc_threads = 0;
34 pthread_mutex_t nacl_thread_alloc_lock = PTHREAD_MUTEX_INITIALIZER;
35 __thread int nacl_thread_idx = -1;
36 __thread GC_thread nacl_gc_thread_self = NULL;
37 #endif
38
39 #if DEBUG_THREADS
40
41 #ifndef NSIG
42 # if defined(MAXSIG)
43 #  define NSIG (MAXSIG+1)
44 # elif defined(_NSIG)
45 #  define NSIG _NSIG
46 # elif defined(__SIGRTMAX)
47 #  define NSIG (__SIGRTMAX+1)
48 # else
49   --> please fix it
50 # endif
51 #endif
52
53 #ifndef NACL
54 void GC_print_sig_mask()
55 {
56     sigset_t blocked;
57     int i;
58
59     if (pthread_sigmask(SIG_BLOCK, NULL, &blocked) != 0)
60         ABORT("pthread_sigmask");
61     GC_printf0("Blocked: ");
62     for (i = 1; i < NSIG; i++) {
63         if (sigismember(&blocked, i)) { GC_printf1("%ld ",(long) i); }
64     }
65     GC_printf0("\n");
66 }
67 #endif /* NACL */
68 #endif
69
70 /* Remove the signals that we want to allow in thread stopping  */
71 /* handler from a set.                                          */
72 void GC_remove_allowed_signals(sigset_t *set)
73 {
74 #   ifdef NO_SIGNALS
75       if (sigdelset(set, SIGINT) != 0
76           || sigdelset(set, SIGQUIT) != 0
77           || sigdelset(set, SIGABRT) != 0
78           || sigdelset(set, SIGTERM) != 0) {
79         ABORT("sigdelset() failed");
80       }
81 #   endif
82
83 #   ifdef MPROTECT_VDB
84       /* Handlers write to the thread structure, which is in the heap,  */
85       /* and hence can trigger a protection fault.                      */
86       if (sigdelset(set, SIGSEGV) != 0
87 #         ifdef SIGBUS
88             || sigdelset(set, SIGBUS) != 0
89 #         endif
90           ) {
91         ABORT("sigdelset() failed");
92       }
93 #   endif
94 }
95
96 static sigset_t suspend_handler_mask;
97
98 word GC_stop_count;     /* Incremented at the beginning of GC_stop_world. */
99
100 #ifdef GC_OSF1_THREADS
101   GC_bool GC_retry_signals = TRUE;
102 #else
103   GC_bool GC_retry_signals = FALSE;
104 #endif
105
106 /*
107  * We use signals to stop threads during GC.
108  * 
109  * Suspended threads wait in signal handler for SIG_THR_RESTART.
110  * That's more portable than semaphores or condition variables.
111  * (We do use sem_post from a signal handler, but that should be portable.)
112  *
113  * The thread suspension signal SIG_SUSPEND is now defined in gc_priv.h.
114  * Note that we can't just stop a thread; we need it to save its stack
115  * pointer(s) and acknowledge.
116  */
117
118 #ifndef SIG_THR_RESTART
119 #  if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS)
120 #    ifdef _SIGRTMIN
121 #      define SIG_THR_RESTART _SIGRTMIN + 5
122 #    else
123 #      define SIG_THR_RESTART SIGRTMIN + 5
124 #    endif
125 #  else
126 #   define SIG_THR_RESTART SIGXCPU
127 #  endif
128 #endif
129
130 sem_t GC_suspend_ack_sem;
131
132 static void _GC_suspend_handler(int sig)
133 {
134 #ifndef NACL
135     int dummy;
136     pthread_t my_thread = pthread_self();
137     GC_thread me;
138 #   ifdef PARALLEL_MARK
139         word my_mark_no = GC_mark_no;
140         /* Marker can't proceed until we acknowledge.  Thus this is     */
141         /* guaranteed to be the mark_no correspending to our            */
142         /* suspension, i.e. the marker can't have incremented it yet.   */
143 #   endif
144     word my_stop_count = GC_stop_count;
145
146     if (sig != SIG_SUSPEND) ABORT("Bad signal in suspend_handler");
147
148 #if DEBUG_THREADS
149     GC_printf1("Suspending 0x%lx\n", my_thread);
150 #endif
151
152     me = GC_lookup_thread(my_thread);
153     /* The lookup here is safe, since I'm doing this on behalf  */
154     /* of a thread which holds the allocation lock in order     */
155     /* to stop the world.  Thus concurrent modification of the  */
156     /* data structure is impossible.                            */
157     if (me -> stop_info.last_stop_count == my_stop_count) {
158         /* Duplicate signal.  OK if we are retrying.    */
159         if (!GC_retry_signals) {
160             WARN("Duplicate suspend signal in thread %lx\n",
161                  pthread_self());
162         }
163         return;
164     }
165 #   ifdef SPARC
166         me -> stop_info.stack_ptr = (ptr_t)GC_save_regs_in_stack();
167 #   else
168         me -> stop_info.stack_ptr = (ptr_t)(&dummy);
169 #   endif
170 #   ifdef IA64
171         me -> backing_store_ptr = (ptr_t)GC_save_regs_in_stack();
172 #   endif
173
174     /* Tell the thread that wants to stop the world that this   */
175     /* thread has been stopped.  Note that sem_post() is        */
176     /* the only async-signal-safe primitive in LinuxThreads.    */
177     sem_post(&GC_suspend_ack_sem);
178     me -> stop_info.last_stop_count = my_stop_count;
179
180     /* Wait until that thread tells us to restart by sending    */
181     /* this thread a SIG_THR_RESTART signal.                    */
182     /* SIG_THR_RESTART should be masked at this point.  Thus there      */
183     /* is no race.                                              */
184     do {
185             me->stop_info.signal = 0;
186             sigsuspend(&suspend_handler_mask);        /* Wait for signal */
187     } while (me->stop_info.signal != SIG_THR_RESTART);
188     /* If the RESTART signal gets lost, we can still lose.  That should be  */
189     /* less likely than losing the SUSPEND signal, since we don't do much   */
190     /* between the sem_post and sigsuspend.                                 */
191     /* We'd need more handshaking to work around that, since we don't want  */
192     /* to accidentally leave a RESTART signal pending, thus causing us to   */
193     /* continue prematurely in a future round.                              */ 
194
195     /* Tell the thread that wants to start the world that this  */
196     /* thread has been started.  Note that sem_post() is        */
197     /* the only async-signal-safe primitive in LinuxThreads.    */
198     sem_post(&GC_suspend_ack_sem);
199
200
201 #if DEBUG_THREADS
202     GC_printf1("Continuing 0x%lx\n", my_thread);
203 #endif
204
205 #endif /* NACL */
206 }
207
208 void GC_suspend_handler(int sig)
209 {
210         int old_errno = errno;
211         _GC_suspend_handler(sig);
212         errno = old_errno;
213 }
214
215 static void _GC_restart_handler(int sig)
216 {
217     pthread_t my_thread = pthread_self();
218     GC_thread me;
219
220     if (sig != SIG_THR_RESTART) ABORT("Bad signal in suspend_handler");
221
222     /* Let the GC_suspend_handler() know that we got a SIG_THR_RESTART. */
223     /* The lookup here is safe, since I'm doing this on behalf  */
224     /* of a thread which holds the allocation lock in order     */
225     /* to stop the world.  Thus concurrent modification of the  */
226     /* data structure is impossible.                            */
227     me = GC_lookup_thread(my_thread);
228     me->stop_info.signal = SIG_THR_RESTART;
229
230     /*
231     ** Note: even if we didn't do anything useful here,
232     ** it would still be necessary to have a signal handler,
233     ** rather than ignoring the signals, otherwise
234     ** the signals will not be delivered at all, and
235     ** will thus not interrupt the sigsuspend() above.
236     */
237
238 #if DEBUG_THREADS
239     GC_printf1("In GC_restart_handler for 0x%lx\n", pthread_self());
240 #endif
241 }
242
243 # ifdef IA64
244 #   define IF_IA64(x) x
245 # else
246 #   define IF_IA64(x)
247 # endif
248 /* We hold allocation lock.  Should do exactly the right thing if the   */
249 /* world is stopped.  Should not fail if it isn't.                      */
250 static void pthread_push_all_stacks()
251 {
252     GC_bool found_me = FALSE;
253     int i;
254     GC_thread p;
255     ptr_t lo, hi;
256     /* On IA64, we also need to scan the register backing store. */
257     IF_IA64(ptr_t bs_lo; ptr_t bs_hi;)
258     pthread_t me = pthread_self();
259     
260     if (!GC_thr_initialized) GC_thr_init();
261     #if DEBUG_THREADS
262         GC_printf1("Pushing stacks from thread 0x%lx\n", (unsigned long) me);
263     #endif
264     for (i = 0; i < THREAD_TABLE_SZ; i++) {
265       for (p = GC_threads[i]; p != 0; p = p -> next) {
266         if (p -> flags & FINISHED) continue;
267         if (pthread_equal(p -> id, me)) {
268 #           ifdef SPARC
269                 lo = (ptr_t)GC_save_regs_in_stack();
270 #           else
271                 lo = GC_approx_sp();
272 #           endif
273             found_me = TRUE;
274             IF_IA64(bs_hi = (ptr_t)GC_save_regs_in_stack();)
275         } else {
276             lo = p -> stop_info.stack_ptr;
277             IF_IA64(bs_hi = p -> backing_store_ptr;)
278         }
279         if ((p -> flags & MAIN_THREAD) == 0) {
280             hi = p -> stack_end;
281             IF_IA64(bs_lo = p -> backing_store_end);
282         } else {
283             /* The original stack. */
284             hi = GC_stackbottom;
285             IF_IA64(bs_lo = BACKING_STORE_BASE;)
286         }
287         #if DEBUG_THREADS
288             GC_printf3("Stack for thread 0x%lx = [%lx,%lx)\n",
289                 (unsigned long) p -> id,
290                 (unsigned long) lo, (unsigned long) hi);
291         #endif
292         if (0 == lo) ABORT("GC_push_all_stacks: sp not set!\n");
293         if (p->altstack && lo >= p->altstack && lo <= p->altstack + p->altstack_size)
294                 hi = p->altstack + p->altstack_size;
295        /* FIXME: Need to scan the normal stack too, but how ? */
296
297 #       ifdef STACK_GROWS_UP
298           /* We got them backwards! */
299           GC_push_all_stack(hi, lo);
300 #       else
301           GC_push_all_stack(lo, hi);
302 #       endif
303 #       ifdef NACL
304           /* Push reg_storage as roots, this will cover the reg context */
305           GC_push_all_stack(p -> stop_info.reg_storage, p -> stop_info.reg_storage + NACL_GC_REG_STORAGE_SIZE);
306 #       endif
307 #       ifdef IA64
308 #         if DEBUG_THREADS
309             GC_printf3("Reg stack for thread 0x%lx = [%lx,%lx)\n",
310                 (unsigned long) p -> id,
311                 (unsigned long) bs_lo, (unsigned long) bs_hi);
312 #         endif
313           if (pthread_equal(p -> id, me)) {
314             GC_push_all_eager(bs_lo, bs_hi);
315           } else {
316             GC_push_all_stack(bs_lo, bs_hi);
317           }
318 #       endif
319       }
320     }
321     if (!found_me && !GC_in_thread_creation)
322       ABORT("Collecting from unknown thread.");
323 }
324
325 void GC_restart_handler(int sig)
326 {
327         int old_errno = errno;
328         _GC_restart_handler (sig);
329         errno = old_errno;
330 }
331
332 /* We hold allocation lock.  Should do exactly the right thing if the   */
333 /* world is stopped.  Should not fail if it isn't.                      */
334 void GC_push_all_stacks()
335 {
336     pthread_push_all_stacks();
337 }
338
339 /* There seems to be a very rare thread stopping problem.  To help us  */
340 /* debug that, we save the ids of the stopping thread. */
341 pthread_t GC_stopping_thread;
342 int GC_stopping_pid;
343
344 #ifdef PLATFORM_ANDROID
345 static
346 int android_thread_kill(pid_t tid, int sig)
347 {
348     int  ret;
349     int  old_errno = errno;
350
351     ret = tkill(tid, sig);
352     if (ret < 0) {
353         ret = errno;
354         errno = old_errno;
355     }
356
357     return ret;
358 }
359 #endif
360
361 /* We hold the allocation lock.  Suspend all threads that might */
362 /* still be running.  Return the number of suspend signals that */
363 /* were sent. */
364 int GC_suspend_all()
365 {
366 #ifndef NACL
367     int n_live_threads = 0;
368     int i;
369     GC_thread p;
370     int result;
371     pthread_t my_thread = pthread_self();
372     
373     GC_stopping_thread = my_thread;    /* debugging only.      */
374     GC_stopping_pid = getpid();                /* debugging only.      */
375     for (i = 0; i < THREAD_TABLE_SZ; i++) {
376       for (p = GC_threads[i]; p != 0; p = p -> next) {
377         if (p -> id != my_thread) {
378             if (p -> flags & FINISHED) continue;
379             if (p -> stop_info.last_stop_count == GC_stop_count) continue;
380             if (p -> thread_blocked) /* Will wait */ continue;
381             n_live_threads++;
382             #if DEBUG_THREADS
383               GC_printf1("Sending suspend signal to 0x%lx\n", p -> id);
384             #endif
385
386 #ifndef PLATFORM_ANDROID
387         result = pthread_kill(p -> id, SIG_SUSPEND);
388 #else
389         result = android_thread_kill(p -> kernel_id, SIG_SUSPEND);
390 #endif
391             switch(result) {
392                 case ESRCH:
393                     /* Not really there anymore.  Possible? */
394                     n_live_threads--;
395                     break;
396                 case 0:
397                     break;
398                 default:
399                     ABORT("pthread_kill failed");
400             }
401         }
402       }
403     }
404     return n_live_threads;
405 #else /* NACL */
406     return 0;
407 #endif
408 }
409
410 /* Caller holds allocation lock.        */
411 static void pthread_stop_world()
412 {
413 #ifndef NACL
414     int i;
415     int n_live_threads;
416     int code;
417
418     #if DEBUG_THREADS
419     GC_printf1("Stopping the world from 0x%lx\n", pthread_self());
420     #endif
421
422     n_live_threads = GC_suspend_all();
423
424       if (GC_retry_signals) {
425           unsigned long wait_usecs = 0;  /* Total wait since retry.     */
426 #         define WAIT_UNIT 3000
427 #         define RETRY_INTERVAL 100000
428           for (;;) {
429               int ack_count;
430
431               sem_getvalue(&GC_suspend_ack_sem, &ack_count);
432               if (ack_count == n_live_threads) break;
433               if (wait_usecs > RETRY_INTERVAL) {
434                   int newly_sent = GC_suspend_all();
435
436 #                 ifdef CONDPRINT
437                     if (GC_print_stats) {
438                       GC_printf1("Resent %ld signals after timeout\n",
439                                  newly_sent);
440                     }
441 #                 endif
442                   sem_getvalue(&GC_suspend_ack_sem, &ack_count);
443                   if (newly_sent < n_live_threads - ack_count) {
444                       WARN("Lost some threads during GC_stop_world?!\n",0);
445                       n_live_threads = ack_count + newly_sent;
446                   }
447                   wait_usecs = 0;
448               }
449               usleep(WAIT_UNIT);
450               wait_usecs += WAIT_UNIT;
451           }
452       }
453     for (i = 0; i < n_live_threads; i++) {
454           while (0 != (code = sem_wait(&GC_suspend_ack_sem))) {
455               if (errno != EINTR) {
456                  GC_err_printf1("Sem_wait returned %ld\n", (unsigned long)code);
457                  ABORT("sem_wait for handler failed");
458               }
459           }
460     }
461     #if DEBUG_THREADS
462       GC_printf1("World stopped from 0x%lx\n", pthread_self());
463     #endif
464     GC_stopping_thread = 0;  /* debugging only */
465 #else /* NACL */
466     GC_thread p;
467     int i;
468     int num_sleeps = 0;
469
470     #if DEBUG_THREADS
471     GC_printf1("pthread_stop_world: num_threads %d\n", nacl_num_gc_threads - 1);
472     #endif
473     nacl_thread_parker = pthread_self();
474     __nacl_thread_suspension_needed = 1;
475     
476     while (1) {
477         #define NACL_PARK_WAIT_NANOSECONDS 100000
478         #define NANOS_PER_SECOND 1000000000
479         int num_threads_parked = 0;
480         struct timespec ts;
481         int num_used = 0;
482         /* Check the 'parked' flag for each thread the GC knows about */
483         for (i = 0; i < MAX_NACL_GC_THREADS && num_used < nacl_num_gc_threads; i++) {
484             if (nacl_thread_used[i] == 1) {
485                 num_used++;
486                 if (nacl_thread_parked[i] == 1) {
487                     num_threads_parked++;
488                 }
489             }
490         }
491         /* -1 for the current thread */
492         if (num_threads_parked >= nacl_num_gc_threads - 1)
493             break;
494         ts.tv_sec = 0;
495         ts.tv_nsec = NACL_PARK_WAIT_NANOSECONDS;
496         #if DEBUG_THREADS
497         GC_printf1("sleeping waiting for %d threads to park...\n", nacl_num_gc_threads - num_threads_parked - 1);
498         #endif
499         nanosleep(&ts, 0);
500         if (++num_sleeps > NANOS_PER_SECOND / NACL_PARK_WAIT_NANOSECONDS) {
501             GC_printf1("GC appears stalled waiting for %d threads to park...\n", nacl_num_gc_threads - num_threads_parked - 1);
502             num_sleeps = 0;
503         }
504     }
505
506 #endif /* NACL */
507 }
508
509
510 #ifdef NACL
511
512 #if __x86_64__
513
514 #define NACL_STORE_REGS()  \
515     do {                  \
516         __asm__ __volatile__ ("push %rbx");\
517         __asm__ __volatile__ ("push %rbp");\
518         __asm__ __volatile__ ("push %r12");\
519         __asm__ __volatile__ ("push %r13");\
520         __asm__ __volatile__ ("push %r14");\
521         __asm__ __volatile__ ("push %r15");\
522         __asm__ __volatile__ ("mov %%esp, %0" : "=m" (nacl_gc_thread_self->stop_info.stack_ptr));\
523         memcpy(nacl_gc_thread_self->stop_info.reg_storage, nacl_gc_thread_self->stop_info.stack_ptr, NACL_GC_REG_STORAGE_SIZE * sizeof(ptr_t));\
524         __asm__ __volatile__ ("naclasp $48, %r15");\
525     } while (0)
526
527 #elif __i386__
528
529 #define NACL_STORE_REGS()  \
530     do {                  \
531         __asm__ __volatile__ ("push %ebx");\
532         __asm__ __volatile__ ("push %ebp");\
533         __asm__ __volatile__ ("push %esi");\
534         __asm__ __volatile__ ("push %edi");\
535         __asm__ __volatile__ ("mov %%esp, %0" : "=m" (nacl_gc_thread_self->stop_info.stack_ptr));\
536         memcpy(nacl_gc_thread_self->stop_info.reg_storage, nacl_gc_thread_self->stop_info.stack_ptr, NACL_GC_REG_STORAGE_SIZE * sizeof(ptr_t));\
537         __asm__ __volatile__ ("add $16, %esp");\
538     } while (0)
539
540 #elif __arm__
541
542 #define NACL_STORE_REGS()  \
543     do {                   \
544         __asm__ __volatile__ (                      \
545                 ".align 4\n\t"                      \
546                 "bic %0, %0, #0xc0000000\n\t"       \
547                 "str sp, [%0]\n\t"                  \
548                 "bic %1, %1, #0xc0000000\n\t"       \
549                 "stm %1, {r4-r8,r10-r12,lr}\n\t"    \
550                         :                                               \
551                         : "r" (&nacl_gc_thread_self->stop_info.stack_ptr), \
552                          "r"(nacl_gc_thread_self->stop_info.reg_storage) \
553                         : "memory");                 \
554     } while (0)
555 #else
556
557 #error "Please port NACL_STORE_REGS"
558
559 #endif
560
561 void nacl_pre_syscall_hook()
562 {
563     int local_dummy = 0;
564     if (nacl_thread_idx != -1) {
565         NACL_STORE_REGS();
566         nacl_gc_thread_self->stop_info.stack_ptr = (ptr_t)(&local_dummy);
567         nacl_thread_parked[nacl_thread_idx] = 1;
568     }
569 }
570
571 void __nacl_suspend_thread_if_needed();
572
573 void nacl_post_syscall_hook()
574 {
575     /* Calling __nacl_suspend_thread_if_needed() right away should guarantee we don't mutate the GC set. */
576     __nacl_suspend_thread_if_needed();
577     if (nacl_thread_idx != -1) {
578         nacl_thread_parked[nacl_thread_idx] = 0;
579     }
580 }
581
582 void __nacl_suspend_thread_if_needed() {
583     if (__nacl_thread_suspension_needed) {
584         pthread_t self = pthread_self();
585         int local_dummy = 0;
586         /* Don't try to park the thread parker. */
587         if (nacl_thread_parker == self)
588             return;
589
590         /* This can happen when a thread is created   */
591         /* outside of the GC system (wthread mostly). */
592         if (nacl_thread_idx < 0)
593             return;
594
595         /* If it was already 'parked', we're returning from a syscall, */
596         /* so don't bother storing registers again, the GC has a set.  */
597         if (!nacl_thread_parked[nacl_thread_idx]) {
598             NACL_STORE_REGS();
599             nacl_gc_thread_self->stop_info.stack_ptr = (ptr_t)(&local_dummy);
600         }
601         nacl_thread_parked[nacl_thread_idx] = 1;
602         while (__nacl_thread_suspension_needed)
603             ; /* spin */
604         nacl_thread_parked[nacl_thread_idx] = 0;
605
606         /* Clear out the reg storage for next suspend. */
607         memset(nacl_gc_thread_self->stop_info.reg_storage, 0, NACL_GC_REG_STORAGE_SIZE * sizeof(ptr_t));
608     }
609 }
610
611 #endif /* NACL */
612
613 /* Caller holds allocation lock.        */
614 void GC_stop_world()
615 {
616     if (GC_notify_event)
617         GC_notify_event (GC_EVENT_PRE_STOP_WORLD);
618     /* Make sure all free list construction has stopped before we start. */
619     /* No new construction can start, since free list construction is   */
620     /* required to acquire and release the GC lock before it starts,    */
621     /* and we have the lock.                                            */
622 #   ifdef PARALLEL_MARK
623       GC_acquire_mark_lock();
624       GC_ASSERT(GC_fl_builder_count == 0);
625       /* We should have previously waited for it to become zero. */
626 #   endif /* PARALLEL_MARK */
627     ++GC_stop_count;
628 #ifdef MONO_DEBUGGER_SUPPORTED
629     if (gc_thread_vtable && gc_thread_vtable->stop_world)
630         gc_thread_vtable->stop_world ();
631     else
632 #endif
633         pthread_stop_world ();
634 #   ifdef PARALLEL_MARK
635       GC_release_mark_lock();
636 #   endif
637     if (GC_notify_event)
638         GC_notify_event (GC_EVENT_POST_STOP_WORLD);
639 }
640
641 /* Caller holds allocation lock, and has held it continuously since     */
642 /* the world stopped.                                                   */
643 static void pthread_start_world()
644 {
645 #ifndef NACL
646     pthread_t my_thread = pthread_self();
647     register int i;
648     register GC_thread p;
649     register int n_live_threads = 0;
650     register int result;
651     int code;
652
653 #   if DEBUG_THREADS
654       GC_printf0("World starting\n");
655 #   endif
656     if (GC_notify_event)
657         GC_notify_event (GC_EVENT_PRE_START_WORLD);
658
659     for (i = 0; i < THREAD_TABLE_SZ; i++) {
660       for (p = GC_threads[i]; p != 0; p = p -> next) {
661         if (p -> id != my_thread) {
662             if (p -> flags & FINISHED) continue;
663             if (p -> thread_blocked) continue;
664             n_live_threads++;
665             #if DEBUG_THREADS
666               GC_printf1("Sending restart signal to 0x%lx\n", p -> id);
667             #endif
668
669 #ifndef PLATFORM_ANDROID
670         result = pthread_kill(p -> id, SIG_THR_RESTART);
671 #else
672         result = android_thread_kill(p -> kernel_id, SIG_THR_RESTART);
673 #endif
674             switch(result) {
675                 case ESRCH:
676                     /* Not really there anymore.  Possible? */
677                     n_live_threads--;
678                     break;
679                 case 0:
680                     break;
681                 default:
682                     ABORT("pthread_kill failed");
683             }
684         }
685       }
686     }
687
688     #if DEBUG_THREADS
689     GC_printf0 ("All threads signaled");
690     #endif
691
692     for (i = 0; i < n_live_threads; i++) {
693         while (0 != (code = sem_wait(&GC_suspend_ack_sem))) {
694             if (errno != EINTR) {
695                 GC_err_printf1("Sem_wait returned %ld\n", (unsigned long)code);
696                 ABORT("sem_wait for handler failed");
697             }
698         }
699     }
700   
701     if (GC_notify_event)
702         GC_notify_event (GC_EVENT_POST_START_WORLD);
703     #if DEBUG_THREADS
704       GC_printf0("World started\n");
705     #endif
706 #else /* NACL */
707     if (GC_notify_event)
708         GC_notify_event (GC_EVENT_PRE_START_WORLD);
709 #   if DEBUG_THREADS
710     GC_printf0("World starting\n");
711 #   endif
712     __nacl_thread_suspension_needed = 0;
713     if (GC_notify_event)
714         GC_notify_event (GC_EVENT_POST_START_WORLD);
715 #endif /* NACL */
716 }
717
718 void GC_start_world()
719 {
720 #ifdef MONO_DEBUGGER_SUPPORTED
721     if (gc_thread_vtable && gc_thread_vtable->start_world)
722         gc_thread_vtable->start_world();
723     else
724 #endif
725         pthread_start_world ();
726 }
727
728 static void pthread_stop_init() {
729 #ifndef NACL
730     struct sigaction act;
731     
732     if (sem_init(&GC_suspend_ack_sem, 0, 0) != 0)
733         ABORT("sem_init failed");
734
735     act.sa_flags = SA_RESTART;
736     if (sigfillset(&act.sa_mask) != 0) {
737         ABORT("sigfillset() failed");
738     }
739     GC_remove_allowed_signals(&act.sa_mask);
740     /* SIG_THR_RESTART is set in the resulting mask.            */
741     /* It is unmasked by the handler when necessary.            */
742     act.sa_handler = GC_suspend_handler;
743     if (sigaction(SIG_SUSPEND, &act, NULL) != 0) {
744         ABORT("Cannot set SIG_SUSPEND handler");
745     }
746
747     act.sa_handler = GC_restart_handler;
748     if (sigaction(SIG_THR_RESTART, &act, NULL) != 0) {
749         ABORT("Cannot set SIG_THR_RESTART handler");
750     }
751
752     /* Inititialize suspend_handler_mask. It excludes SIG_THR_RESTART. */
753       if (sigfillset(&suspend_handler_mask) != 0) ABORT("sigfillset() failed");
754       GC_remove_allowed_signals(&suspend_handler_mask);
755       if (sigdelset(&suspend_handler_mask, SIG_THR_RESTART) != 0)
756           ABORT("sigdelset() failed");
757
758     /* Check for GC_RETRY_SIGNALS.      */
759       if (0 != GETENV("GC_RETRY_SIGNALS")) {
760           GC_retry_signals = TRUE;
761       }
762       if (0 != GETENV("GC_NO_RETRY_SIGNALS")) {
763           GC_retry_signals = FALSE;
764       }
765 #     ifdef CONDPRINT
766           if (GC_print_stats && GC_retry_signals) {
767               GC_printf0("Will retry suspend signal if necessary.\n");
768           }
769 #     endif
770 #endif /* NACL */
771 }
772
773 /* We hold the allocation lock. */
774 void GC_stop_init()
775 {
776 #ifdef MONO_DEBUGGER_SUPPORTED
777     if (gc_thread_vtable && gc_thread_vtable->initialize)
778         gc_thread_vtable->initialize ();
779     else
780 #endif
781         pthread_stop_init ();
782 }
783
784 #ifdef MONO_DEBUGGER_SUPPORTED
785
786 GCThreadFunctions *gc_thread_vtable = NULL;
787
788 void *
789 GC_mono_debugger_get_stack_ptr (void)
790 {
791         GC_thread me;
792
793         me = GC_lookup_thread (pthread_self ());
794         return &me->stop_info.stack_ptr;
795 }
796
797 #endif
798
799 #endif