Subject: Re: Sempahore on NetBSD work or no ?
To: Nathan J. Williams <email@example.com>
From: Zoltan ZSIDO <firstname.lastname@example.org>
Date: 01/28/2003 18:36:42
First of all, signal handling and multi threrading used together is a
nightmare. Developing Posix thread based applications for different
platforms is a long toy. Applications can behave differently compiled on
different platforms, however they comply to the Posix 1003.1c standard.
The Solaris signal(3HEAD) manpage has a little explanation about signals,
which can be helpful to understand the interaction of threads and signals
(it talks about its thr_xxx() function calls, but it is the same for
Signals can be generated synchronously or asynchronously.
Events directly caused by the execution of code by a thread,
such as a reference to an unmapped, protected, or bad memory
can generate SIGSEGV or SIGBUS; a floating point exception
can generate SIGFPE; and the execution of an illegal
instruction can generate SIGILL. Such events are referred to
as traps; signals generated by traps are said to be synchro-
nously generated. Synchronously generated signals are ini-
tiated by a specific thread and are delivered to and handled
by that thread.
Signals may also be generated by calling kill(), sigqueue(),
or sigsend(). Events such as keyboard interrupts generate
signals, such as SIGINT, which are sent to the target pro-
cess. Such events are referred to as interrupts; signals
generated by interrupts are said to be asynchronously gen-
erated. Asynchronously generated signals are not directed to
a particular thread but are handled by an arbitrary thread
that meets either of the following conditions:
o The thread is blocked in a call to sigwait(2) whose
argument includes the type of signal generated.
o The thread has a signal mask that does not include the
type of signal generated. A process responds to sig-
nals in similar ways whether it is using threads or
it is using lightweight processes (LWPs). See
thr_create(3THR). Each process may specify a system
action to be taken in response to each signal sent to
it, called the signal's disposition. All threads or
LWPs in the process share the disposition. The set of
system signal actions for a process is initialized
from that of its parent. Once an action is installed
for a specific signal, it usually remains installed
until another disposition is explicitly requested by a
call to either sigaction(), signal() or sigset(), or
until the process execs(). See sigaction(2) and
signal(3C). When a process execs, all signals whose
disposition has been set to catch the signal will be
set to SIG_DFL. Alternatively, a process may request
that the system automatically reset the disposition of
a signal to SIG_DFL after it has been caught. See
sigaction(2) and signal(3C).
A signal is said to be delivered to a process when a thread
or LWP within the process takes the appropriate action for
the disposition of the signal. Delivery of a signal can be
blocked. There are two methods for handling delivery of a
signal in a multithreaded application. The first method
specifies a signal handler function to execute when the sig-
nal is received by the process. See sigaction(2). The second
method creates a thread to handle the receipt of the signal
sigaction() can be used for both synchronously and asynchro-
nously generated signals. sigwait() will only work for asyn-
chronously generated signals, as synchronously generated
signals are sent to the thread that caused the event.
sigwait() is the recommended interface for use with a mul-
tithreaded application. See sigwait(2).
If You try select(2) in a threaded application for example, it will cause
alarm(3) signal to be delivered on event to the issuer thread if it runs
on HP-UX or OSF/1, but will result different behaviour on Solaris. And of
course You can issue select(2) from each thread You created to make harder
Your life. Imagine, how reliably will work a select(2) based usecond
timer and a bare select(2) for normal fdesc handling....
(Strictly speaking Solaris is closer to the standard, the others are nicer
to the programmer, and needless to say all of them are compliant.)
On platforms having the M to N mapping feature (such as 4.x and up of
DEC's OSF/1 or ~2.5.1 and up of Solaris) gives us another level of
complexity of course.
AFAIK Dave Butenhof was the creator of DEC's multiplatform user level CMA
thread implementation (1003.4 compliant) sold by many OS vendor around
1990's and the later 1003.1 compliant DECthread implementation.
On 27 Jan 2003, Nathan J. Williams wrote:
> Date: 27 Jan 2003 13:49:32 -0500
> From: Nathan J. Williams <email@example.com>
> To: David Maxwell <firstname.lastname@example.org>
> Cc: Jason R Thorpe <email@example.com>,
> Daniel Dias Gonçalves <firstname.lastname@example.org>,
> email@example.com, firstname.lastname@example.org
> Subject: Re: Sempahore on NetBSD work or no ?
> David Maxwell <email@example.com> writes:
> > I was under the impression that POSIX did not require that a signal
> > (such as SIGCHLD) be delivered to the thread that it would have, had the
> > thread been a process instead (i.e. a thread which called fork()).
> That's correct, there is no such requirement. There are all sorts of
> difficulties with making that guarantee; for example, the thread may
> no longer exist, and it precludes applications that want to use
> separate threads for signal handling. What POSIX says is that a signal
> may be delivered to any thread that does not have the signal blocked
> in its per-thread signal mask. If the programmer wants to arrange to
> recieve SIGCHLD in one thread, that can be done by blocking SIGCHLD in
> all *other* threads. This requires knowledge and control of all of the
> threads, which is non-modular, but signals don't modularize well
> > In process space, the process that calls alarm(3) will get the SIGALRM.
> > In thread space, I thought POSIX said 'any thread can get the SIGALRM',
> > and the programmer has to deal with that.
> Any thread that doesn't have SIGALRM blocked.
> I'm going to steal some text from David Butenhof's excellent Pthreads
> book, describing the goals of the authors of the standard with respect
> to signals (from section 6.6):
> ``There were two primary conflicting goals:
> * First, "signals should be completely compatible with traditional
> UNIX". That means signal handlers and masks should remain
> associated with the process. That makes them virtually useless with
> multiple threads, which is as it should be since signals have
> complicated semantics that make it difficult for threads and
> signals to coexist peacefully. Tasks should be accomplished
> synchronously using threads rather than asynchrousnously using
> * Second, "signals should be completely compatible with traditional
> UNIX". This time, "compatible" means signal handlers and masks
> should be completely thread-private. Most existing UNIX code would
> then function essentially the same running within a thread as
> it had within a process. Code migration would be simplified.
> The problem is that the definitions of "compatible" were incompatible.''
> - Nathan