#include "apue.h"
static volatile sig_atomic_t sigflag;
static sigset_t newmask, oldmask,zeromask;
static void sig_usr(int signo)
{
sigflag=1;
}
void TELL_WAIT(void)
{
if(signal(SIGUSR1,sig_usr)==SIG_ERR)
err_sys("signal(SIGUSR1) error");
if(signal(SIGUSR2,sig_usr)==SIG_ERR)
err_sys("signal(SIGUSR2) error");
sigemptyset(&zeromask);
sigemptyset(&newmask);
sigaddset(&newmask,SIGUSR1);
sigaddset(&newmask,SIGUSR2);
if(sigprocmask(SIG_BLOCK,&newmask, &oldmask)<0)
err_sys("SIG_BLOCK error");
}
void TELL_PARENT(pid_t pid)
{
kill(pid,SIGUSR2);
}
void WAIT_PARENT(void)
{
while(sigflag==0)
sigsuspend(&zeromask);
sigflag=0;
if(sigprocmask(SIG_SETMASK, &oldmask, NULL)<0)
err_sys("SIG_SETMASK error");
}
void TELL_CHILD(pid_t pid)
{
kill(pid,SIGUSR1);
}
void WAIT_CHILD(void)
{
while(sigflag==0)
sigsuspend(&zeromask);
sigflag=0;
if(sigprocmask(SIG_SETMASK,&oldmask,NULL)<0)
err_sys("SIG_SETMASK error");
}
Routines to allow a parent and child to synchronize
We use the two user-defined signals: SIGUSR1 is sent by the parent to the child, and SIGUSR2 is sent by the child to the parent.
The code to handle this looks similar to the following:
if (intr_flag) /* flag set by our SIGINT handler */
handle_intr();
if (alrm_flag) /* flag set by our SIGALRM handler */
handle_alrm(); /* signals occurring in here are lost */
while (read( ... ) < 0) {
if (errno == EINTR) {
if (alrm_flag)
handle_alrm();
else if (intr_flag)
handle_intr();
} else {
/* some other error */
}
} else if (n == 0) {
/* end of file */
} else {
/* process input */
}
What we would like to be able to do is the following sequence of steps, in order.
1.Block SIGINT and SIGALRM.
2.Test the two global variables to see whether either signal has occurred and, if so, handle the condition.
3.Call read (or any other system function) and unblock the two signals, as an
atomic operation.
The sigsuspend function helps us only if step 3 is a pause operation.
abort Function
#include <stdlib.h>
void abort(void);
This function sends the SIGABRT signal to the caller. (Processes should not ignore this signal.) ISO C states that calling abort will deliver an unsuccessful termination notification to the host environment by calling raise(SIGABRT).
ISO C requires that if the signal is caught and the signal handler returns, abort still doesn’t return to its caller. If this signal is caught, the only way the signal handler can’t return is if it calls exit, _exit, _Exit, longjmp, or siglongjmp. (Section 10.15 discusses the differences between longjmp and siglongjmp.) POSIX.1 also specifies that abort overrides the blocking or ignoring of the signal by the process.
The ISO C specification of this function leaves it up to the implementation as to
whether output streams are flushed and whether temporary files (Section 5.13) are deleted. POSIX.1 goes further and allows an implementation to call fclose on open standard I/O streams before terminating if the call to abort terminates the process.
Earlier versions of System V generated the SIGIOT signal from the abort function. Furthermore, it was possible for a process to ignore this signal or to catch it and return from the signal handler, in which case abort returned to its caller.
4.3BSD generated the SIGILL signal. Before doing this, the 4.3BSD function unblocked the signal and reset its disposition to SIG_DFL (terminate with core file). This prevented a process from either ignoring the signal or catching it.
Since most UNIX System implementations of tmpfile call unlink immediately after creating the file, the ISO C warning about temporary files does not usually concern us.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void abort(void)
{
sigset_t mask;
struct sigaction action;
sigaction(SIGABRT, NULL, &action);
if(action.sa_handler==SIG_IGN)
{
action.sa_handler==SIG_DFL;
sigaction(SIGABRT,&action,NULL);
}
if(action.sa_handler==SIG_DFL)
fflush(NULL);
sigfillset(&mask);
sigdelset(&mask, SIGABRT);
sigprocmask(SIG_SETMASK,&mask, NULL);
kill(getpid(),SIGABRT);
fflush(NULL);
action.sa_handler=SIG_DFL;
sigaction(SIGABRT,&action,NULL);
sigprocmask(SIG_SETMASK,&mask,NULL);
kill(getpid(),SIGABRT);
return 1;
}
Implementation of POSIX.1 abort