Send a signal to a process group, process, or thread
#include <sys/neutrino.h> int SignalKill( uint32_t nd, pid_t pid, int tid, int signo, int code, int value ); int SignalKill_r( uint32_t nd, pid_t pid, int tid, int signo, int code, int value );
libc
Use the -l c option to qcc to link against this library. This library is usually included automatically.
The SignalKill() and SignalKill_r() kernel calls send the signal signo with a code specified by code and a value specified by value to a process group, process, or thread.
These functions are identical except in the way they indicate errors. See the Returns section for details.
If signo is zero, no signal is sent, but the validity of pid and tid are checked. You can use this as a test for existence.
SignalKill() implements the capabilities of the POSIX functions kill(), sigqueue(), and pthread_kill() in one call. Consider using these functions instead of invoking these kernel calls directly.
The pid and tid determine the target of the signal, as follows:
pid | tid | target |
---|---|---|
= 0 | — | Hit the process group of the caller |
< 0 | — | Hit a process group identified by -pid |
> 0 | = 0 | Hit a single process identified by pid |
> 0 | > 0 | Hit a single thread in process pid identified by tid |
If the target is a thread, the signal is always delivered to exactly that thread. If the thread has the signal blocked — see SignalProcmask() — the signal remains pending on the thread.
If the target is a process, the signal is delivered to a thread that has the signal unblocked; see SignalProcmask(), SignalSuspend(), and SignalWaitinfo(). If multiple threads have the signal unblocked, only one thread is given the signal. Which thread receives the signal isn't deterministic. To make it deterministic, you can:
Or:
If all threads have the signal blocked, it's made pending on the process. The first thread to unblock the signal receives the pending signal. If a signal is pending on a thread, it's never retargetted to the process or another thread, regardless of changes to the signal-blocked mask.
If the target is a process group, the signal is delivered as above to each process in the group.
A multithreaded application typically has one thread responsible for catching most or all signals. Threads that don't wish to be directly involved with signals block all signals in their mask.
The signal-blocked mask is maintained on a per-thread basis. The signal-ignore mask and signal handlers are maintained at the process level and are shared by all threads.
If multiple signals are delivered before the target can run and process the signals, the system queues them in priority order if the SA_SIGINFO bit was set for signo. Lower numbered signals have greater priority. If the SA_SIGINFO bit isn't set for signo, then at most one signal is queued at any time. Additional signals with the same signo replace existing ones. This is the default behavior for POSIX signal handlers installed using the old signal() function. The newer sigaction() function lets you control queuing or not on a per-signal basis. Signals with a code of SI_TIMER are never queued.
The code and value are always saved with the signal. This allows you to deliver data with the signal whether or not SA_SIGINFO has been set on the signo. If SA_SIGINFO is set, you can use signals to deliver small amounts of data without loss. If you wish to pass significant data, you may wish to consider using MsgSendPulse() and MsgSendv(), which deliver data with much greater efficiency.
When a thread receives a signal by a signal handler or SignalWaitinfo() call, it can retrieve the signo, code and value from a siginfo_t structure, which contains at least the following members:
The value of si_code is limited to an 8-bit signed value as follows:
Value | Description |
---|---|
-128 <= si_code <= 0 | User values |
0 < signo <= 127 | System values generated by the kernel |
Some of the common user values defined by POSIX are:
A successful return from this function means the signal has been delivered. What the process(es) or thread does with the signal isn't considered.
If a thread delivers signals that the receiving process has marked as queued faster than the receiver can consume them, the kernel may fail the call if it runs out of signal queue entries. If the signo, code, and value don't change, the kernel performs signal compression by saving an 8-bit count with each queued signal.
None. In the network case, lower priority threads may run.
The only difference between these functions is the way they indicate errors:
Safety: | |
---|---|
Cancellation point | No |
Interrupt handler | No |
Signal handler | Yes |
Thread | Yes |
pthread_kill(), kill(), SignalAction(), SignalProcmask(), SignalSuspend(), SignalWaitinfo(), sigqueue()