ch04:信号处理

来源:互联网 发布:野蛮人之王升级数据 编辑:程序博客网 时间:2024/06/10 07:48
 
第四讲 信号处理
信号是进程间通信的最简单形式
信号的生命周期
简单信号
#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, &currentSet);
 
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;
}