📄 pthread_stop_world.c
字号:
lo = p -> stop_info.stack_ptr; IF_IA64(bs_hi = p -> backing_store_ptr;) } if ((p -> flags & MAIN_THREAD) == 0) { hi = p -> stack_end; IF_IA64(bs_lo = p -> backing_store_end); } else { /* The original stack. */ hi = GC_stackbottom; IF_IA64(bs_lo = BACKING_STORE_BASE;) }# if DEBUG_THREADS GC_printf("Stack for thread 0x%x = [%p,%p)\n", (unsigned)(p -> id), lo, hi);# endif if (0 == lo) ABORT("GC_push_all_stacks: sp not set!\n");# ifdef STACK_GROWS_UP /* We got them backwards! */ GC_push_all_stack(hi, lo);# else GC_push_all_stack(lo, hi);# endif# ifdef IA64# if DEBUG_THREADS GC_printf("Reg stack for thread 0x%x = [%lx,%lx)\n", (unsigned)p -> id, bs_lo, bs_hi);# endif if (THREAD_EQUAL(p -> id, me)) { /* FIXME: This may add an unbounded number of entries, */ /* and hence overflow the mark stack, which is bad. */ GC_push_all_eager(bs_lo, bs_hi); } else { GC_push_all_stack(bs_lo, bs_hi); }# endif } } if (GC_print_stats == VERBOSE) { GC_log_printf("Pushed %d thread stacks\n", nthreads); } if (!found_me && !GC_in_thread_creation) ABORT("Collecting from unknown thread.");}/* There seems to be a very rare thread stopping problem. To help us *//* debug that, we save the ids of the stopping thread. */pthread_t GC_stopping_thread;int GC_stopping_pid;/* We hold the allocation lock. Suspend all threads that might *//* still be running. Return the number of suspend signals that *//* were sent. */int GC_suspend_all(){ int n_live_threads = 0; int i; GC_thread p; int result; pthread_t my_thread = pthread_self(); GC_stopping_thread = my_thread; /* debugging only. */ GC_stopping_pid = getpid(); /* debugging only. */ for (i = 0; i < THREAD_TABLE_SZ; i++) { for (p = GC_threads[i]; p != 0; p = p -> next) { if (!THREAD_EQUAL(p -> id, my_thread)) { if (p -> flags & FINISHED) continue; if (p -> stop_info.last_stop_count == GC_stop_count) continue; if (p -> thread_blocked) /* Will wait */ continue; n_live_threads++;# if DEBUG_THREADS GC_printf("Sending suspend signal to 0x%x\n", (unsigned)(p -> id));# endif result = pthread_kill(p -> id, SIG_SUSPEND); switch(result) { case ESRCH: /* Not really there anymore. Possible? */ n_live_threads--; break; case 0: break; default: ABORT("pthread_kill failed"); } } } } return n_live_threads;}void GC_stop_world(){ int i; int n_live_threads; int code; GC_ASSERT(I_HOLD_LOCK());# if DEBUG_THREADS GC_printf("Stopping the world from 0x%x\n", (unsigned)pthread_self());# endif /* Make sure all free list construction has stopped before we start. */ /* No new construction can start, since free list construction is */ /* required to acquire and release the GC lock before it starts, */ /* and we have the lock. */# ifdef PARALLEL_MARK GC_acquire_mark_lock(); GC_ASSERT(GC_fl_builder_count == 0); /* We should have previously waited for it to become zero. */# endif /* PARALLEL_MARK */ AO_store(&GC_stop_count, GC_stop_count+1); /* Only concurrent reads are possible. */ AO_store_release(&GC_world_is_stopped, TRUE); n_live_threads = GC_suspend_all(); if (GC_retry_signals) { unsigned long wait_usecs = 0; /* Total wait since retry. */# define WAIT_UNIT 3000# define RETRY_INTERVAL 100000 for (;;) { int ack_count; sem_getvalue(&GC_suspend_ack_sem, &ack_count); if (ack_count == n_live_threads) break; if (wait_usecs > RETRY_INTERVAL) { int newly_sent = GC_suspend_all(); if (GC_print_stats) { GC_log_printf("Resent %d signals after timeout\n", newly_sent); } sem_getvalue(&GC_suspend_ack_sem, &ack_count); if (newly_sent < n_live_threads - ack_count) { WARN("Lost some threads during GC_stop_world?!\n",0); n_live_threads = ack_count + newly_sent; } wait_usecs = 0; } usleep(WAIT_UNIT); wait_usecs += WAIT_UNIT; } } for (i = 0; i < n_live_threads; i++) { retry: if (0 != (code = sem_wait(&GC_suspend_ack_sem))) { /* On Linux, sem_wait is documented to always return zero.*/ /* But the documentation appears to be incorrect. */ if (errno == EINTR) { /* Seems to happen with some versions of gdb. */ goto retry; } ABORT("sem_wait for handler failed"); } }# ifdef PARALLEL_MARK GC_release_mark_lock();# endif #if DEBUG_THREADS GC_printf("World stopped from 0x%x\n", (unsigned)pthread_self()); #endif GC_stopping_thread = 0; /* debugging only */}/* Caller holds allocation lock, and has held it continuously since *//* the world stopped. */void GC_start_world(){ pthread_t my_thread = pthread_self(); register int i; register GC_thread p; register int n_live_threads = 0; register int result;# ifdef GC_NETBSD_THREADS_WORKAROUND int code;# endif# if DEBUG_THREADS GC_printf("World starting\n");# endif AO_store(&GC_world_is_stopped, FALSE); for (i = 0; i < THREAD_TABLE_SZ; i++) { for (p = GC_threads[i]; p != 0; p = p -> next) { if (!THREAD_EQUAL(p -> id, my_thread)) { if (p -> flags & FINISHED) continue; if (p -> thread_blocked) continue; n_live_threads++; #if DEBUG_THREADS GC_printf("Sending restart signal to 0x%x\n", (unsigned)(p -> id)); #endif result = pthread_kill(p -> id, SIG_THR_RESTART); switch(result) { case ESRCH: /* Not really there anymore. Possible? */ n_live_threads--; break; case 0: break; default: ABORT("pthread_kill failed"); } } } }# ifdef GC_NETBSD_THREADS_WORKAROUND for (i = 0; i < n_live_threads; i++) while (0 != (code = sem_wait(&GC_restart_ack_sem))) if (errno != EINTR) { GC_err_printf1("sem_wait() returned %ld\n", (unsigned long)code); ABORT("sem_wait() for restart handler failed"); }# endif# if DEBUG_THREADS GC_printf("World started\n");# endif}void GC_stop_init() { struct sigaction act; if (sem_init(&GC_suspend_ack_sem, 0, 0) != 0) ABORT("sem_init failed");# ifdef GC_NETBSD_THREADS_WORKAROUND if (sem_init(&GC_restart_ack_sem, 0, 0) != 0) ABORT("sem_init failed");# endif act.sa_flags = SA_RESTART | SA_SIGINFO; if (sigfillset(&act.sa_mask) != 0) { ABORT("sigfillset() failed"); } GC_remove_allowed_signals(&act.sa_mask); /* SIG_THR_RESTART is set in the resulting mask. */ /* It is unmasked by the handler when necessary. */ act.sa_sigaction = GC_suspend_handler; if (sigaction(SIG_SUSPEND, &act, NULL) != 0) { ABORT("Cannot set SIG_SUSPEND handler"); } act.sa_flags &= ~ SA_SIGINFO; act.sa_handler = GC_restart_handler; if (sigaction(SIG_THR_RESTART, &act, NULL) != 0) { ABORT("Cannot set SIG_THR_RESTART handler"); } /* Inititialize suspend_handler_mask. It excludes SIG_THR_RESTART. */ if (sigfillset(&suspend_handler_mask) != 0) ABORT("sigfillset() failed"); GC_remove_allowed_signals(&suspend_handler_mask); if (sigdelset(&suspend_handler_mask, SIG_THR_RESTART) != 0) ABORT("sigdelset() failed"); /* Check for GC_RETRY_SIGNALS. */ if (0 != GETENV("GC_RETRY_SIGNALS")) { GC_retry_signals = TRUE; } if (0 != GETENV("GC_NO_RETRY_SIGNALS")) { GC_retry_signals = FALSE; } if (GC_print_stats && GC_retry_signals) { GC_log_printf("Will retry suspend signal if necessary.\n"); }}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -