Date: Thu, 10 Jun 2004 22:21:17 -0700 From: Sean McNeil <sean@mcneil.com> To: David Xu <davidxu@freebsd.org> Cc: freebsd-threads@freebsd.org Subject: Re: signal handler priority issue Message-ID: <1086931276.38487.35.camel@server.mcneil.com> In-Reply-To: <40C93D60.3040003@freebsd.org> References: <1086924733.65671.81.camel@server.mcneil.com> <40C93D60.3040003@freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
On Thu, 2004-06-10 at 22:04, David Xu wrote: > Can you provide some code to demostrate the problem ? I have interest. > > David Xu Yes, here is some code snippets from boehm-gc: master thread doing: 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 (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_printf1("Sending suspend signal to 0x%lx\n", 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; } and slave threads doing: void GC_suspend_handler(int sig) { int dummy; pthread_t my_thread = pthread_self(); GC_thread me; sigset_t mask; # ifdef PARALLEL_MARK word my_mark_no = GC_mark_no; /* Marker can't proceed until we acknowledge. Thus this is */ /* guaranteed to be the mark_no correspending to our */ /* suspension, i.e. the marker can't have incremented it yet. */ # endif word my_stop_count = GC_stop_count; if (sig != SIG_SUSPEND) ABORT("Bad signal in suspend_handler"); #if DEBUG_THREADS GC_printf1("Suspending 0x%lx\n", my_thread); #endif me = GC_lookup_thread(my_thread); /* 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. */ if (me -> stop_info.last_stop_count == my_stop_count) { /* Duplicate signal. OK if we are retrying. */ if (!GC_retry_signals) { WARN("Duplicate suspend signal in thread %lx\n", pthread_self()); } return; } # ifdef SPARC me -> stop_info.stack_ptr = (ptr_t)GC_save_regs_in_stack(); # else me -> stop_info.stack_ptr = (ptr_t)(&dummy); # endif # ifdef IA64 me -> backing_store_ptr = (ptr_t)GC_save_regs_in_stack(); # endif /* Tell the thread that wants to stop the world that this */ /* thread has been stopped. Note that sem_post() is */ /* the only async-signal-safe primitive in LinuxThreads. */ sem_post(&GC_suspend_ack_sem); me -> stop_info.last_stop_count = my_stop_count; #if DEBUG_THREADS GC_printf2("Waiting for restart #%d of 0x%lx\n", my_stop_count, my_thread); #endif /* Wait until that thread tells us to restart by sending */ /* this thread a SIG_THR_RESTART signal. */ /* SIG_THR_RESTART should be masked at this point. Thus there */ /* is no race. */ if (sigfillset(&mask) != 0) ABORT("sigfillset() failed"); if (sigdelset(&mask, SIG_THR_RESTART) != 0) ABORT("sigdelset() failed"); # ifdef NO_SIGNALS if (sigdelset(&mask, SIGINT) != 0) ABORT("sigdelset() failed"); if (sigdelset(&mask, SIGQUIT) != 0) ABORT("sigdelset() failed"); if (sigdelset(&mask, SIGTERM) != 0) ABORT("sigdelset() failed"); if (sigdelset(&mask, SIGABRT) != 0) ABORT("sigdelset() failed"); # endif do { me->stop_info.signal = 0; sigsuspend(&mask); /* Wait for signal */ } while (me->stop_info.signal != SIG_THR_RESTART); /* If the RESTART signal gets lost, we can still lose. That should be */ /* less likely than losing the SUSPEND signal, since we don't do much */ /* between the sem_post and sigsuspend. */ /* We'd need more handshaking to work around that, since we don't want */ /* to accidentally leave a RESTART signal pending, thus causing us to */ /* continue prematurely in a future round. */ #if DEBUG_THREADS GC_printf1("Continuing 0x%lx\n", my_thread); #endif } and here is the output with debug messages: Stopping the world from 0x50d000 Sending suspend signal to 0x9d1400 Suspending 0x9d1400 World stopped from 0x50d000 Pushing stacks from thread 0x50d000 Stack for thread 0x9d1400 = [7fffffeed95c,7fffffeee000) Stack for thread 0x50d000 = [7fffffffcf00,800000000000) World starting Sending restart signal to 0x9d1400 World started Buildfile: build.xml Stopping the world from 0x50d000 Sending suspend signal to 0x9d1400 Waiting for restart #2 of 0x9d1400 There are other things causing output, but you can see that the slave isn't getting to the sigsuspend before it is evoked again from the master thread.
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?1086931276.38487.35.camel>