Subject: Re: Sempahore on NetBSD work or no ?
To: Nathan J. Williams <nathanw@wasabisystems.com>
From: Zoltan ZSIDO <zsido@westel900.net>
List: current-users
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
pthread_xxx() also):

     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).
  SIGNAL DELIVERY
     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.


Regards,
	Zoltan

ps:
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 <nathanw@wasabisystems.com>
> To: David Maxwell <david@vex.net>
> Cc: Jason R Thorpe <thorpej@wasabisystems.com>,
>      Daniel Dias Gonçalves <f22@proveritauna.com.br>,
>      current-users@netbsd.org, netbsd-help@netbsd.org
> Subject: Re: Sempahore on NetBSD work or no ?
>
> David Maxwell <david@vex.net> 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
> anyway.
>
> > 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
>    signals.
>  * 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
>