/[dotgnu-pnet]/pnet/libgc/pthread_stop_world.c
ViewVC logotype

Diff of /pnet/libgc/pthread_stop_world.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.2 by ktreichel, Sat Jul 23 12:52:58 2005 UTC revision 1.3 by ktreichel, Sat Sep 17 16:54:39 2005 UTC
# Line 7  Line 7 
7  #include <semaphore.h>  #include <semaphore.h>
8  #include <errno.h>  #include <errno.h>
9  #include <unistd.h>  #include <unistd.h>
10    #include <sys/time.h>
11    #ifndef HPUX
12    # include <sys/select.h>
13      /* Doesn't exist on HP/UX 11.11. */
14    #endif
15    
16  #if DEBUG_THREADS  #if DEBUG_THREADS
17    
# Line 66  void GC_remove_allowed_signals(sigset_t Line 71  void GC_remove_allowed_signals(sigset_t
71    
72  static sigset_t suspend_handler_mask;  static sigset_t suspend_handler_mask;
73    
74  word GC_stop_count;     /* Incremented at the beginning of GC_stop_world. */  volatile sig_atomic_t GC_stop_count;
75                            /* Incremented at the beginning of GC_stop_world. */
76    
77    volatile sig_atomic_t GC_world_is_stopped = FALSE;
78                            /* FALSE ==> it is safe for threads to restart, i.e. */
79                            /* they will see another suspend signal before they  */
80                            /* are expected to stop (unless they have voluntarily */
81                            /* stopped).                                         */
82    
83    void GC_brief_async_signal_safe_sleep()
84    {
85        struct timeval tv;
86        tv.tv_sec = 0;
87        tv.tv_usec = 1000 * TIME_LIMIT / 2;
88        select(0, 0, 0, 0, &tv);
89    }
90    
91  #ifdef GC_OSF1_THREADS  #ifdef GC_OSF1_THREADS
92    GC_bool GC_retry_signals = TRUE;    GC_bool GC_retry_signals = TRUE;
# Line 175  void GC_suspend_handler_inner(ptr_t sig_ Line 195  void GC_suspend_handler_inner(ptr_t sig_
195      /* this thread a SIG_THR_RESTART signal.                    */      /* this thread a SIG_THR_RESTART signal.                    */
196      /* SIG_THR_RESTART should be masked at this point.  Thus there      */      /* SIG_THR_RESTART should be masked at this point.  Thus there      */
197      /* is no race.                                              */      /* is no race.                                              */
198      do {      /* We do not continue until we receive a SIG_THR_RESTART,   */
199              me->stop_info.signal = 0;      /* but we do not take that as authoritative.  (We may be    */
200              sigsuspend(&suspend_handler_mask);        /* Wait for signal */      /* accidentally restarted by one of the user signals we     */
201      } while (me->stop_info.signal != SIG_THR_RESTART);      /* don't block.)  After we receive the signal, we use a     */
202        /* primitive and expensive mechanism to wait until it's     */
203        /* really safe to proceed.  Under normal circumstances,     */
204        /* this code should not be executed.                        */
205        sigsuspend(&suspend_handler_mask);        /* Wait for signal */
206        while (GC_world_is_stopped && GC_stop_count == my_stop_count) {
207            GC_brief_async_signal_safe_sleep();
208    #       if DEBUG_THREADS
209              GC_err_printf0("Sleeping in signal handler");
210    #       endif
211        }
212      /* If the RESTART signal gets lost, we can still lose.  That should be  */      /* If the RESTART signal gets lost, we can still lose.  That should be  */
213      /* less likely than losing the SUSPEND signal, since we don't do much   */      /* less likely than losing the SUSPEND signal, since we don't do much   */
214      /* between the sem_post and sigsuspend.                                 */      /* between the sem_post and sigsuspend.                                 */
215      /* We'd need more handshaking to work around that, since we don't want  */      /* We'd need more handshaking to work around that.                      */
216      /* to accidentally leave a RESTART signal pending, thus causing us to   */      /* Simply dropping the sigsuspend call should be safe, but is unlikely  */
217      /* continue prematurely in a future round.                              */      /* to be efficient.                                                     */
218    
219  #if DEBUG_THREADS  #if DEBUG_THREADS
220      GC_printf1("Continuing 0x%lx\n", my_thread);      GC_printf1("Continuing 0x%lx\n", my_thread);
# Line 194  void GC_suspend_handler_inner(ptr_t sig_ Line 224  void GC_suspend_handler_inner(ptr_t sig_
224  void GC_restart_handler(int sig)  void GC_restart_handler(int sig)
225  {  {
226      pthread_t my_thread = pthread_self();      pthread_t my_thread = pthread_self();
     GC_thread me;  
227    
228      if (sig != SIG_THR_RESTART) ABORT("Bad signal in suspend_handler");      if (sig != SIG_THR_RESTART) ABORT("Bad signal in suspend_handler");
229    
     /* Let the GC_suspend_handler() know that we got a SIG_THR_RESTART. */  
     /* The lookup here is safe, since I'm doing this on behalf  */  
     /* of a thread which holds the allocation lock in order     */  
     /* to stop the world.  Thus concurrent modification of the  */  
     /* data structure is impossible.                            */  
     me = GC_lookup_thread(my_thread);  
     me->stop_info.signal = SIG_THR_RESTART;  
   
230      /*      /*
231      ** Note: even if we didn't do anything useful here,      ** Note: even if we don't do anything useful here,
232      ** it would still be necessary to have a signal handler,      ** it would still be necessary to have a signal handler,
233      ** rather than ignoring the signals, otherwise      ** rather than ignoring the signals, otherwise
234      ** the signals will not be delivered at all, and      ** the signals will not be delivered at all, and
# Line 360  void GC_stop_world() Line 381  void GC_stop_world()
381        /* We should have previously waited for it to become zero. */        /* We should have previously waited for it to become zero. */
382  #   endif /* PARALLEL_MARK */  #   endif /* PARALLEL_MARK */
383      ++GC_stop_count;      ++GC_stop_count;
384        GC_world_is_stopped = TRUE;
385      n_live_threads = GC_suspend_all();      n_live_threads = GC_suspend_all();
386    
387        if (GC_retry_signals) {        if (GC_retry_signals) {
# Line 422  void GC_start_world() Line 444  void GC_start_world()
444        GC_printf0("World starting\n");        GC_printf0("World starting\n");
445  #   endif  #   endif
446    
447        GC_world_is_stopped = FALSE;
448      for (i = 0; i < THREAD_TABLE_SZ; i++) {      for (i = 0; i < THREAD_TABLE_SZ; i++) {
449        for (p = GC_threads[i]; p != 0; p = p -> next) {        for (p = GC_threads[i]; p != 0; p = p -> next) {
450          if (p -> id != my_thread) {          if (p -> id != my_thread) {
# Line 431  void GC_start_world() Line 454  void GC_start_world()
454              #if DEBUG_THREADS              #if DEBUG_THREADS
455                GC_printf1("Sending restart signal to 0x%lx\n", p -> id);                GC_printf1("Sending restart signal to 0x%lx\n", p -> id);
456              #endif              #endif
457                        result = pthread_kill(p -> id, SIG_THR_RESTART);
         result = pthread_kill(p -> id, SIG_THR_RESTART);  
458              switch(result) {              switch(result) {
459                  case ESRCH:                  case ESRCH:
460                      /* Not really there anymore.  Possible? */                      /* Not really there anymore.  Possible? */

Legend:
Removed from v.1.2  
changed lines
  Added in v.1.3

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26