9.4 Realtime Signals

Team-FLY

In the base POSIX standard, a signal handler is a function with a single integer parameter that represents the signal number of the generating signal. The POSIX:XSI Extension and the POSIX:RTS Realtime Signal Extension have expanded signal-handling capabilities to include the queueing of signals and the passing of information to signal handlers. The standard expands the sigaction structure to allow for additional parameters to the signal handler. If _POSIX_REALTIME_SIGNALS is defined, your implementation supports realtime signals.

Section 8.4 introduces the sigaction function for examining or specifying the action associated with a signal. The struct sigaction structure contains at least the fields given below and specifies the action taken by the sigaction function.

  SYNOPSIS  #include <signal.h>   struct sigaction {      void (*sa_handler)(int); /* SIG_DFL, SIG_IGN, or pointer to function */      sigset_t sa_mask;        /* additional signals to be blocked                                  during execution of handler */      int sa_flags;           /* special flags and options */      void(*sa_sigaction) (int, siginfo_t *, void *); /* realtime handler */   };  POSIX:CX  

The sa_sigaction member specifies an alternative type of signal handler. This handler is used if sa_flags & SA_SIGINFO is nonzero. The form of this handler must be as follows .

 void func(int signo, siginfo_t *info, void *context); 

The signo parameter, which is equivalent to the parameter of sa_handler , gives the number of the caught signal. The context is not currently defined by the POSIX standard. The siginfo_t structure has at least the following members .

 int si_signo;                   /* signal number */ int si_code;                    /* cause of the signal */ union sigval si_value;          /* signal value */ 

The si_signo parameter contains the signal number. This value is the same as the value passed by the signo parameter of func .

The si_code parameter reports the cause of the signal. POSIX defines the following values for si_code: SI_USER , SI_QUEUE , SI_TIMER , SI_ASYNCIO and SI_MESGQ . A value of SI_USER means that the signal was generated explicitly by a function such as kill , raise or abort . In these situations, there is no way of generating a value for si_value , so it is not defined. A value of SI_QUEUE means that the sigqueue function generated the signal. A value of SI_TIMER means that a POSIX:RTS timer expired and generated the signal. A value of SI_ASYNCIO means completion of asynchronous I/O, and a value of SI_MESGQ means the arrival of a message on an empty message queue. The si_code variable may have other, implementation-defined values.

POSIX defines the contents of si_value only when the implementation supports the POSIX:RTS Extension and the si_code is SI_QUEUE , SI_TIMER , SI_ASYNCIO or SI_MESGQ . In these cases, the si_value contains the application-specified signal value. The union sigval is defined as follows.

 int sival_int; void *sival_ptr; 

According to this definition, either an integer or a pointer can be transmitted to the signal handler by the generator of the signal.

When multiple signals are pending, POSIX guarantees that at least one instance is delivered if the signal is unblocked. Additional instances may be lost. For applications in which it is important to receive every signal, use the POSIX:RTS signal queuing facility. The sigqueue function is an extension to kill that permits signals to be queued. Multiple instances of a signal generated with the kill function may not be queued, even if instances of the same signal generated by sigqueue are.

The sigqueue function sends signal signo with value value to the process with ID pid . If signo is zero, error checking is performed, but no signal is sent. If SA_SIGINFO in the sa_flags field of the struct sigaction structure was set when the handler for signo was installed, the signal is queued and sent to the receiving process. If SA_SIGINFO was not set for signo , the signal is sent at least once but might not be queued.

  SYNOPSIS  #include <signal.h>   int sigqueue(pid_t pid, int signo, const union sigval value);  POSIX:RTS  

If successful, sigqueue returns 0. If unsuccessful , sigqueue returns “1 and sets errno . The following table lists the mandatory errors for sigqueue .

errno

cause

EAGAIN

system does not have resources to queue this signal

EINVAL

signo is an invalid or unsupported signal

EPERM

caller does not have the appropriate privileges

ESRCH

no process corresponds to pid

Example 9.15

The following code segment checks to see whether process ID mypid corresponds to a valid process.

 pid_t mypid; union sigval qval; if ((sigqueue(mypid, 0, qval) == -1) && (errno == ESRCH))    fprintf(stderr, "%ld is not a valid process ID\n", (long)mypid); 

Program 9.9 shows a program that sends queued signals to a process. The program behaves like the kill command, but it calls sigqueue instead of kill . The process ID, the signal number and the signal value are command-line arguments.

The union sigval union can hold either a pointer or an integer. When the signal is generated from the same process by sigqueue , a timer, asynchronous I/O or a message queue, the pointer can pass an arbitrary amount of information to the signal handler. It does not make sense to use sigqueue to send a pointer from another process unless the address space of the sending process is accessible to the receiver.

Program 9.9 sendsigqueue.c

A program that sends a queued signal to a process .

 #include <signal.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) {    int pid;    int signo;    int sval;    union sigval value;    if (argc != 4) {       fprintf(stderr, "Usage: %s pid signal value\n", argv[0]);       return 1;    }    pid = atoi(argv[1]);    signo = atoi(argv[2]);    sval = atoi(argv[3]);    fprintf(stderr,"Sending signal %d with value %d to process %d\n",                    signo, sval, pid);    value.sival_int = sval;    if (sigqueue(pid, signo, value) == -1) {       perror("Failed to send the signal");       return 1;    }    return 0; } 

Program 9.10 prints its process ID, sets up a signal handler for SIGUSR1 , and suspends itself until a signal arrives. The signal handler just displays the values it receives from its parameters. Notice that the signal handler uses fprintf , which is not async-signal safe. This risky use works only because the main program does not use fprintf after it sets up the handler. The signal handler blocks other SIGUSR1 signals. Any other signal causes the process to terminate. You can use Program 9.9 in conjunction with Program 9.10 to experiment with POSIX realtime signals.

The asyncmonitorsignal.c module of Program 8.14 on page 292 showed how to use a realtime signal with asynchronous I/O. The read is started by initread . Three fields of the aio_sigevent structure are used to set up the signal. The sigev_notify field is set to SIGEV_SIGNAL , and the signal number is set in the sigev_signo field. Setting the sigev_value.sival_ptr field to &aiocb makes this pointer available to the signal handler in the si_value.sival_ptr field of the handler's second parameter. In Program 8.14, aiocb was a global variable, so it was accessed directly. Instead, aiocb could have been local to initread with a static storage class.

Program 9.10 sigqueuehandler.c

A program that receives SIGUSR1 signals and displays their values. See the text for comments about using fprintf in the signal handler .

 #include <signal.h> #include <stdio.h> #include <unistd.h> static void my_handler(int signo, siginfo_t* info, void *context) {    char *code = NULL;    switch(info->si_code) {       case SI_USER:      code = "USER"; break;       case SI_QUEUE:     code = "QUEUE"; break;       case SI_TIMER:     code = "TIMER"; break;       case SI_ASYNCIO:   code = "ASYNCIO"; break;       case SI_MESGQ:     code = "MESGQ"; break;       default:           code = "Unknown";    }    fprintf(stderr, "Signal handler entered for signal number %d\n", signo);    fprintf(stderr, "Signal=%3d, si_signo=%3d, si_code=%d(%s), si_value=%d\n,"           signo, info->si_signo, info->si_code, code, info->si_value.sival_int); } int main(void) {    struct sigaction act;    fprintf(stderr, "Process ID is %ld\n", (long)getpid());    fprintf(stderr, "Setting up signal SIGUSR1 = %d ready\n", SIGUSR1);    act.sa_flags = SA_SIGINFO;    act.sa_sigaction = my_handler;    if ((sigemptyset(&act.sa_mask) == -1)         (sigaction(SIGUSR1, &act, NULL) == -1)) {       perror("Failed to set up SIGUSR1 signal");       return 1;    }    /* no fprintf calls from here on */    for( ; ; )       pause(); } 
Team-FLY


Unix Systems Programming
UNIX Systems Programming: Communication, Concurrency and Threads
ISBN: 0130424110
EAN: 2147483647
Year: 2003
Pages: 274

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net