Examine and/or specify actions for signals
#include <sys/neutrino.h> int SignalAction( pid_t pid, void ( * sigstub)(), int signo, const struct sigaction * act, struct sigaction * oact ); int SignalAction_r( pid_t pid, void * (sigstub)(), int signo, const struct sigaction * act, struct sigaction * oact );
Use the -l c option to qcc to link against this library. This library is usually included automatically.
The SignalAction() and SignalAction_r() kernel calls let the calling process examine or specify (or both) the action to be associated with a specific signal in the process pid. If pid is zero, the calling process is used. The argument signo specifies the signal.
|You should call the POSIX sigaction() function or the ANSI signal() function instead of using these kernel calls directly.|
These functions are identical except in the way they indicate errors. See the Returns section for details.
The signals are defined in <signal.h>, and so are these global variables:
There are 32 POSIX 1003.1a signals, including:
One possible cause for this signal is trying to perform an operation that requires I/O privileges. A thread can request these privileges by calling ThreadCtl(), specifying the _NTO_TCTL_IO flag:
ThreadCtl( _NTO_TCTL_IO, 0 );
|You can't ignore or catch SIGCONT, SIGKILL, or SIGSTOP.|
There are 16 POSIX 1003.1b realtime signals, including:
The entire range of signals goes from _SIGMIN (1) to _SIGMAX (64).
QNX Neutrino uses the top eight signals for special purposes. They're always masked, and attempts to unmask them are ignored. They include two named signals (SIGSELECT and SIGPHOTON) and six unnamed ones.
If act isn't NULL, then the specified signal is modified. If oact isn't NULL, the previous action is stored in the structure it points to. You can use various combinations of act and oact to query or set (or both) the action for a signal.
The structure sigaction contains the following members:
The sa_handler and sa_sigaction members of act are implemented as a union, and share common storage. They differ only in their prototype, with sa_handler being used for POSIX 1003.1a signals, and sa_sigaction being used for POSIX 1003.1b queued realtime signals. The values stored using either name can be one of:
The function member of sa_handler or sa_sigaction is always invoked with the following arguments:
void handler(int signo, siginfo_t* info, void* other)
If you have an old-style signal handler of the form:
void handler(int signo)
the microkernel passes the extra arguments, but the function simply ignores them.
While in the handler, signo is masked, preventing nested signals of the same type. In addition, any signals set in the sa_mask member of act are also ORed into the mask. When the handler returns through a normal return, the previous mask is restored, and any pending and now unmasked signals are acted on. You return to the point in the program where it was interrupted. If the thread was blocked in the kernel when the interruption occurred, the kernel call returns with an EINTR (see ChannelCreate() and SyncMutexLock() for exceptions to this).
|It isn't safe to use floating-point operations in signal handlers.|
When you specify a handler, you must provide the address of a signal stub handler for sigstub. This is a small piece of code in the user's space that interfaces the user's signal handler to the kernel. The library provides a standard one, __signalstub().
The siginfo_t structure of the function in sa_handler or sa_sigaction contains at least the following members:
Signal handlers and actions are defined for the process and affect all threads in the process. For example, if one thread ignores a signal, then all threads ignore the signal.
You can target a signal at a thread, process or process group (see SignalKill()). When targeted at a process, at most one thread receives the signal. This thread must have the signal unblocked (see SignalProcmask()) to be a candidate for receiving it. All synchronously generated signals (e.g. SIGSEGV) are always delivered to the thread that caused them.
In a multithreaded process, if a signal terminates a thread, by default all threads and thus the process are terminated. You can override this standard POSIX behavior when you create the thread; see ThreadCreate().
|If you use longjmp() to return from a signal handler, the signal remains masked. You can use siglongjmp() to restore the mask to the state saved by a previous call to sigsetjmp().|
These calls don't block.
The only difference between these functions is the way they indicate errors:
abort(), ChannelCreate(), kill(), longjmp(), siglongjmp(), signal(), sigaction(), SignalKill(), SignalProcmask(), sigqueue(), sigsetjmp(), SyncMutexLock(), ThreadCreate(), wait(), waitpid()