~ubuntu-branches/ubuntu/quantal/libgc/quantal

« back to all changes in this revision

Viewing changes to pthread_stop_world.c

  • Committer: Bazaar Package Importer
  • Author(s): Christoph Egger
  • Date: 2011-02-19 12:19:56 UTC
  • mfrom: (1.3.2 upstream) (0.1.5 experimental)
  • mto: This revision was merged to the branch mainline in revision 14.
  • Revision ID: james.westby@ubuntu.com-20110219121956-67rb69xlt5nud3v2
Tags: 1:7.1-5
Upload to unstable

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#include "private/pthread_support.h"
2
2
 
3
 
#if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
4
 
     && !defined(GC_WIN32_THREADS) && !defined(GC_DARWIN_THREADS)
 
3
#if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS) && \
 
4
    !defined(GC_DARWIN_THREADS)
5
5
 
6
6
#include <signal.h>
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
#include "atomic_ops.h"
15
11
 
16
12
#if DEBUG_THREADS
17
13
 
34
30
 
35
31
    if (pthread_sigmask(SIG_BLOCK, NULL, &blocked) != 0)
36
32
        ABORT("pthread_sigmask");
37
 
    GC_printf0("Blocked: ");
 
33
    GC_printf("Blocked: ");
38
34
    for (i = 1; i < NSIG; i++) {
39
 
        if (sigismember(&blocked, i)) { GC_printf1("%ld ",(long) i); }
 
35
        if (sigismember(&blocked, i)) { GC_printf("%d ", i); }
40
36
    }
41
 
    GC_printf0("\n");
 
37
    GC_printf("\n");
42
38
}
43
39
 
44
40
#endif
47
43
/* handler from a set.                                          */
48
44
void GC_remove_allowed_signals(sigset_t *set)
49
45
{
50
 
#   ifdef NO_SIGNALS
51
 
      if (sigdelset(set, SIGINT) != 0
 
46
    if (sigdelset(set, SIGINT) != 0
52
47
          || sigdelset(set, SIGQUIT) != 0
53
48
          || sigdelset(set, SIGABRT) != 0
54
49
          || sigdelset(set, SIGTERM) != 0) {
55
50
        ABORT("sigdelset() failed");
56
 
      }
57
 
#   endif
 
51
    }
58
52
 
59
53
#   ifdef MPROTECT_VDB
60
54
      /* Handlers write to the thread structure, which is in the heap,  */
71
65
 
72
66
static sigset_t suspend_handler_mask;
73
67
 
74
 
volatile sig_atomic_t GC_stop_count;
 
68
volatile AO_t GC_stop_count;
75
69
                        /* Incremented at the beginning of GC_stop_world. */
76
70
 
77
 
volatile sig_atomic_t GC_world_is_stopped = FALSE;
 
71
volatile AO_t GC_world_is_stopped = FALSE;
78
72
                        /* FALSE ==> it is safe for threads to restart, i.e. */
79
73
                        /* they will see another suspend signal before they  */
80
74
                        /* are expected to stop (unless they have voluntarily */
81
75
                        /* stopped).                                         */
82
76
 
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
77
#ifdef GC_OSF1_THREADS
92
78
  GC_bool GC_retry_signals = TRUE;
93
79
#else
127
113
  sem_t GC_restart_ack_sem;
128
114
#endif
129
115
 
130
 
void GC_suspend_handler_inner(ptr_t sig_arg);
 
116
void GC_suspend_handler_inner(ptr_t sig_arg, void *context);
131
117
 
132
118
#if defined(IA64) || defined(HP_PA) || defined(M68K)
133
 
extern void GC_with_callee_saves_pushed();
134
 
 
 
119
#ifdef SA_SIGINFO
 
120
void GC_suspend_handler(int sig, siginfo_t *info, void *context)
 
121
#else
135
122
void GC_suspend_handler(int sig)
 
123
#endif
136
124
{
137
125
  int old_errno = errno;
138
126
  GC_with_callee_saves_pushed(GC_suspend_handler_inner, (ptr_t)(word)sig);
139
127
  errno = old_errno;
140
128
}
141
 
 
142
129
#else
143
130
/* We believe that in all other cases the full context is already       */
144
131
/* in the signal handler frame.                                         */
 
132
#ifdef SA_SIGINFO
 
133
void GC_suspend_handler(int sig, siginfo_t *info, void *context)
 
134
#else
145
135
void GC_suspend_handler(int sig)
 
136
#endif
146
137
{
147
138
  int old_errno = errno;
148
 
  GC_suspend_handler_inner((ptr_t)(word)sig);
 
139
# ifndef SA_SIGINFO
 
140
    void *context = 0;
 
141
# endif
 
142
  GC_suspend_handler_inner((ptr_t)(word)sig, context);
149
143
  errno = old_errno;
150
144
}
151
145
#endif
152
146
 
153
 
void GC_suspend_handler_inner(ptr_t sig_arg)
 
147
void GC_suspend_handler_inner(ptr_t sig_arg, void *context)
154
148
{
155
149
    int sig = (int)(word)sig_arg;
156
150
    int dummy;
162
156
        /* guaranteed to be the mark_no correspending to our            */
163
157
        /* suspension, i.e. the marker can't have incremented it yet.   */
164
158
#   endif
165
 
    word my_stop_count = GC_stop_count;
 
159
    AO_t my_stop_count = AO_load(&GC_stop_count);
166
160
 
167
161
    if (sig != SIG_SUSPEND) ABORT("Bad signal in suspend_handler");
168
162
 
169
 
#if DEBUG_THREADS
170
 
    GC_printf1("Suspending 0x%lx\n", my_thread);
171
 
#endif
 
163
#   if DEBUG_THREADS
 
164
      GC_printf("Suspending 0x%x\n", (unsigned)my_thread);
 
165
#   endif
172
166
 
173
167
    me = GC_lookup_thread(my_thread);
174
168
    /* The lookup here is safe, since I'm doing this on behalf  */
184
178
        return;
185
179
    }
186
180
#   ifdef SPARC
187
 
        me -> stop_info.stack_ptr = (ptr_t)GC_save_regs_in_stack();
 
181
        me -> stop_info.stack_ptr = GC_save_regs_in_stack();
188
182
#   else
189
183
        me -> stop_info.stack_ptr = (ptr_t)(&dummy);
190
184
#   endif
191
185
#   ifdef IA64
192
 
        me -> backing_store_ptr = (ptr_t)GC_save_regs_in_stack();
 
186
        me -> backing_store_ptr = GC_save_regs_in_stack();
193
187
#   endif
194
188
 
195
189
    /* Tell the thread that wants to stop the world that this   */
209
203
    /* primitive and expensive mechanism to wait until it's     */
210
204
    /* really safe to proceed.  Under normal circumstances,     */
211
205
    /* 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
 
    }
 
206
    do {
 
207
        sigsuspend (&suspend_handler_mask);
 
208
    } while (AO_load_acquire(&GC_world_is_stopped)
 
209
             && AO_load(&GC_stop_count) == my_stop_count);
219
210
    /* If the RESTART signal gets lost, we can still lose.  That should be  */
220
211
    /* less likely than losing the SUSPEND signal, since we don't do much   */
221
212
    /* between the sem_post and sigsuspend.                                 */
223
214
    /* Simply dropping the sigsuspend call should be safe, but is unlikely  */
224
215
    /* to be efficient.                                                     */
225
216
 
226
 
#if DEBUG_THREADS
227
 
    GC_printf1("Continuing 0x%lx\n", my_thread);
228
 
#endif
 
217
#   if DEBUG_THREADS
 
218
      GC_printf("Continuing 0x%x\n", (unsigned)my_thread);
 
219
#   endif
229
220
}
230
221
 
231
222
void GC_restart_handler(int sig)
232
223
{
233
224
    pthread_t my_thread = pthread_self();
 
225
    GC_thread me;
234
226
 
235
227
    if (sig != SIG_THR_RESTART) ABORT("Bad signal in suspend_handler");
236
228
 
237
 
#ifdef GC_NETBSD_THREADS_WORKAROUND
238
 
    sem_post(&GC_restart_ack_sem);
239
 
#endif
 
229
#   ifdef GC_NETBSD_THREADS_WORKAROUND
 
230
      sem_post(&GC_restart_ack_sem);
 
231
#   endif
240
232
 
241
233
    /*
242
234
    ** Note: even if we don't do anything useful here,
246
238
    ** will thus not interrupt the sigsuspend() above.
247
239
    */
248
240
 
249
 
#if DEBUG_THREADS
250
 
    GC_printf1("In GC_restart_handler for 0x%lx\n", pthread_self());
251
 
#endif
 
241
#   if DEBUG_THREADS
 
242
      GC_printf("In GC_restart_handler for 0x%x\n", (unsigned)pthread_self());
 
243
#   endif
252
244
}
253
245
 
254
246
# ifdef IA64
261
253
void GC_push_all_stacks()
262
254
{
263
255
    GC_bool found_me = FALSE;
 
256
    size_t nthreads = 0;
264
257
    int i;
265
258
    GC_thread p;
266
259
    ptr_t lo, hi;
269
262
    pthread_t me = pthread_self();
270
263
    
271
264
    if (!GC_thr_initialized) GC_thr_init();
272
 
    #if DEBUG_THREADS
273
 
        GC_printf1("Pushing stacks from thread 0x%lx\n", (unsigned long) me);
274
 
    #endif
 
265
#   if DEBUG_THREADS
 
266
        GC_printf("Pushing stacks from thread 0x%x\n", (unsigned) me);
 
267
#   endif
275
268
    for (i = 0; i < THREAD_TABLE_SZ; i++) {
276
269
      for (p = GC_threads[i]; p != 0; p = p -> next) {
277
270
        if (p -> flags & FINISHED) continue;
278
 
        if (pthread_equal(p -> id, me)) {
 
271
        ++nthreads;
 
272
        if (THREAD_EQUAL(p -> id, me)) {
279
273
#           ifdef SPARC
280
274
                lo = (ptr_t)GC_save_regs_in_stack();
281
275
#           else
295
289
            hi = GC_stackbottom;
296
290
            IF_IA64(bs_lo = BACKING_STORE_BASE;)
297
291
        }
298
 
        #if DEBUG_THREADS
299
 
            GC_printf3("Stack for thread 0x%lx = [%lx,%lx)\n",
300
 
                (unsigned long) p -> id,
301
 
                (unsigned long) lo, (unsigned long) hi);
302
 
        #endif
 
292
#       if DEBUG_THREADS
 
293
            GC_printf("Stack for thread 0x%x = [%p,%p)\n",
 
294
                      (unsigned)(p -> id), lo, hi);
 
295
#       endif
303
296
        if (0 == lo) ABORT("GC_push_all_stacks: sp not set!\n");
304
297
#       ifdef STACK_GROWS_UP
305
298
          /* We got them backwards! */
309
302
#       endif
310
303
#       ifdef IA64
311
304
#         if DEBUG_THREADS
312
 
            GC_printf3("Reg stack for thread 0x%lx = [%lx,%lx)\n",
313
 
                (unsigned long) p -> id,
314
 
                (unsigned long) bs_lo, (unsigned long) bs_hi);
 
305
            GC_printf("Reg stack for thread 0x%x = [%lx,%lx)\n",
 
306
                      (unsigned)p -> id, bs_lo, bs_hi);
315
307
#         endif
316
 
          if (pthread_equal(p -> id, me)) {
 
308
          if (THREAD_EQUAL(p -> id, me)) {
317
309
            /* FIXME:  This may add an unbounded number of entries,     */
318
310
            /* and hence overflow the mark stack, which is bad.         */
319
311
            GC_push_all_eager(bs_lo, bs_hi);
323
315
#       endif
324
316
      }
325
317
    }
 
318
    if (GC_print_stats == VERBOSE) {
 
319
        GC_log_printf("Pushed %d thread stacks\n", nthreads);
 
320
    }
326
321
    if (!found_me && !GC_in_thread_creation)
327
322
      ABORT("Collecting from unknown thread.");
328
323
}
347
342
    GC_stopping_pid = getpid();                /* debugging only.      */
348
343
    for (i = 0; i < THREAD_TABLE_SZ; i++) {
349
344
      for (p = GC_threads[i]; p != 0; p = p -> next) {
350
 
        if (p -> id != my_thread) {
 
345
        if (!THREAD_EQUAL(p -> id, my_thread)) {
351
346
            if (p -> flags & FINISHED) continue;
352
347
            if (p -> stop_info.last_stop_count == GC_stop_count) continue;
353
348
            if (p -> thread_blocked) /* Will wait */ continue;
354
349
            n_live_threads++;
355
 
            #if DEBUG_THREADS
356
 
              GC_printf1("Sending suspend signal to 0x%lx\n", p -> id);
357
 
            #endif
 
350
#           if DEBUG_THREADS
 
351
              GC_printf("Sending suspend signal to 0x%x\n",
 
352
                        (unsigned)(p -> id));
 
353
#           endif
358
354
        
359
 
        result = pthread_kill(p -> id, SIG_SUSPEND);
 
355
            result = pthread_kill(p -> id, SIG_SUSPEND);
360
356
            switch(result) {
361
357
                case ESRCH:
362
358
                    /* Not really there anymore.  Possible? */
373
369
    return n_live_threads;
374
370
}
375
371
 
376
 
/* Caller holds allocation lock.        */
377
372
void GC_stop_world()
378
373
{
379
374
    int i;
380
375
    int n_live_threads;
381
376
    int code;
382
377
 
383
 
    #if DEBUG_THREADS
384
 
    GC_printf1("Stopping the world from 0x%lx\n", pthread_self());
385
 
    #endif
 
378
    GC_ASSERT(I_HOLD_LOCK());
 
379
#   if DEBUG_THREADS
 
380
      GC_printf("Stopping the world from 0x%x\n", (unsigned)pthread_self());
 
381
#   endif
386
382
       
387
383
    /* Make sure all free list construction has stopped before we start. */
388
384
    /* No new construction can start, since free list construction is   */
393
389
      GC_ASSERT(GC_fl_builder_count == 0);
394
390
      /* We should have previously waited for it to become zero. */
395
391
#   endif /* PARALLEL_MARK */
396
 
    ++GC_stop_count;
397
 
    GC_world_is_stopped = TRUE;
 
392
    AO_store(&GC_stop_count, GC_stop_count+1);
 
393
        /* Only concurrent reads are possible. */
 
394
    AO_store_release(&GC_world_is_stopped, TRUE);
398
395
    n_live_threads = GC_suspend_all();
399
396
 
400
397
      if (GC_retry_signals) {
409
406
              if (wait_usecs > RETRY_INTERVAL) {
410
407
                  int newly_sent = GC_suspend_all();
411
408
 
412
 
#                 ifdef CONDPRINT
413
 
                    if (GC_print_stats) {
414
 
                      GC_printf1("Resent %ld signals after timeout\n",
415
 
                                 newly_sent);
416
 
                    }
417
 
#                 endif
 
409
                  if (GC_print_stats) {
 
410
                      GC_log_printf("Resent %d signals after timeout\n",
 
411
                                newly_sent);
 
412
                  }
418
413
                  sem_getvalue(&GC_suspend_ack_sem, &ack_count);
419
414
                  if (newly_sent < n_live_threads - ack_count) {
420
415
                      WARN("Lost some threads during GC_stop_world?!\n",0);
427
422
          }
428
423
      }
429
424
    for (i = 0; i < n_live_threads; i++) {
430
 
          while (0 != (code = sem_wait(&GC_suspend_ack_sem))) {
431
 
              if (errno != EINTR) {
432
 
                 GC_err_printf1("Sem_wait returned %ld\n", (unsigned long)code);
433
 
                 ABORT("sem_wait for handler failed");
 
425
        retry:
 
426
          if (0 != (code = sem_wait(&GC_suspend_ack_sem))) {
 
427
              /* On Linux, sem_wait is documented to always return zero.*/
 
428
              /* But the documentation appears to be incorrect.         */
 
429
              if (errno == EINTR) {
 
430
                /* Seems to happen with some versions of gdb.   */
 
431
                goto retry;
434
432
              }
 
433
              ABORT("sem_wait for handler failed");
435
434
          }
436
435
    }
437
436
#   ifdef PARALLEL_MARK
438
437
      GC_release_mark_lock();
439
438
#   endif
440
439
    #if DEBUG_THREADS
441
 
      GC_printf1("World stopped from 0x%lx\n", pthread_self());
 
440
      GC_printf("World stopped from 0x%x\n", (unsigned)pthread_self());
442
441
    #endif
443
442
    GC_stopping_thread = 0;  /* debugging only */
444
443
}
452
451
    register GC_thread p;
453
452
    register int n_live_threads = 0;
454
453
    register int result;
455
 
#ifdef GC_NETBSD_THREADS_WORKAROUND
456
 
    int code;
457
 
#endif
 
454
#   ifdef GC_NETBSD_THREADS_WORKAROUND
 
455
      int code;
 
456
#   endif
458
457
 
459
458
#   if DEBUG_THREADS
460
 
      GC_printf0("World starting\n");
 
459
      GC_printf("World starting\n");
461
460
#   endif
462
461
 
463
 
    GC_world_is_stopped = FALSE;
 
462
    AO_store(&GC_world_is_stopped, FALSE);
464
463
    for (i = 0; i < THREAD_TABLE_SZ; i++) {
465
464
      for (p = GC_threads[i]; p != 0; p = p -> next) {
466
 
        if (p -> id != my_thread) {
 
465
        if (!THREAD_EQUAL(p -> id, my_thread)) {
467
466
            if (p -> flags & FINISHED) continue;
468
467
            if (p -> thread_blocked) continue;
469
468
            n_live_threads++;
470
469
            #if DEBUG_THREADS
471
 
              GC_printf1("Sending restart signal to 0x%lx\n", p -> id);
 
470
              GC_printf("Sending restart signal to 0x%x\n",
 
471
                        (unsigned)(p -> id));
472
472
            #endif
 
473
        
473
474
            result = pthread_kill(p -> id, SIG_THR_RESTART);
474
475
            switch(result) {
475
476
                case ESRCH:
484
485
        }
485
486
      }
486
487
    }
487
 
#ifdef GC_NETBSD_THREADS_WORKAROUND
488
 
    for (i = 0; i < n_live_threads; i++)
 
488
#   ifdef GC_NETBSD_THREADS_WORKAROUND
 
489
      for (i = 0; i < n_live_threads; i++)
489
490
        while (0 != (code = sem_wait(&GC_restart_ack_sem)))
490
491
            if (errno != EINTR) {
491
 
                GC_err_printf1("sem_wait() returned %ld\n", (unsigned long)code);
 
492
                GC_err_printf("sem_wait() returned %d\n",
 
493
                               code);
492
494
                ABORT("sem_wait() for restart handler failed");
493
495
            }
494
 
#endif
495
 
    #if DEBUG_THREADS
496
 
      GC_printf0("World started\n");
497
 
    #endif
 
496
#    endif
 
497
#    if DEBUG_THREADS
 
498
      GC_printf("World started\n");
 
499
#    endif
498
500
}
499
501
 
500
502
void GC_stop_init() {
502
504
    
503
505
    if (sem_init(&GC_suspend_ack_sem, 0, 0) != 0)
504
506
        ABORT("sem_init failed");
505
 
#ifdef GC_NETBSD_THREADS_WORKAROUND
506
 
    if (sem_init(&GC_restart_ack_sem, 0, 0) != 0)
 
507
#   ifdef GC_NETBSD_THREADS_WORKAROUND
 
508
      if (sem_init(&GC_restart_ack_sem, 0, 0) != 0)
507
509
        ABORT("sem_init failed");
508
 
#endif
 
510
#   endif
509
511
 
510
 
    act.sa_flags = SA_RESTART;
 
512
    act.sa_flags = SA_RESTART
 
513
#   ifdef SA_SIGINFO
 
514
        | SA_SIGINFO
 
515
#   endif
 
516
        ;
511
517
    if (sigfillset(&act.sa_mask) != 0) {
512
518
        ABORT("sigfillset() failed");
513
519
    }
514
520
    GC_remove_allowed_signals(&act.sa_mask);
515
521
    /* SIG_THR_RESTART is set in the resulting mask.            */
516
522
    /* It is unmasked by the handler when necessary.            */
 
523
#   ifdef SA_SIGINFO
 
524
    act.sa_sigaction = GC_suspend_handler;
 
525
#   else
517
526
    act.sa_handler = GC_suspend_handler;
 
527
#   endif
518
528
    if (sigaction(SIG_SUSPEND, &act, NULL) != 0) {
519
529
        ABORT("Cannot set SIG_SUSPEND handler");
520
530
    }
521
531
 
 
532
#   ifdef SA_SIGINFO
 
533
    act.sa_flags &= ~ SA_SIGINFO;
 
534
#   endif
522
535
    act.sa_handler = GC_restart_handler;
523
536
    if (sigaction(SIG_THR_RESTART, &act, NULL) != 0) {
524
537
        ABORT("Cannot set SIG_THR_RESTART handler");
537
550
      if (0 != GETENV("GC_NO_RETRY_SIGNALS")) {
538
551
          GC_retry_signals = FALSE;
539
552
      }
540
 
#     ifdef CONDPRINT
541
 
          if (GC_print_stats && GC_retry_signals) {
542
 
              GC_printf0("Will retry suspend signal if necessary.\n");
543
 
          }
544
 
#     endif
 
553
      if (GC_print_stats && GC_retry_signals) {
 
554
          GC_log_printf("Will retry suspend signal if necessary.\n");
 
555
      }
545
556
}
546
557
 
547
558
#endif