The realtime signals are similar to the original signals, in that they have
signal numbers and can be dealt with using the original signal functions
(such as kill()
). The realtime signals are those whose number
is between the two constants SIGRTMIN and SIGRTMAX, defined in signal.h
.
With the GNU C library, SIGRTMIN is actually a function call*, as the threading
library reserves some realtime signals for its own use.
The signals between SIGRTMIN and SIGRTMAX have no standard purpose and may be used by a program in any way that it sees fit. POSIX mandates at least 8 real time signals be available. On linux signal numbers between 32 and 63 are available, though as previously stated some (presently 2, historically 3, in the range 32 through 33 or 34) may be used by the GNU C library's threads support.
* Not sure if this is still true in 2023. The necessary signals might just be "always reserved".
** SIGRTMIN returns 34 on my current system. Not sure if three signals were ever really used; that may have been an error on my part.
Lower number signals are given priority over higher number signals. In Linux this is true across the range of all signals, which incidentally gives the regular signals higher priority than all real-time signals (POSIX says that priority of real-time versus ordinary signals is unspecified, and only the realtime signals have a specified priority relative to each other).
On Linux there is a system-wide limit to the number of queued signals. This is a potential source of denial-of-service attacks. However, there is a per-user resource limit to control the total number of pending signals that can be allocated to a single user.
struct sigaction
structure. It is:
void (*sa_sigaction)(int, siginfo_t *, void *);
A new flag, SA_SIGINFO
, is used (in the sa_flags
field) to
specify that the sa_sigaction
rather than the sa_handler
field specifies the signal handler.
The siginfo_t structure has at least the following members:
int si_signo; // the signal number int si_errno; // if non-zero, an errno value assosciated with this // signal, as defined inint si_code; // signal code
The si_code
field contains information on the source or cause
of the signal. For signals sent with kill()
, si_code
will be set to
SI_USER
.
A range of other values for si_code
are not documented here, see the sigaction man
page for relevant details.
The third argument to the new-style signal handler is a void
pointer referred to as context. It is actually a pointer to a ucontext_t
structure, as documented in the GNU libc manual, representing the execution context that was
interrupted by delivery of the signal; it is not typically needed or used.
The sigqueue()
function provides a means to queue a signal, and
provide additional signal data.
int sigqueue(pid_t pid, int signo, const union sigval value);
The union sigval
has the following members:
int sival_int; // a simple integer value void *sival_ptr; // a pointer
This union therefore allows either an integer or pointer value to be sent to
the designated process, via the specified signal. As with kill()
,
a signal number of 0 does not result in a signal being delivered but still
performs error checking, so that it can be used to verify if a process with
a given pid actually exists (and determine whether it is owned by the same
user).
According to POSIX, the function fails immediately (returning -1) if queueing the signal is not possible. On Linux (at least with GNU libc), only one instance of each of the non-realtime signals can be queued, but an error is not returned in case an already-pending non-realtime signal is sent; instead, the sent signal is silently discarded and no error is indicated. This does not appear to be POSIX-conformant behaviour.
Return is 0 if successful, -1 otherwise (but as noted above, Linux always returns success for
non-realtime signals). The following error conditions (stored in the errno
variable) apply:
EAGAIN
- the signal buffer is full, so the signal could not be queued
EACCESS
- the sending process does not have permission to send
a signal to the specified process
EINVAL
- the signal number is not valid
ESRCH
- the specified process does not exist
On reception of a real-time signal queued using sigqueue()
, an extended
signal handler will see the si_code
field of the siginfo_t
structure is set to SI_QUEUE, and the value
will be available
from a field called si_value
in the same structure. This is the
only condition under which si_code
can contain SI_QUEUE
.
The differences between kill()
and sigqueue()
are:
sigqueue()
can send extra information with the signal.sigqueue()
causes the handler (if established via sigaction()
with
SA_SIGINFO
flag set) to see an si_code
of SI_QUEUE
instead of SI_USER
.sigqueue()
fails with an error if the signal is a real-time
signal which cannot be queued due to the signal buffer being full (on Linux/Glibc it does
not return an error code if it fails to queue a non-realtime signal, which will be the case
if the same signal is already pending, although POSIX indicates that it should do so).kill()
guarantees that the signal will be received, though it may
be merged with an already pending signal. Note that kill()
allows sending
a signal even when the process- or system-wide signal buffer is full,
seeing as a signal without the extra data does not require a slot in the
buffer.kill()
allows sending a signal to the current process group (pid = 0),
all other processes (pid = -1), a process group id (pid = -pgid), or
a specific process. sigqueue()
only allows sending a signal to a
specific process.SA_SIGINFO
must be specified in the signal flags when the signal
handler is setup using sigaction()
, and the sigqueue()
function must be used
to send the signal. This is not the case on Linux; realtime signals are always queued if possible.kill()
and sigqueue()
can queue multiple realtime
signal instances. POSIX does not require that kill()
can do so.sigqueue()
and even via kill()
. Linux does not (and as noted
above, can return an incorrect result from sigqueue()
in case this is attempted).sigsuspend()
function provides no means to retrieve assosciated
extra data sent with a queued signal. The new sigwaitinfo()
function
does exactly that. A third function, sigtimedwait()
, also allows
specifying a timeout value for a signal-wait operation.
#include <signal.h> int sigwaitinfo(const sigset_t *set, const siginfo_t *info); int sigtimedwait(const sigset_t *se, const siginfo_t *info, const struct timespec *timeout);
These functions behave as you would expect if you are familiar with sigsuspend()
.
The specified signals should generally be blocked before the call.
Both functions return the signal number received, or -1 if an error or timout occurs.
For sigwaitinfo()
the only possibly errno
value
is EINTR
, which indicates that a signal not in the specified set
was received.
The sigtimedwait()
function has two additional errno
values, EINVAL
which specifies that the supplied timeout was
invalid and EAGAIN
which specifies that the timeout was reached
without a signal reception occurring.