The libc
library of P.I.P.S. provides support for POSIX
signals, thereby facilitating the porting of applications that use signals
for exception handling and as control IPC.
P.I.P.S. supports POSIX signals by emulating them in user-side code. This is different from the UNIX architecture, where the kernel manages the generation and delivery of signals, and has important implications.
Signals are always handled in the context of a signal-handler thread created by the P.I.P.S. backend. For this reason, signals cannot be directed to a particular thread.
Before the handler function of a signal is invoked in the signal-handler thread, all other threads are suspended. When the handler function returns, the other threads resume. This is done to mirror the UNIX behaviour of process execution being suspended when a signal is being handled.
There might be a considerable amount of latency when you send or receive signals.
Signals can be sent between P.I.P.S. processes using kill(), raise() or sigqueue().
You can use these functions to send any of the supported signals (refer to the following table).
The P.I.P.S. runtime sends the following signals to P.I.P.S. processes:
SIGPIPE: This signal is sent to a process which attempts to write to a broken pipe().
SIGCHLD: This signal is sent to a parent process when a child process exits.
SIGALRM: This signal is sent to a process when an alarm registered by the process times out.
Note: Always ensure that you handle SIGPIPE
, SIGCHLD
or SIGALRM
using
a signal handler to avoid the termination of the process receiving these signals.
For more information about handling signals, see the following section.
A signal can be received by a process at any time and is handled immediately, unless it is currently blocked. You can handle a signal in the following ways:
Use default handling: The default action for each signal supported on the Symbian platform is listed in the following table.
Note: The default action
for all of the signals sent by the P.I.P.S. runtime (SIGPIPE
, SIGCHLD
or SIGALRM
)
is process termination. You must provide a custom handler for each of these
signals.
Signal | Default Action |
---|---|
|
Ignore |
|
Ignore |
|
Ignore |
|
Ignore |
|
Ignore |
|
Ignore |
|
Ignore |
|
Ignore |
|
Ignore |
|
Process termination |
|
Ignore |
|
Ignore |
|
Ignore |
|
Process termination |
|
Process termination |
|
Process termination |
|
Ignore |
|
Ignore |
|
Ignore |
|
Ignore |
|
Ignore |
|
Ignore |
|
Ignore |
|
Ignore |
|
Ignore |
|
Ignore |
|
Ignore |
|
Ignore |
|
Ignore |
|
Ignore |
|
Ignore |
|
Ignore |
|
Ignore |
|
Ignore |
|
Ignore |
Ignore the signal: You can choose to ignore a signal when it is delivered.
Use a custom signal handler function: You can set a custom signal handler function to be invoked when the signal arrives.
The following example code demonstrates how
you can handle a SIGCHLD
signal by setting a custom signal
handler function:
#include <signal.h> #include <stdio.h> #include <stdlib.h> void sighandler(int signum) { if(signum == SIGCHLD) { // Program logic for custom signal handling } else printf(“Error: Unknown signal”); } int main() { // When SIGCHLD arrives, invoke sighandler() signal(SIGCHLD,sighandler); // program logic return 0; }
A P.I.P.S. process can choose to block (and subsequently unblock) signals to itself using sighold(), sigset(), sigrelse() and sigprocmask(). Signals that are blocked on a P.I.P.S. process are not be delivered for handling. Instead, they are queued to be handled when they are unblocked.
Non-realtime signals are queued only once, even when they are delivered multiple times. However, real-time signals are queued every time they are delivered.
Note: You can force non-realtime signals to be queued multiple times by sending the signal using sigqueue().
Examples
The following example code demonstrates how real-time signals are queued when they are blocked:
#include <stdio.h> #include <signal.h> void func(int sig) { printf("Signal was received"); } int main(void) { signal(SIGRTMIN+3,func); sighold(SIGRTMIN+3); raise(SIGRTMIN+3); raise(SIGRTMIN+3); raise(SIGRTMIN+3); //This will cause func() to be called thrice sigrelse(SIGRTMIN+3); return 0; }
The output displayed is:
Signal was received Signal was received Signal was received
The following example code demonstrates how non-realtime signals are queued when they are blocked:
#include <stdio.h> #include <signal.h> void func(int sig) { printf("Signal was received"); } int main(void) { signal(SIGINT,func); sighold(SIGINT); raise(SIGINT); raise(SIGINT); raise(SIGINT); // This will cause func() to be called only ONCE, since SIGINT is a non-realtime signal. sigrelse(SIGINT); return 0; }
The output displayed is:
Signal was received
The following example code demonstrates how you can force a non-realtime signal to be queued multiple times by sending the signal using sigqueue():
#include <stdio.h> #include <signal.h> #include <unistd.h> void func(int sig) { printf("Signal was received"); } int main(void) { union sigval val; val.sigval_int = 0; signal(SIGINT,func); sighold(SIGINT); sigqueue(getpid(), SIGINT,val); sigqueue(getpid(), SIGINT,val); sigqueue(getpid(), SIGINT,val); // This will cause func() to be called thrice sigrelse(SIGINT); return 0; }
The output displayed is:
Signal was received Signal was received Signal was received