Merge branch 'master' of github.com:mono/mono into masterwork
[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
7 #include <signal.h>
8 #include <semaphore.h>
9 #include <errno.h>
10 #include <unistd.h>
11
12 /* work around a dlopen issue (bug #75390), undefs to avoid warnings with redefinitions */
13 #undef PACKAGE_BUGREPORT
14 #undef PACKAGE_NAME
15 #undef PACKAGE_STRING
16 #undef PACKAGE_TARNAME
17 #undef PACKAGE_VERSION
18 #include "mono/utils/mono-compiler.h"
19
20 #ifdef MONO_DEBUGGER_SUPPORTED
21 #include "include/libgc-mono-debugger.h"
22 #endif
23
24 #if DEBUG_THREADS
25
26 #ifndef NSIG
27 # if defined(MAXSIG)
28 #  define NSIG (MAXSIG+1)
29 # elif defined(_NSIG)
30 #  define NSIG _NSIG
31 # elif defined(__SIGRTMAX)
32 #  define NSIG (__SIGRTMAX+1)
33 # else
34   --> please fix it
35 # endif
36 #endif
37
38 void GC_print_sig_mask()
39 {
40     sigset_t blocked;
41     int i;
42
43     if (pthread_sigmask(SIG_BLOCK, NULL, &blocked) != 0)
44         ABORT("pthread_sigmask");
45     GC_printf0("Blocked: ");
46     for (i = 1; i < NSIG; i++) {
47         if (sigismember(&blocked, i)) { GC_printf1("%ld ",(long) i); }
48     }
49     GC_printf0("\n");
50 }
51
52 #endif
53
54 /* Remove the signals that we want to allow in thread stopping  */
55 /* handler from a set.                                          */
56 void GC_remove_allowed_signals(sigset_t *set)
57 {
58 #   ifdef NO_SIGNALS
59       if (sigdelset(set, SIGINT) != 0
60           || sigdelset(set, SIGQUIT) != 0
61           || sigdelset(set, SIGABRT) != 0
62           || sigdelset(set, SIGTERM) != 0) {
63         ABORT("sigdelset() failed");
64       }
65 #   endif
66
67 #   ifdef MPROTECT_VDB
68       /* Handlers write to the thread structure, which is in the heap,  */
69       /* and hence can trigger a protection fault.                      */
70       if (sigdelset(set, SIGSEGV) != 0
71 #         ifdef SIGBUS
72             || sigdelset(set, SIGBUS) != 0
73 #         endif
74           ) {
75         ABORT("sigdelset() failed");
76       }
77 #   endif
78 }
79
80 static sigset_t suspend_handler_mask;
81
82 word GC_stop_count;     /* Incremented at the beginning of GC_stop_world. */
83
84 #ifdef GC_OSF1_THREADS
85   GC_bool GC_retry_signals = TRUE;
86 #else
87   GC_bool GC_retry_signals = FALSE;
88 #endif
89
90 /*
91  * We use signals to stop threads during GC.
92  * 
93  * Suspended threads wait in signal handler for SIG_THR_RESTART.
94  * That's more portable than semaphores or condition variables.
95  * (We do use sem_post from a signal handler, but that should be portable.)
96  *
97  * The thread suspension signal SIG_SUSPEND is now defined in gc_priv.h.
98  * Note that we can't just stop a thread; we need it to save its stack
99  * pointer(s) and acknowledge.
100  */
101
102 #ifndef SIG_THR_RESTART
103 #  if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS)
104 #    ifdef _SIGRTMIN
105 #      define SIG_THR_RESTART _SIGRTMIN + 5
106 #    else
107 #      define SIG_THR_RESTART SIGRTMIN + 5
108 #    endif
109 #  else
110 #   define SIG_THR_RESTART SIGXCPU
111 #  endif
112 #endif
113
114 sem_t GC_suspend_ack_sem;
115
116 static void _GC_suspend_handler(int sig)
117 {
118     int dummy;
119     pthread_t my_thread = pthread_self();
120     GC_thread me;
121 #   ifdef PARALLEL_MARK
122         word my_mark_no = GC_mark_no;
123         /* Marker can't proceed until we acknowledge.  Thus this is     */
124         /* guaranteed to be the mark_no correspending to our            */
125         /* suspension, i.e. the marker can't have incremented it yet.   */
126 #   endif
127     word my_stop_count = GC_stop_count;
128
129     if (sig != SIG_SUSPEND) ABORT("Bad signal in suspend_handler");
130
131 #if DEBUG_THREADS
132     GC_printf1("Suspending 0x%lx\n", my_thread);
133 #endif
134
135     me = GC_lookup_thread(my_thread);
136     /* The lookup here is safe, since I'm doing this on behalf  */
137     /* of a thread which holds the allocation lock in order     */
138     /* to stop the world.  Thus concurrent modification of the  */
139     /* data structure is impossible.                            */
140     if (me -> stop_info.last_stop_count == my_stop_count) {
141         /* Duplicate signal.  OK if we are retrying.    */
142         if (!GC_retry_signals) {
143             WARN("Duplicate suspend signal in thread %lx\n",
144                  pthread_self());
145         }
146         return;
147     }
148 #   ifdef SPARC
149         me -> stop_info.stack_ptr = (ptr_t)GC_save_regs_in_stack();
150 #   else
151         me -> stop_info.stack_ptr = (ptr_t)(&dummy);
152 #   endif
153 #   ifdef IA64
154         me -> backing_store_ptr = (ptr_t)GC_save_regs_in_stack();
155 #   endif
156
157     /* Tell the thread that wants to stop the world that this   */
158     /* thread has been stopped.  Note that sem_post() is        */
159     /* the only async-signal-safe primitive in LinuxThreads.    */
160     sem_post(&GC_suspend_ack_sem);
161     me -> stop_info.last_stop_count = my_stop_count;
162
163     /* Wait until that thread tells us to restart by sending    */
164     /* this thread a SIG_THR_RESTART signal.                    */
165     /* SIG_THR_RESTART should be masked at this point.  Thus there      */
166     /* is no race.                                              */
167     do {
168             me->stop_info.signal = 0;
169             sigsuspend(&suspend_handler_mask);        /* Wait for signal */
170     } while (me->stop_info.signal != SIG_THR_RESTART);
171     /* If the RESTART signal gets lost, we can still lose.  That should be  */
172     /* less likely than losing the SUSPEND signal, since we don't do much   */
173     /* between the sem_post and sigsuspend.                                 */
174     /* We'd need more handshaking to work around that, since we don't want  */
175     /* to accidentally leave a RESTART signal pending, thus causing us to   */
176     /* continue prematurely in a future round.                              */ 
177
178     /* Tell the thread that wants to start the world that this  */
179     /* thread has been started.  Note that sem_post() is        */
180     /* the only async-signal-safe primitive in LinuxThreads.    */
181     sem_post(&GC_suspend_ack_sem);
182
183
184 #if DEBUG_THREADS
185     GC_printf1("Continuing 0x%lx\n", my_thread);
186 #endif
187 }
188
189 void GC_suspend_handler(int sig)
190 {
191         int old_errno = errno;
192         _GC_suspend_handler(sig);
193         errno = old_errno;
194 }
195
196 static void _GC_restart_handler(int sig)
197 {
198     pthread_t my_thread = pthread_self();
199     GC_thread me;
200
201     if (sig != SIG_THR_RESTART) ABORT("Bad signal in suspend_handler");
202
203     /* Let the GC_suspend_handler() know that we got a SIG_THR_RESTART. */
204     /* The lookup here is safe, since I'm doing this on behalf  */
205     /* of a thread which holds the allocation lock in order     */
206     /* to stop the world.  Thus concurrent modification of the  */
207     /* data structure is impossible.                            */
208     me = GC_lookup_thread(my_thread);
209     me->stop_info.signal = SIG_THR_RESTART;
210
211     /*
212     ** Note: even if we didn't do anything useful here,
213     ** it would still be necessary to have a signal handler,
214     ** rather than ignoring the signals, otherwise
215     ** the signals will not be delivered at all, and
216     ** will thus not interrupt the sigsuspend() above.
217     */
218
219 #if DEBUG_THREADS
220     GC_printf1("In GC_restart_handler for 0x%lx\n", pthread_self());
221 #endif
222 }
223
224 # ifdef IA64
225 #   define IF_IA64(x) x
226 # else
227 #   define IF_IA64(x)
228 # endif
229 /* We hold allocation lock.  Should do exactly the right thing if the   */
230 /* world is stopped.  Should not fail if it isn't.                      */
231 static void pthread_push_all_stacks()
232 {
233     GC_bool found_me = FALSE;
234     int i;
235     GC_thread p;
236     ptr_t lo, hi;
237     /* On IA64, we also need to scan the register backing store. */
238     IF_IA64(ptr_t bs_lo; ptr_t bs_hi;)
239     pthread_t me = pthread_self();
240     
241     if (!GC_thr_initialized) GC_thr_init();
242     #if DEBUG_THREADS
243         GC_printf1("Pushing stacks from thread 0x%lx\n", (unsigned long) me);
244     #endif
245     for (i = 0; i < THREAD_TABLE_SZ; i++) {
246       for (p = GC_threads[i]; p != 0; p = p -> next) {
247         if (p -> flags & FINISHED) continue;
248         if (pthread_equal(p -> id, me)) {
249 #           ifdef SPARC
250                 lo = (ptr_t)GC_save_regs_in_stack();
251 #           else
252                 lo = GC_approx_sp();
253 #           endif
254             found_me = TRUE;
255             IF_IA64(bs_hi = (ptr_t)GC_save_regs_in_stack();)
256         } else {
257             lo = p -> stop_info.stack_ptr;
258             IF_IA64(bs_hi = p -> backing_store_ptr;)
259         }
260         if ((p -> flags & MAIN_THREAD) == 0) {
261             hi = p -> stack_end;
262             IF_IA64(bs_lo = p -> backing_store_end);
263         } else {
264             /* The original stack. */
265             hi = GC_stackbottom;
266             IF_IA64(bs_lo = BACKING_STORE_BASE;)
267         }
268         #if DEBUG_THREADS
269             GC_printf3("Stack for thread 0x%lx = [%lx,%lx)\n",
270                 (unsigned long) p -> id,
271                 (unsigned long) lo, (unsigned long) hi);
272         #endif
273         if (0 == lo) ABORT("GC_push_all_stacks: sp not set!\n");
274 #       ifdef STACK_GROWS_UP
275           /* We got them backwards! */
276           GC_push_all_stack(hi, lo);
277 #       else
278           GC_push_all_stack(lo, hi);
279 #       endif
280 #       ifdef IA64
281 #         if DEBUG_THREADS
282             GC_printf3("Reg stack for thread 0x%lx = [%lx,%lx)\n",
283                 (unsigned long) p -> id,
284                 (unsigned long) bs_lo, (unsigned long) bs_hi);
285 #         endif
286           if (pthread_equal(p -> id, me)) {
287             GC_push_all_eager(bs_lo, bs_hi);
288           } else {
289             GC_push_all_stack(bs_lo, bs_hi);
290           }
291 #       endif
292       }
293     }
294     if (!found_me && !GC_in_thread_creation)
295       ABORT("Collecting from unknown thread.");
296 }
297
298 void GC_restart_handler(int sig)
299 {
300         int old_errno = errno;
301         _GC_restart_handler (sig);
302         errno = old_errno;
303 }
304
305 /* We hold allocation lock.  Should do exactly the right thing if the   */
306 /* world is stopped.  Should not fail if it isn't.                      */
307 void GC_push_all_stacks()
308 {
309     pthread_push_all_stacks();
310 }
311
312 /* There seems to be a very rare thread stopping problem.  To help us  */
313 /* debug that, we save the ids of the stopping thread. */
314 pthread_t GC_stopping_thread;
315 int GC_stopping_pid;
316
317 #ifdef PLATFORM_ANDROID
318 int android_thread_kill(pid_t tid, int sig)
319 {
320     int  ret;
321     int  old_errno = errno;
322
323     ret = tkill(tid, sig);
324     if (ret < 0) {
325         ret = errno;
326         errno = old_errno;
327     }
328
329     return ret;
330 }
331 #endif
332
333 /* We hold the allocation lock.  Suspend all threads that might */
334 /* still be running.  Return the number of suspend signals that */
335 /* were sent. */
336 int GC_suspend_all()
337 {
338     int n_live_threads = 0;
339     int i;
340     GC_thread p;
341     int result;
342     pthread_t my_thread = pthread_self();
343     
344     GC_stopping_thread = my_thread;    /* debugging only.      */
345     GC_stopping_pid = getpid();                /* debugging only.      */
346     for (i = 0; i < THREAD_TABLE_SZ; i++) {
347       for (p = GC_threads[i]; p != 0; p = p -> next) {
348         if (p -> id != my_thread) {
349             if (p -> flags & FINISHED) continue;
350             if (p -> stop_info.last_stop_count == GC_stop_count) continue;
351             if (p -> thread_blocked) /* Will wait */ continue;
352             n_live_threads++;
353             #if DEBUG_THREADS
354               GC_printf1("Sending suspend signal to 0x%lx\n", p -> id);
355             #endif
356
357 #ifndef PLATFORM_ANDROID
358         result = pthread_kill(p -> id, SIG_SUSPEND);
359 #else
360         result = android_thread_kill(p -> kernel_id, SIG_SUSPEND);
361 #endif
362             switch(result) {
363                 case ESRCH:
364                     /* Not really there anymore.  Possible? */
365                     n_live_threads--;
366                     break;
367                 case 0:
368                     break;
369                 default:
370                     ABORT("pthread_kill failed");
371             }
372         }
373       }
374     }
375     return n_live_threads;
376 }
377
378 /* Caller holds allocation lock.        */
379 static void pthread_stop_world()
380 {
381     int i;
382     int n_live_threads;
383     int code;
384
385     #if DEBUG_THREADS
386     GC_printf1("Stopping the world from 0x%lx\n", pthread_self());
387     #endif
388
389     n_live_threads = GC_suspend_all();
390
391       if (GC_retry_signals) {
392           unsigned long wait_usecs = 0;  /* Total wait since retry.     */
393 #         define WAIT_UNIT 3000
394 #         define RETRY_INTERVAL 100000
395           for (;;) {
396               int ack_count;
397
398               sem_getvalue(&GC_suspend_ack_sem, &ack_count);
399               if (ack_count == n_live_threads) break;
400               if (wait_usecs > RETRY_INTERVAL) {
401                   int newly_sent = GC_suspend_all();
402
403 #                 ifdef CONDPRINT
404                     if (GC_print_stats) {
405                       GC_printf1("Resent %ld signals after timeout\n",
406                                  newly_sent);
407                     }
408 #                 endif
409                   sem_getvalue(&GC_suspend_ack_sem, &ack_count);
410                   if (newly_sent < n_live_threads - ack_count) {
411                       WARN("Lost some threads during GC_stop_world?!\n",0);
412                       n_live_threads = ack_count + newly_sent;
413                   }
414                   wait_usecs = 0;
415               }
416               usleep(WAIT_UNIT);
417               wait_usecs += WAIT_UNIT;
418           }
419       }
420     for (i = 0; i < n_live_threads; i++) {
421           while (0 != (code = sem_wait(&GC_suspend_ack_sem))) {
422               if (errno != EINTR) {
423                  GC_err_printf1("Sem_wait returned %ld\n", (unsigned long)code);
424                  ABORT("sem_wait for handler failed");
425               }
426           }
427     }
428     #if DEBUG_THREADS
429       GC_printf1("World stopped from 0x%lx\n", pthread_self());
430     #endif
431     GC_stopping_thread = 0;  /* debugging only */
432 }
433
434 /* Caller holds allocation lock.        */
435 void GC_stop_world()
436 {
437     if (GC_notify_event)
438         GC_notify_event (GC_EVENT_PRE_STOP_WORLD);
439     /* Make sure all free list construction has stopped before we start. */
440     /* No new construction can start, since free list construction is   */
441     /* required to acquire and release the GC lock before it starts,    */
442     /* and we have the lock.                                            */
443 #   ifdef PARALLEL_MARK
444       GC_acquire_mark_lock();
445       GC_ASSERT(GC_fl_builder_count == 0);
446       /* We should have previously waited for it to become zero. */
447 #   endif /* PARALLEL_MARK */
448     ++GC_stop_count;
449 #ifdef MONO_DEBUGGER_SUPPORTED
450     if (gc_thread_vtable && gc_thread_vtable->stop_world)
451         gc_thread_vtable->stop_world ();
452     else
453 #endif
454         pthread_stop_world ();
455 #   ifdef PARALLEL_MARK
456       GC_release_mark_lock();
457 #   endif
458     if (GC_notify_event)
459         GC_notify_event (GC_EVENT_POST_STOP_WORLD);
460 }
461
462 /* Caller holds allocation lock, and has held it continuously since     */
463 /* the world stopped.                                                   */
464 static void pthread_start_world()
465 {
466     pthread_t my_thread = pthread_self();
467     register int i;
468     register GC_thread p;
469     register int n_live_threads = 0;
470     register int result;
471     int code;
472
473 #   if DEBUG_THREADS
474       GC_printf0("World starting\n");
475 #   endif
476     if (GC_notify_event)
477         GC_notify_event (GC_EVENT_PRE_START_WORLD);
478
479     for (i = 0; i < THREAD_TABLE_SZ; i++) {
480       for (p = GC_threads[i]; p != 0; p = p -> next) {
481         if (p -> id != my_thread) {
482             if (p -> flags & FINISHED) continue;
483             if (p -> thread_blocked) continue;
484             n_live_threads++;
485             #if DEBUG_THREADS
486               GC_printf1("Sending restart signal to 0x%lx\n", p -> id);
487             #endif
488
489 #ifndef PLATFORM_ANDROID
490         result = pthread_kill(p -> id, SIG_THR_RESTART);
491 #else
492         result = android_thread_kill(p -> kernel_id, SIG_THR_RESTART);
493 #endif
494             switch(result) {
495                 case ESRCH:
496                     /* Not really there anymore.  Possible? */
497                     n_live_threads--;
498                     break;
499                 case 0:
500                     break;
501                 default:
502                     ABORT("pthread_kill failed");
503             }
504         }
505       }
506     }
507
508     #if DEBUG_THREADS
509     GC_printf0 ("All threads signaled");
510     #endif
511
512     for (i = 0; i < n_live_threads; i++) {
513         while (0 != (code = sem_wait(&GC_suspend_ack_sem))) {
514             if (errno != EINTR) {
515                 GC_err_printf1("Sem_wait returned %ld\n", (unsigned long)code);
516                 ABORT("sem_wait for handler failed");
517             }
518         }
519     }
520   
521     if (GC_notify_event)
522         GC_notify_event (GC_EVENT_POST_START_WORLD);
523     #if DEBUG_THREADS
524       GC_printf0("World started\n");
525     #endif
526 }
527
528 void GC_start_world()
529 {
530 #ifdef MONO_DEBUGGER_SUPPORTED
531     if (gc_thread_vtable && gc_thread_vtable->start_world)
532         gc_thread_vtable->start_world();
533     else
534 #endif
535         pthread_start_world ();
536 }
537
538 static void pthread_stop_init() {
539     struct sigaction act;
540     
541     if (sem_init(&GC_suspend_ack_sem, 0, 0) != 0)
542         ABORT("sem_init failed");
543
544     act.sa_flags = SA_RESTART;
545     if (sigfillset(&act.sa_mask) != 0) {
546         ABORT("sigfillset() failed");
547     }
548     GC_remove_allowed_signals(&act.sa_mask);
549     /* SIG_THR_RESTART is set in the resulting mask.            */
550     /* It is unmasked by the handler when necessary.            */
551     act.sa_handler = GC_suspend_handler;
552     if (sigaction(SIG_SUSPEND, &act, NULL) != 0) {
553         ABORT("Cannot set SIG_SUSPEND handler");
554     }
555
556     act.sa_handler = GC_restart_handler;
557     if (sigaction(SIG_THR_RESTART, &act, NULL) != 0) {
558         ABORT("Cannot set SIG_THR_RESTART handler");
559     }
560
561     /* Inititialize suspend_handler_mask. It excludes SIG_THR_RESTART. */
562       if (sigfillset(&suspend_handler_mask) != 0) ABORT("sigfillset() failed");
563       GC_remove_allowed_signals(&suspend_handler_mask);
564       if (sigdelset(&suspend_handler_mask, SIG_THR_RESTART) != 0)
565           ABORT("sigdelset() failed");
566
567     /* Check for GC_RETRY_SIGNALS.      */
568       if (0 != GETENV("GC_RETRY_SIGNALS")) {
569           GC_retry_signals = TRUE;
570       }
571       if (0 != GETENV("GC_NO_RETRY_SIGNALS")) {
572           GC_retry_signals = FALSE;
573       }
574 #     ifdef CONDPRINT
575           if (GC_print_stats && GC_retry_signals) {
576               GC_printf0("Will retry suspend signal if necessary.\n");
577           }
578 #     endif
579 }
580
581 /* We hold the allocation lock. */
582 void GC_stop_init()
583 {
584 #ifdef MONO_DEBUGGER_SUPPORTED
585     if (gc_thread_vtable && gc_thread_vtable->initialize)
586         gc_thread_vtable->initialize ();
587     else
588 #endif
589         pthread_stop_init ();
590 }
591
592 #ifdef MONO_DEBUGGER_SUPPORTED
593
594 GCThreadFunctions *gc_thread_vtable = NULL;
595
596 void *
597 GC_mono_debugger_get_stack_ptr (void)
598 {
599         GC_thread me;
600
601         me = GC_lookup_thread (pthread_self ());
602         return &me->stop_info.stack_ptr;
603 }
604
605 #endif
606
607 #endif