The OS supports the 32 standard POSIX signals (as in UNIX) as well as the POSIX realtime signals, both numbered from a kernel-implemented set of 64 signals with uniform functionality. While the POSIX standard defines realtime signals as differing from UNIX-style signals (in that they may contain four bytes of data and a byte code and may be queued for delivery), this functionality can be explicitly selected or deselected on a per-signal basis, allowing this converged implementation to still comply with the standard. Incidentally, the UNIX-style signals can select POSIX realtime signal queuing, if the application wants it. The BlackBerry 10 OS also extends the signal-delivery mechanisms of POSIX by allowing signals to be targeted at specific threads, rather than simply at the process containing the threads. Since signals are an asynchronous event, they're also implemented with the event-delivery mechanisms.
|Microkernel call||POSIX call||Description|
|SignalKill()||kill(), pthread_kill(), raise(), sigqueue()||Set a signal on a process group, process, or thread.|
|SignalAction()||sigaction()||Define action to take on receipt of a signal.|
|SignalProcmask()||sigprocmask(), pthread_sigmask()||Change signal blocked mask of a thread.|
|SignalSuspend()||sigsuspend(), pause()||Block until a signal invokes a signal handler.|
|SignalWaitinfo()||sigwaitinfo()||Wait for signal and return info on it.|
The original POSIX specification defined signal operation on processes only. In a multithreaded process, the following rules are followed:
- The signal actions are maintained at the process level. If a thread ignores or catches a signal, it affects all threads within the process.
- The signal mask is maintained at the thread level. If a thread blocks a signal, it affects only that thread.
- An unignored signal targeted at a thread is delivered to that thread alone.
- An unignored signal targeted at a process is delivered to the first thread that doesn't have the signal blocked. If all threads have the signal blocked, the signal is queued on the process until any thread ignores or unblocks the signal. If ignored, the signal on the process is removed. If unblocked, the signal is moved from the process to the thread that unblocked it.
When a signal is targeted at a process with a large number of threads, the thread table must be scanned, looking for a thread with the signal unblocked. Standard practice for most multithreaded processes is to mask the signal in all threads but one, which is dedicated to handling them. To increase the efficiency of process-signal delivery, the kernel caches the last thread that accepted a signal and always attempts to deliver the signal to it first.
The POSIX standard includes the concept of queued realtime signals. The BlackBerry 10 OS supports optional queuing of any signal, not just realtime signals. The queuing can be specified on a signal-by-signal basis within a process. Each signal can have an associated 8-bit code and a 32-bit value.
This is very similar to message pulses described earlier. The kernel takes advantage of this similarity and uses common code for managing both signals and pulses. The signal number is mapped to a pulse priority using _SIGMAX – signo. As a result, signals are delivered in priority order with lower signal numbers having higher priority. This conforms with the POSIX standard, which states that existing signals have priority over the new realtime signals.
It isn't safe to use floating-point operations in signal handlers.
The OS defines a total of 64 signals. Their range is as follows:
|1 ... 57||57 POSIX signals (including traditional UNIX signals)|
|41 ... 56||16 POSIX realtime signals (SIGRTMIN to SIGRTMAX)|
|57 ... 64||Eight special-purpose BlackBerry 10 OS signals|
A regular signal can be programmed to this behavior using the following standard signal calls. The special signals save the programmer from writing this code and protect the signal from accidental changes to this behavior.
sigset_t *set; struct sigaction action; sigemptyset(&set); sigaddset(&set, signo); sigprocmask(SIG_BLOCK, &set, NULL); action.sa_handler = SIG_DFL; action.sa_flags = SA_SIGINFO; sigaction(signo, &action, NULL);
This configuration makes these signals suitable for synchronous notification using the sigwaitinfo() function or SignalWaitinfo() kernel call. The following code blocks until the eighth special signal is received:
sigset_t *set; siginfo_t info; sigemptyset(&set); sigaddset(&set, SIGRTMAX + 8); sigwaitinfo(&set, &info); printf("Received signal %d with code %d and value %d\n", info.si_signo, info.si_code, info.si_value.sival_int);
Since the signals are always blocked, the program cannot be interrupted or killed if the special signal is delivered outside of the sigwaitinfo() function. Since signal queuing is always enabled, signals won't be lost—they are queued for the next sigwaitinfo() call.
These signals were designed to solve a common IPC requirement where a server wishes to notify a client that it has information available for the client. The server uses the MsgDeliverEvent() call to notify the client. There are two reasonable choices for the event within the notification: pulses or signals.
A pulse is the preferred method for a client that may also be a server to other clients. In this case, the client has created a channel for receiving messages and can also receive the pulse.
This won't be true for most simple clients. To receive a pulse, a simple client would be forced to create a channel for this express purpose. A signal can be used in place of a pulse if the signal is configured to be synchronous (that is, the signal is blocked) and queued—this is exactly how the special signals are configured. The client would replace the MsgReceive() call used to wait for a pulse on a channel with a simple sigwaitinfo() call to wait for the signal.
The eight special signals include named signals for special purposes:
- Used by select() to wait for I/O from multiple servers.
Summary of signals
This table describes what each signal means.
|SIGABRT||Abnormal termination signal such as issued by the abort() function.|
|SIGALRM||Timeout signal such as issued by the alarm() function.|
|SIGBUS||Indicates a memory parity error (BlackBerry 10 OS-specific interpretation). Note that if a second fault occurs while your process is in a signal handler for this fault, the process is terminated.|
|SIGCHLD (or SIGCLD)||Child process terminated. The default action is to ignore the signal.|
|SIGCONT||Continue if HELD. The default action is to ignore the signal if the process isn't HELD.|
|SIGDEADLK||Mutex deadlock occurred. If a process dies while holding a mutex, and you haven't called SyncMutexEvent() to set up an event to be delivered to the mutex's owner when the mutex dies, the kernel delivers a SIGDEADLK instead to all threads that are waiting on the mutex without a timeout.|
|SIGEMT||EMT instruction (emulator trap).
Note that SIGEMT uses the same signal number as SIGDEADLK.
|SIGFPE||Erroneous arithmetic operation (integer or floating point), such as division by zero or an operation resulting in overflow. Note that if a second fault occurs while your process is in a signal handler for this fault, the process is terminated.|
|SIGHUP||Death of session leader, or hangup detected on controlling terminal.|
|SIGILL||Detection of an invalid hardware instruction. Note that if
a second fault occurs while your process is in a signal handler for this fault,
the process is terminated.
One possible cause for this signal is trying to perform an operation that requires I/O privileges. A thread can request these privileges by:
|SIGINT||Interactive attention signal (Break).|
|SIGIOT||IOT instruction (not generated on x86 hardware).|
|SIGKILL||Termination signal—should be used only for emergency situations. This signal can't be caught or ignored.|
|SIGPIPE||Attempt to write on a pipe with no readers.|
|SIGPOLL (or SIGIO)||Pollable event occurred.|
|SIGPWR||Power failure or restart.|
|SIGQUIT||Interactive termination signal.|
|SIGSEGV||Detection of an invalid memory reference. Note that if a second fault occurs while your process is in a signal handler for this fault, the process is terminated.|
|SIGSTOP||Stop process (the default). This signal cannot be caught or ignored.|
|SIGSYS||Bad argument to system call.|
|SIGTRAP||Unsupported software interrupt.|
|SIGTSTP||Stop signal generated from keyboard.|
|SIGTTIN||Background read attempted from control terminal.|
|SIGTTOU||Background write attempted to control terminal.|
|SIGURG||Urgent condition present on socket.|
|SIGUSR1||Reserved as application-defined signal 1.|
|SIGUSR2||Reserved as application-defined signal 2.|
|SIGWINCH||Window size changed.|
Last modified: 2015-05-07