Merge branch 'cecil-light'
[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 static
319 int android_thread_kill(pid_t tid, int sig)
320 {
321     int  ret;
322     int  old_errno = errno;
323
324     ret = tkill(tid, sig);
325     if (ret < 0) {
326         ret = errno;
327         errno = old_errno;
328     }
329
330     return ret;
331 }
332 #endif
333
334 /* We hold the allocation lock.  Suspend all threads that might */
335 /* still be running.  Return the number of suspend signals that */
336 /* were sent. */
337 int GC_suspend_all()
338 {
339     int n_live_threads = 0;
340     int i;
341     GC_thread p;
342     int result;
343     pthread_t my_thread = pthread_self();
344     
345     GC_stopping_thread = my_thread;    /* debugging only.      */
346     GC_stopping_pid = getpid();                /* debugging only.      */
347     for (i = 0; i < THREAD_TABLE_SZ; i++) {
348       for (p = GC_threads[i]; p != 0; p = p -> next) {
349         if (p -> id != my_thread) {
350             if (p -> flags & FINISHED) continue;
351             if (p -> stop_info.last_stop_count == GC_stop_count) continue;
352             if (p -> thread_blocked) /* Will wait */ continue;
353             n_live_threads++;
354             #if DEBUG_THREADS
355               GC_printf1("Sending suspend signal to 0x%lx\n", p -> id);
356             #endif
357
358 #ifndef PLATFORM_ANDROID
359         result = pthread_kill(p -> id, SIG_SUSPEND);
360 #else
361         result = android_thread_kill(p -> kernel_id, SIG_SUSPEND);
362 #endif
363             switch(result) {
364                 case ESRCH:
365                     /* Not really there anymore.  Possible? */
366                     n_live_threads--;
367                     break;
368                 case 0:
369                     break;
370                 default:
371                     ABORT("pthread_kill failed");
372             }
373         }
374       }
375     }
376     return n_live_threads;
377 }
378
379 /* Caller holds allocation lock.        */
380 static void pthread_stop_world()
381 {
382     int i;
383     int n_live_threads;
384     int code;
385
386     #if DEBUG_THREADS
387     GC_printf1("Stopping the world from 0x%lx\n", pthread_self());
388     #endif
389
390     n_live_threads = GC_suspend_all();
391
392       if (GC_retry_signals) {
393           unsigned long wait_usecs = 0;  /* Total wait since retry.     */
394 #         define WAIT_UNIT 3000
395 #         define RETRY_INTERVAL 100000
396           for (;;) {
397               int ack_count;
398
399               sem_getvalue(&GC_suspend_ack_sem, &ack_count);
400               if (ack_count == n_live_threads) break;
401               if (wait_usecs > RETRY_INTERVAL) {
402                   int newly_sent = GC_suspend_all();
403
404 #                 ifdef CONDPRINT
405                     if (GC_print_stats) {
406                       GC_printf1("Resent %ld signals after timeout\n",
407                                  newly_sent);
408                     }
409 #                 endif
410                   sem_getvalue(&GC_suspend_ack_sem, &ack_count);
411                   if (newly_sent < n_live_threads - ack_count) {
412                       WARN("Lost some threads during GC_stop_world?!\n",0);
413                       n_live_threads = ack_count + newly_sent;
414                   }
415                   wait_usecs = 0;
416               }
417               usleep(WAIT_UNIT);
418               wait_usecs += WAIT_UNIT;
419           }
420       }
421     for (i = 0; i < n_live_threads; i++) {
422           while (0 != (code = sem_wait(&GC_suspend_ack_sem))) {
423               if (errno != EINTR) {
424                  GC_err_printf1("Sem_wait returned %ld\n", (unsigned long)code);
425                  ABORT("sem_wait for handler failed");
426               }
427           }
428     }
429     #if DEBUG_THREADS
430       GC_printf1("World stopped from 0x%lx\n", pthread_self());
431     #endif
432     GC_stopping_thread = 0;  /* debugging only */
433 }
434
435 /* Caller holds allocation lock.        */
436 void GC_stop_world()
437 {
438     if (GC_notify_event)
439         GC_notify_event (GC_EVENT_PRE_STOP_WORLD);
440     /* Make sure all free list construction has stopped before we start. */
441     /* No new construction can start, since free list construction is   */
442     /* required to acquire and release the GC lock before it starts,    */
443     /* and we have the lock.                                            */
444 #   ifdef PARALLEL_MARK
445       GC_acquire_mark_lock();
446       GC_ASSERT(GC_fl_builder_count == 0);
447       /* We should have previously waited for it to become zero. */
448 #   endif /* PARALLEL_MARK */
449     ++GC_stop_count;
450 #ifdef MONO_DEBUGGER_SUPPORTED
451     if (gc_thread_vtable && gc_thread_vtable->stop_world)
452         gc_thread_vtable->stop_world ();
453     else
454 #endif
455         pthread_stop_world ();
456 #   ifdef PARALLEL_MARK
457       GC_release_mark_lock();
458 #   endif
459     if (GC_notify_event)
460         GC_notify_event (GC_EVENT_POST_STOP_WORLD);
461 }
462
463 /* Caller holds allocation lock, and has held it continuously since     */
464 /* the world stopped.                                                   */
465 static void pthread_start_world()
466 {
467     pthread_t my_thread = pthread_self();
468     register int i;
469     register GC_thread p;
470     register int n_live_threads = 0;
471     register int result;
472     int code;
473
474 #   if DEBUG_THREADS
475       GC_printf0("World starting\n");
476 #   endif
477     if (GC_notify_event)
478         GC_notify_event (GC_EVENT_PRE_START_WORLD);
479
480     for (i = 0; i < THREAD_TABLE_SZ; i++) {
481       for (p = GC_threads[i]; p != 0; p = p -> next) {
482         if (p -> id != my_thread) {
483             if (p -> flags & FINISHED) continue;
484             if (p -> thread_blocked) continue;
485             n_live_threads++;
486             #if DEBUG_THREADS
487               GC_printf1("Sending restart signal to 0x%lx\n", p -> id);
488             #endif
489
490 #ifndef PLATFORM_ANDROID
491         result = pthread_kill(p -> id, SIG_THR_RESTART);
492 #else
493         result = android_thread_kill(p -> kernel_id, SIG_THR_RESTART);
494 #endif
495             switch(result) {
496                 case ESRCH:
497                     /* Not really there anymore.  Possible? */
498                     n_live_threads--;
499                     break;
500                 case 0:
501                     break;
502                 default:
503                     ABORT("pthread_kill failed");
504             }
505         }
506       }
507     }
508
509     #if DEBUG_THREADS
510     GC_printf0 ("All threads signaled");
511     #endif
512
513     for (i = 0; i < n_live_threads; i++) {
514         while (0 != (code = sem_wait(&GC_suspend_ack_sem))) {
515             if (errno != EINTR) {
516                 GC_err_printf1("Sem_wait returned %ld\n", (unsigned long)code);
517                 ABORT("sem_wait for handler failed");
518             }
519         }
520     }
521   
522     if (GC_notify_event)
523         GC_notify_event (GC_EVENT_POST_START_WORLD);
524     #if DEBUG_THREADS
525       GC_printf0("World started\n");
526     #endif
527 }
528
529 void GC_start_world()
530 {
531 #ifdef MONO_DEBUGGER_SUPPORTED
532     if (gc_thread_vtable && gc_thread_vtable->start_world)
533         gc_thread_vtable->start_world();
534     else
535 #endif
536         pthread_start_world ();
537 }
538
539 static void pthread_stop_init() {
540     struct sigaction act;
541     
542     if (sem_init(&GC_suspend_ack_sem, 0, 0) != 0)
543         ABORT("sem_init failed");
544
545     act.sa_flags = SA_RESTART;
546     if (sigfillset(&act.sa_mask) != 0) {
547         ABORT("sigfillset() failed");
548     }
549     GC_remove_allowed_signals(&act.sa_mask);
550     /* SIG_THR_RESTART is set in the resulting mask.            */
551     /* It is unmasked by the handler when necessary.            */
552     act.sa_handler = GC_suspend_handler;
553     if (sigaction(SIG_SUSPEND, &act, NULL) != 0) {
554         ABORT("Cannot set SIG_SUSPEND handler");
555     }
556
557     act.sa_handler = GC_restart_handler;
558     if (sigaction(SIG_THR_RESTART, &act, NULL) != 0) {
559         ABORT("Cannot set SIG_THR_RESTART handler");
560     }
561
562     /* Inititialize suspend_handler_mask. It excludes SIG_THR_RESTART. */
563       if (sigfillset(&suspend_handler_mask) != 0) ABORT("sigfillset() failed");
564       GC_remove_allowed_signals(&suspend_handler_mask);
565       if (sigdelset(&suspend_handler_mask, SIG_THR_RESTART) != 0)
566           ABORT("sigdelset() failed");
567
568     /* Check for GC_RETRY_SIGNALS.      */
569       if (0 != GETENV("GC_RETRY_SIGNALS")) {
570           GC_retry_signals = TRUE;
571       }
572       if (0 != GETENV("GC_NO_RETRY_SIGNALS")) {
573           GC_retry_signals = FALSE;
574       }
575 #     ifdef CONDPRINT
576           if (GC_print_stats && GC_retry_signals) {
577               GC_printf0("Will retry suspend signal if necessary.\n");
578           }
579 #     endif
580 }
581
582 /* We hold the allocation lock. */
583 void GC_stop_init()
584 {
585 #ifdef MONO_DEBUGGER_SUPPORTED
586     if (gc_thread_vtable && gc_thread_vtable->initialize)
587         gc_thread_vtable->initialize ();
588     else
589 #endif
590         pthread_stop_init ();
591 }
592
593 #ifdef MONO_DEBUGGER_SUPPORTED
594
595 GCThreadFunctions *gc_thread_vtable = NULL;
596
597 void *
598 GC_mono_debugger_get_stack_ptr (void)
599 {
600         GC_thread me;
601
602         me = GC_lookup_thread (pthread_self ());
603         return &me->stop_info.stack_ptr;
604 }
605
606 #endif
607
608 #endif