信号处理(unix操作系统系)---5
信号处理
一.实验目的
本实验要求利用可靠信号机制解决信号处理时可能出现的时间窗口,以及非局部转移等问题,将学习使用sigaction,alarm,sigpending,sigsetjmp和siglongjmp等函数解决在处理信号时遇到的问题。
二.实验设计
我们可以直接利用系统shell(在cs8是bash):execl(“/bin/sh”, “sh”, “-c”, buf, (char *) 0); 这样程序sigtest就具有系统shell的全部功能。
需要处理的信号:因为需要使用闹钟,所以实验需要处理两个信号:SIGALRM和SIGQUIT。如果当前程序正在执行用户命令,则信号处理函数必须“杀死”用户命令进程:kill(pid, SIGKILL); // pid为用户命令进程的ID。
对于信号SIGQUIT还有一种可能:正在接收用户输入的命令串。此时需要放弃当前输入,重新开始接收输入。解决方法可能需要使用非局部转移机制。
三.源代码
#include "apue.h" #include <sys/wait.h> #include <setjmp.h> #include <unistd.h> #include <signal.h> static void sig_int(int); /* our signal-catching function */ static void sig_alrm(int); static volatile pid_t pid; static sigjmp_buf jmpbuf; Sigfunc * signal(int signo , Sigfunc *func) { struct sigaction act,oact; act.sa_handler = func; sigemptyset (& act.sa_mask); act.sa_flags = 0; if (signo == SIGALRM) sigaddset (& act.sa_mask,SIGQUIT); act.sa_flags |=SA_RESTART; if (sigaction(signo , &act,&oact)<0) return (SIG_ERR); return (oact.sa_handler); } int main(int argc,char *argv[]) { char buf[MAXLINE]; /* from apue.h */ int status,time,flag=0; if (argc >=3){ flag=1; time=atoi(argv[2]); } if (signal(SIGQUIT, sig_int) == SIG_ERR) err_sys("signal error"); if (signal(SIGALRM, sig_alrm) == SIG_ERR) err_sys("signal error"); sigsetjmp(jmpbuf,1); printf("%% "); /* print prompt (printf requires %% to print %) */ if (flag) alarm(time); while (fgets(buf, MAXLINE, stdin) != NULL) { if (buf[strlen(buf) - 1] == '\n') buf[strlen(buf) - 1] = 0; /* replace newline with null */ if ((pid = fork()) < 0) { err_sys("fork error"); } else if (pid == 0) { /* child */ execl("/bin/sh","sh","-c",buf,(char *)0); err_ret("couldn't execute: %s", buf); exit(127); } /* parent */ waitpid(pid, &status, 0); pid =0; alarm(0); printf("%% "); } exit(0); } void sig_int(int signo) { sigset_t pendmask; if (pid >0){ kill(pid,SIGKILL); // waitpid (pid,NULL,0); } else{ printf ("\n"); printf ("interrupt\n"); siglongjmp (jmpbuf,1); } if (sigpending(&pendmask)<0) err_sys("sigpending error"); if (sigismember(&pendmask,SIGALRM)){ signal(SIGALRM,SIG_IGN); signal(SIGALRM,sig_alrm); } } void sig_alrm(int signo) { printf("TIME OUT!\n"); sigset_t pendmask; if (pid >0){ kill(pid,SIGKILL); } if (sigpending(&pendmask)<0) err_sys("sigpending error"); if (sigismember(&pendmask,SIGQUIT)){ signal(SIGQUIT,SIG_IGN); signal(SIGQUIT,sig_int); } siglongjmp (jmpbuf,1); }
四.运行结果