Signal Emulation on the Symbian Platform

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.

Sending 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.

Handling signals

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:

  1. 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

    SIGHUP

    Ignore

    SIGINT

    Ignore

    SIGQUIT

    Ignore

    SIGILL

    Ignore

    SIGTRAP

    Ignore

    SIGABRT

    Ignore

    SIGIOT

    Ignore

    SIGEMT

    Ignore

    SIGFPE

    Ignore

    SIGKILL

    Process termination

    SIGBUS

    Ignore

    SIGSEGV

    Ignore

    SIGSYS

    Ignore

    SIGPIPE

    Process termination

    SIGALRM

    Process termination

    SIGTERM

    Process termination

    SIGURG

    Ignore

    SIGSTOP

    Ignore

    SIGTSTP

    Ignore

    SIGCONT

    Ignore

    SIGCHLD

    Ignore

    SIGTTIN

    Ignore

    SIGTTOU

    Ignore

    SIGIO

    Ignore

    SIGXCPU

    Ignore

    SIGXFSZ

    Ignore

    SIGVTALRM

    Ignore

    SIGPROF

    Ignore

    SIGWINCH

    Ignore

    SIGINFO

    Ignore

    SIGUSR1

    Ignore

    SIGUSR2

    Ignore

    SIGTHR

    Ignore

    SIGRTMIN

    Ignore

    SIGRTMAX

    Ignore

  2. Ignore the signal: You can choose to ignore a signal when it is delivered.

  3. 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;
        }

Blocking signals

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

Related concepts