第十章 信号:
0 < signo < NSIG
#include <signal.h>
void (*signal(int signo, void(*func)(int)))(int);
if error return SIG_ERR, else return previous handler
#include <signal.h>
int kill(pid_t pid, int signo);
pid:
== -1, send to any process
> 0, send to the process which process-id == pid
== 0, send to any process
which pgid == this-pgid
< -1, send to any process which pgid == abs(pid)
this process need have privilege to send to receiver
otherwise will not send
particular: if signo == SIGCONT, will send to any process
which sid == this-sid
if signo is 0, not real to send, but check the receiver is alive or not?
if receiver is not exist, return -1, error is ESRCH
if success return 0, else return -1
int raise(int signo);
same as kill(getpid(), signo)
if success return 0, else return -1
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
return 0 or rest seconds of last alarm
#include <unistd.h>
int pause(void);
only catch a signal and handler it, will return
always return -1, errno is EINTR
#include <signal.h>
int sigemptyset(sigset_t * set);
if success return 0, else return -1
int sigfillset(sigset_t * set);
if success return 0, else return -1
int sigaddset(sigset_t * set, int signo);
if success return 0, else return -1
int sigdelset(sigset_t * set, int signo);
if success return 0, else return -1
int sigismember(const sigset_t * set, int signo);
ret: 1 means true, 0 means false, -1 means error
#include <signal.h>
int sigprocmask(int how, const sigset_t * restrict set,
sigset_t * restrict oset);
how: SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK
if success return 0, else return -1
#include <signal.h>
int sigpending(sigset_t * set);
if success return 0, else return -1
#include <signal.h>
int sigaction(int signo, const struct sigaction * restrict act,
struct sigaction * restrict oact);
if success return 0, else return -1
struct sigaction {
void (*sa_handler)(int);
sigset_t sa_mask;
int sa_flags;
void (*sa_sigaction)(int, siginfo_t *, void *);
};
sa_flags:
SA_INTERRUPT, SA_NOCLDSTOP, SA_NOCLDWAIT, SA_NODEFER
SA_ONSTACK, SA_RESETHAND, SA_RESTART, SA_SIGINFO
#include <setjmp.h>
int sigsetjmp(sigjmp_buf env, int savemask);
savemask: 0, not save mask to env; not 0, save mask to env
if callback by siglongjmp return non-zero, else return 0
void siglongjmp(sigjmp_buf env, int val);
#include <signal.h>
int sigsuspend(const sigset_t * sigmask);
always return -1, errno is EINTR
#include <stdlib.h>
void abort(void);
cannot be block and ignore
#include <unistd.h>
unsigned int sleep(unsigned int seconds);
return 0 or rest seconds
#include <signal.h>
void psignal(int signo, const char * msg);
#include <string.h>
#include <siginfo.h> /* Solaris need it */
char * strsignal(int signo);
#include <signal.h>
int sig2str(int signo, char * str);
SIG2STR_MAX defined by Solaris
Never change errno
if success return 0, else return -1
int str2sig(const char * str, int * signop);
Never change errno
if success return 0, else return -1
示例:
#include <stdio.h>
#include <signal.h>
void
sig_usr(int signo)
{
if (signo == SIGUSR1) {
printf("received SIGUSR1\n");
}
else if (signo == SIGUSR2) {
printf("received SIGUSR2\n");
}
else {
printf("error: received signal %d\n", signo);
}
}
int
main(void)
{
if (signal(SIGUSR1, sig_usr) == SIG_ERR) {
printf("can not catch SIGUSR1\n");
return -1;
}
if (signal(SIGUSR2, sig_usr) == SIG_ERR) {
printf("can not catch SIGUSR2\n");
return -1;
}
while (1) {
pause();
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <pwd.h>
#include <signal.h>
void
my_alarm(int signo)
{
struct passwd * rootptr;
printf("int signal handler\n");
if ((rootptr = getpwnam("root")) == NULL) {
printf("getpwnam(root) error\n");
exit(127);
}
alarm(1);
}
int
main(void)
{
struct passwd * ptr;
if (signal(SIGALRM, my_alarm) == SIG_ERR) {
printf("signal(SIGALRM) error\n");
exit(127);
}
printf("alarm\n");
alarm(1);
while (1) {
if ((ptr = getpwnam("adwardink")) == NULL) {
printf("getpwnam(adwardink) error\n");
exit(127);
}
if (strcmp(ptr->pw_name, "adwardink") != 0) {
printf("return value corrupted!, pw_name = %s\n", ptr->pw_name);
}
}
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
void
sig_cld(int signo)
{
pid_t pid;
int status;
printf("SIGCLD reccived\n");
if (signal(SIGCLD, sig_cld) == SIG_ERR) { /* may error in some old sys*/
printf("signal error\n");
exit(127);
}
if ((pid = wait(&status)) < 0) {
printf("wait error\n");
exit(127);
}
printf("pid = %d\n", pid);
}
int
main(void)
{
pid_t pid;
if (signal(SIGCLD, sig_cld) == SIG_ERR) {
printf("signal error\n");
exit(127);
}
if ((pid = fork()) < 0) {
printf("fork error\n");
exit(127);
}
else if (pid == 0) {
sleep(2);
_exit(0); /* test exit(0), get same answer*/
}
else {
pause();
exit(0);
}
}
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <unistd.h>
#include <signal.h>
jmp_buf jmpbuf;
void
sig_alm(int signo)
{
longjmp(jmpbuf, 1);
}
int
main(void)
{
int i;
int n;
char buff[BUFSIZ];
if (signal(SIGALRM, sig_alm) == SIG_ERR) {
printf("signal error\n");
exit(127);
}
if (setjmp(jmpbuf) != 0) {
printf("time out\n");
exit(127);
}
for (i = 0; i < 5; ++i) {
alarm(5);
if ((n = read(STDIN_FILENO, buff, BUFSIZ)) < 0) {
printf("read error\n");
exit(127);
}
alarm(0);
if (write(STDOUT_FILENO, buff, n) != n) {
printf("write error\n");
exit(127);
}
}
exit(0);
}
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <signal.h>
void
sig_quit(int signo)
{
printf("caught SIGQUIT\n");
if (signal(SIGQUIT, SIG_DFL) == SIG_ERR) {
printf("cannot reset SIGQUIT\n");
exit(127);
}
}
int
main(void)
{
sigset_t newmask;
sigset_t oldmask;
sigset_t pendmask;
if (signal(SIGQUIT, sig_quit) == SIG_ERR) {
printf("signal error\n");
exit(127);
}
/*
* block SIGQUIT and save current signal mask
*/
if (sigemptyset(&newmask) < 0) {
printf("sigemptyset error\n");
exit(127);
}
if (sigaddset(&newmask, SIGQUIT) < 0) {
printf("sigaddset error\n");
exit(127);
}
if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) {
printf("sigprocmask error\n");
exit(127);
}
sleep(5); /* SIGQUIT here will remain pending */
if (sigpending(&pendmask) < 0) {
printf("sigpending error\n");
exit(127);
}
if (sigismember(&pendmask, SIGQUIT) == 1) {
printf("\nSIGQUIT pending\n");
}
/*
* reset signal mask which unblocks SIGQUIT
*/
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) {
printf("sigprocmask error\n");
exit(127);
}
printf("SIGQUIT unblocked\n");
sleep(5); /* SIGQUIT here will terminate with core file */
exit(0);
}
#include <stdio.h>
#include <errno.h>
#include <time.h>
#include <setjmp.h>
#include <stdlib.h>
#include <signal.h>
sigjmp_buf jmpbuf;
volatile sig_atomic_t canjump;
void
pr_mask(const char * str)
{
sigset_t sigset;
int errno_save;
errno_save = errno;
if (sigprocmask(0, NULL, &sigset) == -1) {
printf("sigprocmask error\n");
return;
}
printf("%s", str);
if (sigismember(&sigset, SIGINT) == 1) {
printf("SIGINT ");
}
if (sigismember(&sigset, SIGQUIT) == 1) {
printf("SIGQUIT ");
}
if (sigismember(&sigset, SIGUSR1) == 1) {
printf("SIGUSR1 ");
}
if (sigismember(&sigset, SIGUSR2) == 1) {
printf("SIGUSR2 ");
}
if (sigismember(&sigset, SIGALRM) == 1) {
printf("SIGALRM ");
}
printf("\n");
errno = errno_save;
}
void
sig_usr1(int signo)
{
time_t starttime;
if (canjump = 0) {
return; /* unexpected signal, ignore */
}
pr_mask("starting sig_usr1: ");
alarm(3); /* SIGALRM in 3 seconds */
starttime = time(NULL);
while (1) {
if (time(NULL) > starttime + 5) { /* busy wait for 5 seconds */
break;
}
}
pr_mask("finishing sig_usr1: ");
canjump = 0;
siglongjmp(jmpbuf, 1); /* jump back to main, donot return */
}
void
sig_alrm(int signo)
{
pr_mask("in sig_alrm: ");
}
int
main(void)
{
if (signal(SIGUSR1, sig_usr1) == SIG_ERR) {
printf("signal(SIGUSR1) error\n");
exit(127);
}
if (signal(SIGALRM, sig_alrm) == SIG_ERR) {
printf("signal(SIGALRM) error\n");
exit(127);
}
pr_mask("starting main: ");
if (sigsetjmp(jmpbuf, 1) != 0) {
pr_mask("ending main: ");
exit(0);
}
canjump = 1; /* now sigsetjmp() is OK */
while (1) {
pause();
}
}
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <signal.h>
void
pr_mask(const char * str)
{
sigset_t sigset;
int errno_save;
errno_save = errno;
if (sigprocmask(0, NULL, &sigset) == -1) {
printf("sigprocmask error\n");
return;
}
printf("%s", str);
if (sigismember(&sigset, SIGINT) == 1) {
printf("SIGINT ");
}
if (sigismember(&sigset, SIGQUIT) == 1) {
printf("SIGQUIT ");
}
if (sigismember(&sigset, SIGUSR1) == 1) {
printf("SIGUSR1 ");
}
if (sigismember(&sigset, SIGUSR2) == 1) {
printf("SIGUSR2 ");
}
if (sigismember(&sigset, SIGALRM) == 1) {
printf("SIGALRM ");
}
printf("\n");
errno = errno_save;
}
void
sig_int(int signo)
{
pr_mask("\nin sig_int: ");
}
int
main(void)
{
sigset_t newmask;
sigset_t oldmask;
sigset_t waitmask;
if (signal(SIGINT, sig_int) == SIG_ERR) {
printf("signal error\n");
exit(127);
}
if (sigemptyset(&newmask) < 0) {
printf("sigemptyset error\n");
exit(127);
}
if (sigaddset(&newmask, SIGINT) < 0) {
printf("sigaddset error\n");
exit(127);
}
if (sigemptyset(&waitmask) < 0) {
printf("sigemptyset error\n");
exit(127);
}
if (sigaddset(&waitmask, SIGUSR1) < 0) {
printf("sigaddset error\n");
exit(127);
}
/*
* block SIGINT and save current signal mask
*/
if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) {
printf("sigprocmask error\n");
exit(127);
}
/*
* critical region of code
*/
pr_mask("in critical region: ");
/*
* pause, allowing all signals, except SIGUSR1
*/
if (sigsuspend(&waitmask) != -1) {
printf("sigsuspend error\n");
exit(127);
}
pr_mask("after return from sigsuspend: ");
/*
* reset signal mask which unblocks SIGINT
*/
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) {
printf("sigprocmask error\n");
exit(0);
}
/*
* and continue processing ...
*/
pr_mask("program exit: ");
exit(0);
}
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
volatile sig_atomic_t quitflag; /* set nonzero by signal handler */
void
sig_int(int signo)
{
if (signo == SIGINT) {
printf("\ninterrupt\n");
}
else if (signo == SIGQUIT) {
quitflag = 1;
}
}
int
main(void)
{
sigset_t newmask;
sigset_t oldmask;
sigset_t zeromask;
if (signal(SIGINT, sig_int) == SIG_ERR) {
printf("signal error\n");
exit(127);
}
if (signal(SIGQUIT, sig_int) == SIG_ERR) {
printf("signal error\n");
exit(127);
}
if (sigemptyset(&zeromask) < 0) {
printf("sigemptyset error\n");
exit(127);
}
if (sigemptyset(&newmask) < 0) {
printf("sigemptyset error\n");
exit(127);
}
if (sigaddset(&newmask, SIGQUIT) < 0) {
printf("sigaddset error\n");
exit(127);
}
/*
* block SIGQUIT and save current signal mask
*/
if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) {
printf("sigprocmask error\n");
exit(127);
}
/*
* pause, allowing all signals
*/
while (quitflag == 0) {
if (sigsuspend(&zeromask) != -1) {
printf("sigsuspend error\n");
exit(127);
}
}
/*
* SIGQUIT has been caught and is now blocked, do whatever
*/
quitflag = 0;
/*
* reset signal mask which unblocks SIGINT
*/
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) {
printf("sigprocmask error\n");
exit(0);
}
exit(0);
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#define BUFFSIZE (1024)
void
sig_tstp(int signo) /* signal handler for SIGTSTP */
{
sigset_t mask;
/* ... move cursor to lower left corner, reset tty mod ... */
/*
* unblock SIGTSTP, since it is blocked while we are handling it
*/
sigemptyset(&mask);
sigaddset(&mask, SIGTSTP);
sigprocmask(SIG_UNBLOCK, &mask, NULL);
signal(SIGTSTP, SIG_DFL); /* reset disposition to default */
kill(getpid(), SIGTSTP); /* and send the signal to ourselves */
/* we wonnot return from the kill until we are continued */
signal(SIGTSTP, sig_tstp); /* reestablish signal handler */
/* ... reset tty mode, redraw screen ... */
}
int
main(void)
{
int n;
char buf[BUFFSIZE];
/*
* only catch SIGTSTP if we are running with a job-control shell
*/
if (signal(SIGTSTP, SIG_IGN) == SIG_DFL) {
signal(SIGTSTP, sig_tstp);
}
while ((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0) {
if (write(STDOUT_FILENO, buf, n) != n) {
printf("write error\n");
exit(127);
}
}
if (n < 0) {
printf("read error\n");
exit(127);
}
exit(0);
}
#ifndef __MY_SIGNAL_H__
#define __MY_SIGNAL_H__
#include <stdio.h>
#include <errno.h>
#include <signal.h>
typedef void Sigfunc(int);
Sigfunc *
my_signal(int signo, Sigfunc * func)
{
struct sigaction act;
struct sigaction oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if (signo == SIGALRM) {
#ifdef SA_INTERRUPT
act.sa_flags |= SA_INTERRUPT;
#endif
}
else {
#ifdef SA_RESTART
act.sa_flags |= SA_RESTART;
#endif
}
if (sigaction(signo, &act, &oact) < 0) {
return SIG_ERR;
}
else {
return oact.sa_handler;
}
}
Sigfunc *
my_signal_intr(int signo, Sigfunc * func)
{
struct sigaction act;
struct sigaction oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
#ifdef SA_INTERRUPT
act.sa_flags |= SA_INTERRUPT;
#endif
if (sigaction(signo,&act, &oact) < 0) {
return SIG_ERR;
}
else {
return oact.sa_handler;
}
}
#endif
#include <stdlib.h>
#include <signal.h>
void
sig_alrm(int signo)
{
/* nothing to do, just returning wakes up sigsuspend() */
}
unsigned int
sleep(unsigned int seconds)
{
struct sigaction newact;
struct sigaction oldact;
sigset_t newmask;
sigset_t oldmask;
sigset_t pendmask;
unsigned int unslept;
/* set our handler, save previous information */
newact.sa_handler = sig_alrm;
sigemptyset(&newact.sa_mask);
newact.sa_flags = 0;
sigaction(SIGALRM, &newact, &oldact);
/* block SIGALRM and save current signal mask */
sigemptyset(&newmask);
sigaddset(&newmask, SIGALRM);
sigprocmask(SIG_BLOCK, &newmask, &oldmask);
alarm(seconds);
pendmask = oldmask;
sigdelset(&pendmask, SIGALRM); /* make sure SIGALRM is not blocked */
sigsuspend(&pendmask); /* wait for any signal to be caught */
/* some signal has been caught, SIGALRM is now blocked */
unslept = alarm(0);
sigaction(SIGALRM, &oldact, NULL); /* reset previous action */
/* reset signal mask, which unblocks SIGALRM */
sigprocmask(SIG_SETMASK, &oldmask, NULL);
return unslept;
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
void
my_abort(void) /* POSIX-style abort() function */
{
sigset_t mask;
struct sigaction action;
/*
* caller cannot ignore SIGABRT, if so reset to default
*/
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); /* flush all open stdio streams */
}
/*
* caller cannot block SIGABRT, make sure it is unblocked
*/
sigfillset(&mask);
sigdelset(&mask, SIGABRT); /* make has only SIGABRT turned off */
sigprocmask(SIG_SETMASK, &mask, NULL);
kill(getpid(), SIGABRT); /* send the signal */
/*
* if we are here, process caught SIGABRT and returned
*/
fflush(NULL); /* flush all open stdio streams */
action.sa_handler = SIG_DFL;
sigaction(SIGABRT, &action, NULL); /* reset to default */
sigprocmask(SIG_SETMASK, &mask, NULL); /* just in case ... */
kill(getpid(), SIGABRT); /* and one more time */
exit(1); /* this should never be executed ... */
}
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
int
my_system(const char * cmdstring) /* with appropriate signal handling */
{
pid_t pid;
int status;
struct sigaction ignore;
struct sigaction saveintr;
struct sigaction savequit;
sigset_t chldmask;
sigset_t savemask;
if (cmdstring == NULL) {
return 1; /* always a command processor with UNIX */
}
ignore.sa_handler = SIG_IGN; /* ignore SIGINT and SIGQUIT */
sigemptyset(&ignore.sa_mask);
ignore.sa_flags = 0;
if (sigaction(SIGINT, &ignore, &saveintr) < 0) {
return -1;
}
if (sigaction(SIGQUIT, &ignore, &savequit) < 0) {
return -1;
}
sigemptyset(&chldmask);
sigaddset(&chldmask, SIGCHLD); /* now block SIGCHLD */
if (sigprocmask(SIG_BLOCK, &chldmask, &savemask) < 0) {
return -1;
}
if ((pid = fork()) < 0) {
status = -1; /* probably out of processes */
}
else if (pid == 0) {
/* restore previous signal actions, reset signal mask */
sigaction(SIGINT, &saveintr, NULL);
sigaction(SIGQUIT, &savequit, NULL);
sigprocmask(SIG_SETMASK, &savemask, NULL);
execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
_exit(127); /* exec error */
}
else {
while (waitpid(pid, &status, 0) < 0) {
if (errno != EINTR) {
status = -1; /* error other than EINTR from waitpid() */
break;
}
}
}
/* restore previous signal actions, reset signal mask */
if (sigaction(SIGINT, &saveintr, NULL) < 0) {
return -1;
}
if (sigaction(SIGQUIT, &savequit, NULL) < 0) {
return -1;
}
if (sigprocmask(SIG_SETMASK, &savemask, NULL) < 0) {
return -1;
}
return status;
}
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include "signal.h"
volatile sig_atomic_t sigflag; /* set nonzero by sig handler */
sigset_t newmask, oldmask, zeromask;
void
sig_usr(int signo) /* one signal handler for SIGUSR1 and SIGUSR2 */
{
sigflag = 1;
}
void
TELL_WAIT(void)
{
if (signal(SIGUSR1, sig_usr) == SIG_ERR) {
printf("signal(SIGUSR1) error\n");
exit(127);
}
if (signal(SIGUSR2, sig_usr) == SIG_ERR) {
printf("signal(SIGUSR2) error\n");
exit(127);
}
if (sigemptyset(&zeromask) < 0) {
printf("sigemptyset error\n");
exit(127);
}
if (sigemptyset(&newmask) < 0) {
printf("sigemptyset error\n");
exit(127);
}
if (sigaddset(&newmask, SIGUSR1) < 0) {
printf("sigaddset error\n");
exit(127);
}
if (sigaddset(&newmask, SIGUSR2) < 0) {
printf("sigaddset error\n");
exit(127);
}
/*
* block SIGUSR1 and SIGUSR2, and save current signal mask
*/
if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) {
printf("sigprocmask(SIG_BLOCK) error\n");
exit(127);
}
}
void
TELL_PARENT(pid_t pid)
{
kill(pid, SIGUSR2); /* tell parent we are done */
}
void
WAIT_PARENT(void)
{
while (sigflag == 0) {
if (sigsuspend(&zeromask) != -1) { /* and wait for parent */
printf("sigsuspend error\n");
exit(127);
}
}
sigflag = 0;
/*
* reset signal mask to original value
*/
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) {
printf("sigprocmask(SIG_SETMASK) error\n");
exit(0);
}
}
void
TELL_CHILD(pid_t pid)
{
kill(pid, SIGUSR1); /* tell child we are done */
}
void
WAIT_CHILD(void)
{
while (sigflag == 0) {
if (sigsuspend(&zeromask) != -1) { /* and wait for child */
printf("sigsuspend error\n");
exit(127);
}
}
sigflag = 0;
/*
* reset signal mask to original value
*/
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) {
printf("sigprocmask(SIG_SETMASK) error\n");
exit(0);
}
}
关于SIGKILL/SIGSTOP/SIGTSTP:http://blog.sina.com.cn/s/blog_53a7e8a3010155hx.html
SIGKILL和SIGSTOP的区别
SIGKILL提供给管理员杀死进程的权利, SIGSTOP提供给管理员暂停进程的权利, 所以这两个信号不能被忽略和重定义。
Kill父进程后, 子进程的父进程号为1; 但是stop父进程后子进程的父进程号还是该父进程。
SIGSTOP和SIGTSTP的区别
SIGSTOP提供给管理员暂停进程的特权, 所以不能忽略和重定义。
当用户按下CTRL-Z时, 向前台进程组发送SIGTSTP信号以暂停进程(默认动作), 该信号可以被忽略和重定义。
另外用户在控制终端上输入CTRL-S可以暂停进程的输出, 输入CTRL-Q可以恢复进程的输出。