第四講 訊號處理訊號是處理序間通訊的最簡單形式訊號的生命週期簡單訊號#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_SETMASKsigprocmask(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_ACCERRSIGBUS BUS_ADDRALN BUS_ADDERR BUS_OBJERRSIGCHLD 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;}