|
|
When a process receives a signal of some type (for example, SIGINT type) the process can either take the default response, ignore the signal (the kernel does not actually deliver the signal), or catch the signal. When the signal is caught, the system will call a handler function when the signal is delivered. This response is called the ``disposition'' for the signal type. In SVR4.2MP and UnixWare 2.0, that disposition is common to all of the threads of a process.
If the disposition for a signal type is
Moreover, if any thread changes the disposition (say by calling sigaction(2)) the new disposition is in effect for all threads.
On the other hand, ``signal masks'' (the set of signal types being blocked) are maintained per thread. Signal masking for threads behaves identically to the traditional signal masking for processes. If the disposition for a particular signal type is not ``ignore'' and the signal is not masked for a thread targeted to receive that signal, the signal will be delivered and the appropriate action will be taken by the thread. If the disposition is not ``ignore'' but the signal is masked by a thread targeted to receive that signal, the signal will be made ``pending'' for the thread; this means that the thread will not take the appropriate action until it unmasks that signal. If the disposition of the signal is ``ignore,'' the signal is neither made pending nor delivered, regardless of the thread's signal mask.
A thread inherits the signal mask of its creating thread. A thread can alter its mask with the thr_sigsetmask(3thread) routine.
int thr_sigsetmask( int how, const sigset_t *set, sigset_t *oset );
Signals can be categorized as being asynchronously generated or synchronously generated. A ``synchronously-generated signal'' is one that arises from the action of a particular thread or process. For example, alarm signals, signals resulting from an illegal memory reference, and signals resulting from an illegal arithmetic operation are all synchronously-generated signals. An ``asynchronously-generated'' signal is one that is sent from outside the thread (or process); its delivery is unpredictable. Interruptions and termination signals are usually an asynchronously generated.
When a signal is delivered to a process, if it is being caught, it will be handled by one, and only one, of the threads meeting either of the following conditions:
One useful paradigm for managing signals originating outside of the process is to have all threads include the caught signals in their signal mask and specifically create one daemon thread to handle the signals. If that thread uses the sigwait(2) system call, the signals can be handled in a synchronous style.
thr_sigsetmask(mask); while( (signo = sigwait(mask)) > 0){ handle signal type signo }
Note that it is not only valid to wait for masked signals with sigwait, but it is important to mask out the signal types of interest before calling sigwait. Otherwise, the arrival of one such signal between calls to sigwait will be handled according to the current process disposition. By default, that will terminate the entire process. sigwait effectively unmasks any masked signals while blocked, then masks them again before returning.
Even if a handler function is specified, it will not be executed if a signal is delivered to a thread blocked in sigwait; sigwait bypasses any handler.
Since all threads are masking out the same set of signals, one can predict that the signals in that set will be handled by the single thread using sigwait. This paradigm is advantageous because:
A caught, non-masked signal that is caused by a particular thread will be handled by that thread. Examples include:
The Threads Library arranges for such signals to always be delivered to the requesting thread even if that (``multiplexed'') thread is no longer held by the same LWP as at the time of the request.
Each thread will use the common handler function.
One thread can signal another thread with the thr_kill(3thread) function:
int thr_kill( thread_t tid, int signo );where
A thread catching a signal cannot distinguish between a signal originating from another thread of the process or from outside of the process.
The process disposition for the sent signal type (signo) is also applied for thread-to-thread signaling. As usual, the response will be to ignore the signal, to call the handler function, or to take the default response (usually, process termination).
This facility allows one thread to influence (perhaps ``reset'' or terminate) another thread asynchronously.