12.6. Real-Time Signals To address some of the limitations of the POSIX signal model, notably the lack of any data attached to the signal and the possibility of multiple signals being collapsed into a single delivery, the POSIX Real Time Signals extension was developed.[20] Systems that support real-time signals, including Linux, also support the traditional POSIX signals mechanism we described earlier. For the highest levels of portability between systems, we suggest using the standard POSIX interfaces unless there is a need for some of the extra features provided by the real-time extension. [20] Real time is a misnomer here, as the extension makes no attempt to provide guarantees on the latency of signal delivery. The features it does add are useful in building soft real-time implementations, however. 12.6.1. Signal Queueing and Ordering Two of the limitations of the standard POSIX signal model are that when a signal is pending sending that signal again does not result in multiple signal deliveries and the lack of ordering guarantees for the delivery of multiple different signals (if you send a SIGTERM followed by a SIGKILL there is no way of knowing which one will be delivered first). The POSIX Real Time Signal extensions have added a new set of signals that are not subject to these constraints. There are a number of real-time signals available, and they are not used by the kernel for any predefined purpose. All of the signals between SIGRTMIN and SIGRTMAX are real-time signals, although the exact number of these is not specified by POSIX (Linux provides 32 at the time of writing, but that could be increased in the future). Real-time signals are always queued; every real-time signal sent to an application is delivered to that application (unless the application terminates before some of the signals have been delivered). The ordering of real-time signals is also well defined. Real-time signals with smaller signal numbers are always delivered before signals with larger signal numbers, and when multiple signals with the same signal number have been queued, they are delivered in the order they were sent. The ordering between non-real-time signals is not defined, nor is the ordering between non-real-time signals and real-time signals. Here is some sample code to illustrate signal queuing and ordering: 1: /* queued.c */ 2: 3: /* get the definition of strsignal() from string.h */ 4: #define _GNU_SOURCE 1 5: 6: #include <sys/signal.h> 7: #include <stdlib.h> 8: #include <stdio.h> 9: #include <string.h> 10: #include <unistd.h> 11: 12: /* Globals for building a list of caught signals */ 13: int nextSig = 0; 14: int sigOrder[10]; 15: 16: /* Catch a signal and record that it was handled. */ 17: void handler(int signo) { 18: sigOrder[nextSig++] = signo; 19: } 20: 21: int main() { 22: sigset_t mask; 23: sigset_t oldMask; 24: struct sigaction act; 25: int i; 26: 27: /* Signals we're handling in this program */ 28: sigemptyset(&mask); 29: sigaddset(&mask, SIGRTMIN); 30: sigaddset(&mask, SIGRTMIN + 1); 31: sigaddset(&mask, SIGUSR1); 32: 33: /* Send signals to handler() and keep all signals blocked 34: that handler() has been configured to catch to avoid 35: races in manipulating the global variables. */ 36: act.sa_handler = handler; 37: act.sa_mask = mask; 38: act.sa_flags = 0; 39: 40: sigaction(SIGRTMIN, &act, NULL); 41: sigaction(SIGRTMIN + 1, &act, NULL); 42: sigaction(SIGUSR1, &act, NULL); 43: 44: /* Block the signals we're working with so we can see the 45: queuing and ordering behavior. */ 46: sigprocmask(SIG_BLOCK, &mask, &oldMask); 47: 48: /* Generate signals */ 49: raise(SIGRTMIN + 1); 50: raise(SIGRTMIN); 51: raise(SIGRTMIN); 52: raise(SIGRTMIN + 1); 53: raise(SIGRTMIN); 54: raise(SIGUSR1); 55: raise(SIGUSR1); 56: 57: /* Enable delivery of the signals. They'll all be delivered 58: right before this call returns (on Linux; this is NOT 59: portable behavior). */ 60: sigprocmask(SIG_SETMASK, &oldMask, NULL); 61: 62: /* Display the ordered list of signals we caught */ 63: printf("signals received:\n"); 64: for (i = 0; i < nextSig; i++) 65: if (sigOrder[i] < SIGRTMIN) 66: printf("\t%s\n", strsignal(sigOrder[i])); 67: else 68: printf("\tSIGRTMIN + %d\n", sigOrder[i] - SIGRTMIN); 69: 70: return 0; 71: } This program sends itself a number of signals and records the order the signals arrive in for display. While the signals are being sent, it blocks those signals to prevent them from being delivered immediately. It also blocks the signals whenever the signal handler is being run by setting the sa_mask member of struct sigaction when installing the signal handler for each signal. This prevents possible races accessing the global variables nextSig and sigOrder from inside the signal handler. Running this program gives the following results: signals received: User defined signal 1 SIGRTMIN + 0 SIGRTMIN + 0 SIGRTMIN + 0 SIGRTMIN + 1 SIGRTMIN + 1 This shows that all of the real-time signals were delivered, while only a single instance of SIGUSR1 was delivered. You can also see the reordering of real-time signals, with all of the SIGRTMIN signals delivered before SIGRTMIN + 1. |