第四讲 信号处理
信号是进程间通信的最简单形式
信号的生命周期
简单信号
#include <signal.h>
void *signal(int signum, void *handler);
SIG_IGN, SIG_DFL, SIGKILL, SIGSTOP
可靠信号 (sigset_t)
信号和系统调用
Linux信号系统api
发送信号
int tkill(pid_t pid, int signum);
int raise(int signum);
使用sigset_t
#include <signal.h>
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set); // 将当前全部的有效信号添加到set中
int sigaddset(sigset_t *set, int signum);
int sigdelset(sigset_t *set, int signum);
int sigismember(const sigset_t *set, int signum);
EINVAL
#include<signal.h>
int sigaction(int signum, struct sigaction *act, struct sigaction *oact);
struct sigaction{
__sighandler_t sa_handler;
sigset_t sa_mask;
int sa_flags;
}
void handler(int signum);
SA_NOCLDSTOP, SA_NODEFER, SA_RESETHAND, SA_RESTART
while( *src )
*dest++ = *src++;
int sigprocmask(int what, const sigset_t *set, sigset_t *oldset);
SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK
sigprocmask(SIG_BLOCK, NULL, ¤tSet);
sigset_t hup;
sigemptyset(&hup);
sigaddset(&hup, SIGHUP);
sigprocmask(SIG_BLOCK, &hup, NULL);
while(*src)
*dest++ = *src++;
sigprocmask(SIG_UNBLOCK, &hup,NULL);
int sigpending(sigset_t *set);
int pause(void);
int sigsuspend(const sigset_t *mask);
errno = EINTR
信号
SIGABRT, SIGALM, SIGBUS, SIGCHLD, SIGCONT,SIGFPE, SIGHUP, SIGILL, SIGINT, SIGIO, SIGKILL, SIGPIPE, SIGPROF, SIGPWR, SIGQUIT, SIGSEGV, SIGSTOP, SIGSYS, SIGTERM, SIGTRAP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGUSR1, SIGUSR2, SIGVTALRM, SIGWINCH, SIGXCPU, SIGXFSZ
编写信号处理程序
重新打开日志文件
例
#include <error.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
volatile int reopenLog = 0;
void logstring(int logfd, char *str)
{
write(logfd,str,strlen(str));
}
void hupHandler(int signum)
{
reopenLog = 1;
}
int main()
{
int done = 0;
struct sigaction sa;
int rc;
int logfd;
logfd = STDOUT_FILENO;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = hupHandler;
if (sigaction(SIGHUP, &sa, NULL))
{
perror("sigaction");
}
while (!done)
{
rc = sleep(5);
if (rc)
{
if (reopenLog)
{
logstring(logfd,"*reopening log files at sig hup request/n");
reopenLog = 0;
}
else
{
logstring(logfd,"*sleep interrupted by unkown signal/n");
done = 1;
}
}
else
{
logstring(logfd, "periodic message/n");
}
}
return 0;
}
实时信号
SIGRTMIN, SIGRTMAX
例
#define _GNU_SOURCE 1
#include <sys/signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int nextSig = 0;
int sigOrder[10];
void handler(int signo)
{
sigOrder[nextSig++] = signo;
}
int main()
{
sigset_t mask;
sigset_t oldmask;
struct sigaction act;
int i;
sigemptyset(&mask);
sigaddset(&mask, SIGRTMIN);
sigaddset(&mask, SIGRTMIN + 1);
sigaddset(&mask, SIGUSR1);
act.sa_handler = handler;
act.sa_mask = mask;
act.sa_flags = 0;
sigaction(SIGRTMIN, &act, NULL);
sigaction(SIGRTMIN + 1, &act, NULL);
sigaction(SIGUSR1, &act ,NULL);
sigprocmask(SIG_BLOCK, &mask, &oldmask);
raise(SIGRTMIN + 1);
raise(SIGRTMIN);
raise(SIGRTMIN);
raise(SIGRTMIN + 1);
raise(SIGRTMIN);
raise(SIGUSR1);
raise(SIGUSR1);
sigprocmask(SIG_SETMASK, &oldmask, NULL);
printf("signals received:/n");
for (i = 0; i < nextSig; i++)
{
if (sigOrder[i] < SIGRTMIN)
{
printf("/t%s/n",strsignal(sigOrder[i]));
}
else
{
printf("/tSIGRTIM + %d/n",sigOrder[i] - SIGRTMIN);
}
}
return 0;
}
获取信号信息
得到信号上下文
void handler(int signum, siginfo_t *siginfo, void *context);
SA_SIGINFO
#include <signal.h>
struct sigaction{
union{
__sighandler_t sa_handler;
__sigaction_t sa_sigaction;
}
sigset_t sa_mask;
unsigned long sa_flags;
}
#define sa_handler __sigactin_handler.sa_handler
#define sa_sigaction __sigaction_handler.sa_sigaction
Si_signo si_code: SI_USER, SI_QUEUE, SI_TKILL, SI_KERNEL
SIGSEGV SEGV_MAPER
SEGV_ACCERR
SIGBUS
BUS_ADDRALN
BUS_ADDERR
BUS_OBJERR
SIGCHLD CLD_EXITED
CLD_KILLED
CLD_STOPPED
例子
#include <sys/signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#ifndef SI_TKILL
#define SI_TKILL -6
#endif
void handler(int signo, siginfo_t *info, void *f)
{
static int count = 0;
printf("caught signal sent by ");
switch(info->si_code)
{
case SI_USER:
printf("kill()/n");
break;
case SI_QUEUE:
printf("sigqueue()/n");
break;
case SI_TKILL:
printf("tkill() or raise()/n");
break;
case CLD_EXITED:
printf("kernel telling us child exited/n");
exit(0);
}
if (++count == 4)
_exit(1);
}
int main()
{
struct sigaction act;
union sigval val;
pid_t pid = getpid();
val.sival_int = 1234;
act.sa_sigaction = handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO;
sigaction(SIGCHLD, &act, NULL);
kill(pid, SIGCHLD);
sigqueue(pid, SIGCHLD, val);
raise(SIGCHLD);
if (!fork())
{
_exit(0);
}
sleep(60);
return 0;
}
#include <sys/signal.h>
#include <stdlib.h>
#include <stdio.h>
void handler(int signo, siginfo_t *info, void *f)
{
printf("caught");
if (info->si_signo == SIGSEGV)
{
printf("segv accessing %p", info->si_addr);
}
if (info->si_code == SEGV_MAPERR)
{
printf("segv_maperr");
}
printf("/n");
_exit(1);
}
int main()
{
struct sigaction act;
act.sa_sigaction = handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO;
sigaction(SIGSEGV, &act, NULL);
*((int*)NULL) = 1;
return 0;
}
使用信号发送数据
#include <signal.h>
void *sigqueue(pid_t pid ,int signum, const union sigval value);
union sigval{
int sival_int;
void *sival_ptr;
}
例
#include <sys/signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
void handler(int signo, siginfo_t *si ,void *context)
{
printf("%d/n", si->si_value.sival_int);
}
int main()
{
sigset_t mask;
sigset_t oldmask;
struct sigaction act;
int me = getpid();
union sigval val;
act.sa_sigaction = handler;
act.sa_mask = mask;
act.sa_flags = SA_SIGINFO;
sigaction(SIGRTMIN, &act, NULL);
sigemptyset(&mask);
sigaddset(&mask, SIGRTMIN);
sigprocmask(SIG_BLOCK, &mask, &oldmask);
val.sival_int = 1;
sigqueue(we, SIGRTMIN, val);
val.sival_int++;
sigqueue(we, SIGRTMIN, val);
val.sival_int++;
sigqueue(we, SIGRTMIN, val);
sigprocmask(SIG_SETMASK, &oldmask, NULL);
return 0;
}