~ubuntu-branches/ubuntu/intrepid/ecl/intrepid

« back to all changes in this revision

Viewing changes to src/gc/pthread_stop_world.c

  • Committer: Bazaar Package Importer
  • Author(s): Peter Van Eynde
  • Date: 2006-06-21 09:21:21 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20060621092121-txz1f21lj0wh0f67
Tags: 0.9h-20060617-1
* New upstream version
* Updated standards version without real changes. 

Show diffs side-by-side

added added

removed removed

Lines of Context:
7
7
#include <semaphore.h>
8
8
#include <errno.h>
9
9
#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
10
15
 
11
16
#if DEBUG_THREADS
12
17
 
66
71
 
67
72
static sigset_t suspend_handler_mask;
68
73
 
69
 
word GC_stop_count;     /* Incremented at the beginning of GC_stop_world. */
 
74
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
}
70
90
 
71
91
#ifdef GC_OSF1_THREADS
72
92
  GC_bool GC_retry_signals = TRUE;
87
107
 */
88
108
 
89
109
#ifndef SIG_THR_RESTART
90
 
#  if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS)
 
110
#  if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS) || defined(GC_NETBSD_THREADS)
91
111
#    ifdef _SIGRTMIN
92
112
#      define SIG_THR_RESTART _SIGRTMIN + 5
93
113
#    else
100
120
 
101
121
sem_t GC_suspend_ack_sem;
102
122
 
 
123
#ifdef GC_NETBSD_THREADS
 
124
# define GC_NETBSD_THREADS_WORKAROUND
 
125
  /* It seems to be necessary to wait until threads have restarted.     */
 
126
  /* But it is unclear why that is the case.                            */
 
127
  sem_t GC_restart_ack_sem;
 
128
#endif
 
129
 
103
130
void GC_suspend_handler_inner(ptr_t sig_arg);
104
131
 
105
132
#if defined(IA64) || defined(HP_PA)
175
202
    /* this thread a SIG_THR_RESTART signal.                    */
176
203
    /* SIG_THR_RESTART should be masked at this point.  Thus there      */
177
204
    /* is no race.                                              */
178
 
    do {
179
 
            me->stop_info.signal = 0;
180
 
            sigsuspend(&suspend_handler_mask);        /* Wait for signal */
181
 
    } while (me->stop_info.signal != SIG_THR_RESTART);
 
205
    /* We do not continue until we receive a SIG_THR_RESTART,   */
 
206
    /* but we do not take that as authoritative.  (We may be    */
 
207
    /* accidentally restarted by one of the user signals we     */
 
208
    /* don't block.)  After we receive the signal, we use a     */
 
209
    /* primitive and expensive mechanism to wait until it's     */
 
210
    /* really safe to proceed.  Under normal circumstances,     */
 
211
    /* this code should not be executed.                        */
 
212
    sigsuspend(&suspend_handler_mask);        /* Wait for signal */
 
213
    while (GC_world_is_stopped && GC_stop_count == my_stop_count) {
 
214
        GC_brief_async_signal_safe_sleep();
 
215
#       if DEBUG_THREADS
 
216
          GC_err_printf0("Sleeping in signal handler");
 
217
#       endif
 
218
    }
182
219
    /* If the RESTART signal gets lost, we can still lose.  That should be  */
183
220
    /* less likely than losing the SUSPEND signal, since we don't do much   */
184
221
    /* between the sem_post and sigsuspend.                                 */
185
 
    /* We'd need more handshaking to work around that, since we don't want  */
186
 
    /* to accidentally leave a RESTART signal pending, thus causing us to   */
187
 
    /* continue prematurely in a future round.                              */ 
 
222
    /* We'd need more handshaking to work around that.                      */
 
223
    /* Simply dropping the sigsuspend call should be safe, but is unlikely  */
 
224
    /* to be efficient.                                                     */
188
225
 
189
226
#if DEBUG_THREADS
190
227
    GC_printf1("Continuing 0x%lx\n", my_thread);
194
231
void GC_restart_handler(int sig)
195
232
{
196
233
    pthread_t my_thread = pthread_self();
197
 
    GC_thread me;
198
234
 
199
235
    if (sig != SIG_THR_RESTART) ABORT("Bad signal in suspend_handler");
200
236
 
201
 
    /* Let the GC_suspend_handler() know that we got a SIG_THR_RESTART. */
202
 
    /* The lookup here is safe, since I'm doing this on behalf  */
203
 
    /* of a thread which holds the allocation lock in order     */
204
 
    /* to stop the world.  Thus concurrent modification of the  */
205
 
    /* data structure is impossible.                            */
206
 
    me = GC_lookup_thread(my_thread);
207
 
    me->stop_info.signal = SIG_THR_RESTART;
 
237
#ifdef GC_NETBSD_THREADS_WORKAROUND
 
238
    sem_post(&GC_restart_ack_sem);
 
239
#endif
208
240
 
209
241
    /*
210
 
    ** Note: even if we didn't do anything useful here,
 
242
    ** Note: even if we don't do anything useful here,
211
243
    ** it would still be necessary to have a signal handler,
212
244
    ** rather than ignoring the signals, otherwise
213
245
    ** the signals will not be delivered at all, and
282
314
                (unsigned long) bs_lo, (unsigned long) bs_hi);
283
315
#         endif
284
316
          if (pthread_equal(p -> id, me)) {
 
317
            /* FIXME:  This may add an unbounded number of entries,     */
 
318
            /* and hence overflow the mark stack, which is bad.         */
285
319
            GC_push_all_eager(bs_lo, bs_hi);
286
320
          } else {
287
321
            GC_push_all_stack(bs_lo, bs_hi);
360
394
      /* We should have previously waited for it to become zero. */
361
395
#   endif /* PARALLEL_MARK */
362
396
    ++GC_stop_count;
 
397
    GC_world_is_stopped = TRUE;
363
398
    n_live_threads = GC_suspend_all();
364
399
 
365
400
      if (GC_retry_signals) {
417
452
    register GC_thread p;
418
453
    register int n_live_threads = 0;
419
454
    register int result;
 
455
#ifdef GC_NETBSD_THREADS_WORKAROUND
 
456
    int code;
 
457
#endif
420
458
 
421
459
#   if DEBUG_THREADS
422
460
      GC_printf0("World starting\n");
423
461
#   endif
424
462
 
 
463
    GC_world_is_stopped = FALSE;
425
464
    for (i = 0; i < THREAD_TABLE_SZ; i++) {
426
465
      for (p = GC_threads[i]; p != 0; p = p -> next) {
427
466
        if (p -> id != my_thread) {
431
470
            #if DEBUG_THREADS
432
471
              GC_printf1("Sending restart signal to 0x%lx\n", p -> id);
433
472
            #endif
434
 
        
435
 
        result = pthread_kill(p -> id, SIG_THR_RESTART);
 
473
            result = pthread_kill(p -> id, SIG_THR_RESTART);
436
474
            switch(result) {
437
475
                case ESRCH:
438
476
                    /* Not really there anymore.  Possible? */
446
484
        }
447
485
      }
448
486
    }
 
487
#ifdef GC_NETBSD_THREADS_WORKAROUND
 
488
    for (i = 0; i < n_live_threads; i++)
 
489
        while (0 != (code = sem_wait(&GC_restart_ack_sem)))
 
490
            if (errno != EINTR) {
 
491
                GC_err_printf1("sem_wait() returned %ld\n", (unsigned long)code);
 
492
                ABORT("sem_wait() for restart handler failed");
 
493
            }
 
494
#endif
449
495
    #if DEBUG_THREADS
450
496
      GC_printf0("World started\n");
451
497
    #endif
456
502
    
457
503
    if (sem_init(&GC_suspend_ack_sem, 0, 0) != 0)
458
504
        ABORT("sem_init failed");
 
505
#ifdef GC_NETBSD_THREADS_WORKAROUND
 
506
    if (sem_init(&GC_restart_ack_sem, 0, 0) != 0)
 
507
        ABORT("sem_init failed");
 
508
#endif
459
509
 
460
510
    act.sa_flags = SA_RESTART;
461
511
    if (sigfillset(&act.sa_mask) != 0) {