The sigaction function allows the caller to examine or specify the action associated with a
specific signal. The sig parameter of sigaction specifies the signal number for the action. The
act parameter is a pointer to a struct sigaction structure that specifies the action to be
taken. The oact parameter is a pointer to a struct sigaction structure that receives the
previous action associated with the signal. If act is NULL, the call to sigaction does not
change the action associated with the signal. If oact is NULL, the call to sigaction does not
return the previous action associated with the signal.
SYNOPSIS
#include <signal.h>
int sigaction(int sig, const struct sigaction *restrict act,
struct sigaction *restrict oact);
POSIX:CX
If successful, sigaction returns 0. If unsuccessful, sigaction returns –1 and sets errno. The
following table lists the mandatory errors for sigaction.
Programs sometimes use signals to handle errors that are not fatal but that can occur in many
places in a program. For example, a user might want to avoid terminating a program while
aborting a long calculation or an I/O operation that has blocked for a long time. The program's
response to Ctrl-C should be to start over at the beginning (or at some other specified
location). A similar situation occurs when the program has nested prompts or menus and
should start over when a user misenters a response. Object-oriented languages often handle
these situations by throwing exceptions that are caught elsewhere. C programs can use signals
indirectly or directly to handle this type of problem.
In the indirect approach, the signal handler for SIGINT sets a flag in response to Ctrl-C. The
program tests the flag in strategic places and returns to the desired termination point if the flag
is set. The indirect approach is complicated, since the program might have to return through
several layers of functions. At each return layer, the program tests the flag for this special case.
In the direct approach, the signal handler jumps directly back to the desired termination point.
The jump requires unraveling the program stack. A pair of functions, sigsetjmp and
siglongjmp, provides this capability. The sigsetjmp function is analogous to a statement label,
and siglongjmp function is analogous to a goto statement. The main difference is that the
sigsetjmp and siglongjmp pair cleans up the stack and signal states as well as doing the jump.
Call the sigsetjmp at the point the program is to return to. The sigsetjmp provides a marker
in the program similar to a statement label. The caller must provide a buffer, env, of type
sigjmp_buf that sigsetjmp initializes to the collection of information needed for a jump back
to that marker. If savemask is nonzero, the current state of the signal mask is saved in the env
buffer. When the program calls sigsetjmp directly, it returns 0. To jump back to the sigsetjmp
point from a signal handler, execute siglongjmp with the same sigjmp_buf variable. The call
makes it appear that the program is returning from sigsetjmp with a return value of val.
SYNOPSIS
#include <setjmp.h>
void siglongjmp(sigjmp_buf env, int val);
int sigsetjmp(sigjmp_buf env, int savemask);
POSIX:CX
No errors are defined for siglongjmp. The sigsetjmp returns 0 when invoked directly and the
val parameter value when invoked by calling siglongjmp.
The C standard library provides functions setjmp and longjmp for the types of jumps referred
to above, but the action of these functions on the signal mask is system dependent. The
sigsetjmp function allows the program to specify whether the signal mask should be reset
when a signal handler calls this function. The siglongjmp function causes the signal mask to be
restored if and only if the value of savemask is nonzero. The val parameter of siglongjmp
specifies the value that is to be returned at the point set by sigsetjmp.
Program 8.12 sigjmp.c
Code to set up a signal handler that returns to the main loop when Ctrl-C is typed.
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
static sigjmp_buf jmpbuf;
static volatile sig_atomic_t jumpok = 0;
/* ARGSUSED */
static void chandler(int signo) {
if (jumpok == 0) return;
siglongjmp(jmpbuf, 1);
}
int main(void) {
struct sigaction act;
act.sa_flags = 0;
act.sa_handler = chandler;
if ((sigemptyset(&act.sa_mask) == -1) ||
(sigaction(SIGINT, &act, NULL) == -1)) {
perror("Failed to set up SIGINT handler");
return 1;
}
/* stuff goes here */
fprintf(stderr, "This is process %ld\n", (long)getpid());
if (sigsetjmp(jmpbuf, 1))
fprintf(stderr, "Returned to main loop due to ^c\n");
jumpok = 1;
for ( ; ; )
; /* main loop goes here */
}
Code to set up a signal handler that returns to the main loop when Ctrl-C is typed.
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
static sigjmp_buf jmpbuf;
static volatile sig_atomic_t jumpok = 0;
/* ARGSUSED */
static void chandler(int signo) {
if (jumpok == 0) return;
siglongjmp(jmpbuf, 1);
}
int main(void) {
struct sigaction act;
act.sa_flags = 0;
act.sa_handler = chandler;
if ((sigemptyset(&act.sa_mask) == -1) ||
(sigaction(SIGINT, &act, NULL) == -1)) {
perror("Failed to set up SIGINT handler");
return 1;
}
/* stuff goes here */
fprintf(stderr, "This is process %ld\n", (long)getpid());
if (sigsetjmp(jmpbuf, 1))
fprintf(stderr, "Returned to main loop due to ^c\n");
jumpok = 1;
for ( ; ; )
; /* main loop goes here */
}
Program 8.12 shows how to set up a SIGINT handler that causes the program to return to the
main loop when Ctrl-C is typed. It is important to execute sigsetjmp before calling siglongjmp
in order to establish a point of return. The call to sigaction should appear before the
sigsetjmp so that it is called only once. To prevent the signal handler from calling siglongjmp
before the program executes sigsetjmp, Program 8.12 uses the flag jumpok. The signal
handler tests this flag before calling siglongjmp.
8.8 Programming with Asynchronous I/O
Normally, when performing a read or write, a process blocks until the I/O completes. Some types
of performance-critical applications would rather initiate the request and continue executing,
allowing the I/O operation to be processed asynchronously with program execution. The older
method of asynchronous I/O uses either SIGPOLL or SIGIO to notify a process when I/O is
available. The mechanism for using these signals is set up with ioctl. This section discusses the
newer version which is part of the POSIX:AIO Asynchronous I/O Extension that was introduced
with the POSIX:RTS Realtime Extension.
The POSIX:AIO Extension bases its definition of asynchronous I/O on four main functions. The
aio_read function allows a process to queue a request for reading on an open file descriptor. The
aio_write function queues requests for writing. The aio_return function returns the status of an
asynchronous I/O operation after it completes, and the aio_error function returns the error
status. A fifth function, aio_cancel, allows cancellation of asynchronous I/O operations that are
already in progress.
The aio_read and aio_write functions take a single parameter, aiocbp, which is a pointer to an
asynchronous I/O control block. The aio_read function reads aiocbp->aio_bytes from the file
associated with aiocbp->aio_fildes into the buffer specified by aiocbp->aio_buf. The function
returns when the request is queued. The aio_write function behaves similarly.
SYNOPSIS
#include <aio.h>
int aio_read(struct aiocb *aiocbp);
int aio_write(struct aiocb *aiocbp);
POSIX:AIO
If the request was successfully queued, aio_read and aio_write return 0. If unsuccessful, these
functions return –1 and set errno. The following table lists the mandatory errors for these
functions that are specific to asynchronous I/O.
errno cause
EAGAIN system did not have the resources to queue request (B)
EBADF aiocbp->aio_fildes invalid (BA)
EFBIG aiocbp->aio_offset exceeds maximum (aio_write) (BA)
ECANCELED request canceled because of explicit aio_cancel (A)
EINVAL invalid member of aiocbp (BA)
EOVERFLOW aiocbp->aio_offset exceeds maximum (aio_read) (BA)
Errors that occur before the return of aio_read or aio_write have a B tag. These are values that
errno can have if the call returns –1. The errors that may occur after the return have an A tag.
These errors are returned by a subsequent call to aio_error. The aio_read and aio_write
functions also have the mandatory errors of their respective read and write counterparts.
The struct aiocb structure has at least the following members.
int aio_fildes; /* file descriptor */
volatile void *aio_buf; /* buffer location */
size_t aio_nbytes; /* length of transfer */
off_t aio_offset; /* file offset */
int aio_reqprio; /* request priority offset */
struct sigevent aio_sigevent; /* signal number and value */
int aio_lio_opcode; /* listio operation */
The first three members of this structure are similar to the parameters in an ordinary read or
write function. The aio_offset specifies the starting position in the file for the I/O. If the
implementation supports user scheduling (_POSIX_PRIORITIZED_IO and
_POSIX_PRIORITY_SCHEDULING are defined), aio_reqprio lowers the priority of the request. The
aio_sigevent field specifies how the calling process is notified of the completion. If
aio_sigevent.sigev_notify has the value SIGEV_NONE, the operating system does not generate
a signal when the I/O completes. If aio_sigevent.sigev_notify is SIGEV_SIGNAL, the operating
system generates the signal specified in aio_sigevent.sigev_signo. The aio_lio_opcode
function is used by the lio_listio function (not discussed here) to submit multiple I/O requests.
The aio_error and aio_return functions return the status of the I/O operation designated by
aiocbp. Monitor the progress of the asynchronous I/O operation with aio_error. When the
operation completes, call aio_return to retrieve the number of bytes read or written.
SYNOPSIS
#include <aio.h>
ssize_t aio_return(struct aiocb *aiocbp);
int aio_error(const struct aiocb *aiocbp);
POSIX:AIO
The aio_error function returns 0 when the I/O operation has completed successfully or
EINPROGRESS if the I/O operation is still executing. If the operation fails, aio_error returns the
error code associated with the failure. This error status corresponds to the value of errno that
would have been set by the corresponding read or write function. The aio_return function
returns the status of a completed underlying I/O operation. If the operation was successful, the
return value is the number of bytes read or written. Once aio_return has been called, neither
aio_return nor aio_error should be called for the same struct aiocb until another
asynchronous operation is started with this buffer. The results of aio_return are undefined if the
asynchronous I/O has not yet completed.
Comments
Post a Comment