- 2
- 0
- 约4.39千字
- 约 6页
- 2020-10-05 发布于浙江
- 举报
实验五 信号处理
实验目的
学习和掌握信号的处理方法,特别是sigaction,alarm,sigpending,sigsetjmp和siglongjmp等函数的使用。
实验要求
1、编制具有简单执行时间限制功能的shell:
myshell [ -t time ]
这个测试程序的功能类似实验1,但是具有系统shell (在cs8服务器上是bash)的全部功能。time是测试程序允许用户命令执行的时间限制,默认值为无限制。当用户命令的执行时间限制到达时,测试程序终止用户命令的执行,转而接收下一个用户命令。
2、myshell只在前台运行。
3、按Ctrl-\键不是中断myshell程序的运行,而是中断当前用户命令的接收或终止当前用户命令的执行,转而接收下一个用户命令。
4、注意信号SIGALRM和SIGQUIT之间嵌套关系的处理。
实验分析
1、shell功能实现
可以直接利用系统shell(在cs8是bash):
execl(“/bin/sh”, “sh”, “-c”, buf, (char *) 0);
这样程序sigtest就具有系统shell的全部功能。如果命令带“-t”选项,则在创建执行上面函数的子进程之前,必须设置闹钟;在子进程结束之后,必须将闹钟清零。
因为需要使用闹钟,所以实验需要处理两个信号:SIGALRM和SIGQUIT。如果当前程序正在执行用户命令,则信号处理函数必须“杀死”用户命令进程:
kill(pid, SIGKILL); // pid为用户命令进程的ID
对于信号SIGQUIT还有一种可能:正在接收用户输入的命令串。此时需要放弃当前输入,重新开始接收输入。解决方法可能需要使用非局部转移机制。
2、信号SIGALRM和SIGQUIT之间嵌套关系的处理:
由于如果同时存在多个未决信号,系统总是一个信号处理完之后再处理下一个信号,但是在处理完全部未决信号之前,不会返回被中断的函数或系统调用。因此,无论SIGALRM和SIGQUIT这两个信号哪个先处理,另一个未决信号就应该忽略(清除未决信号);在处理其中一个信号时,屏蔽另一个信号(如果发生,就是未决信号)。
static volatile pid_t pid; // 全局变量,存放执行用户命令的子进程的ID,
// 非0表正在执行用户命令
设置信号SIGALRM处理方式的代码(供参考):
struct sigaction act, oact;
act.sahandler = func; // 信号SIGALRM的处理函数
sigemptyset(act.sa_mask);
act.sa_mask |= SIGQUIT; // 在处理信号SIGALRM时,屏蔽信号SIGQUIT
act.sa_flags = 0;
#ifdef SA_RESTART // 如果定义了该常量,则系统默认不重启,应改为重启
act.sa_flags |= SA_RESTART;
#endif
sigaction(SIGALRM, act, oact);
信号SIGQUIT处理函数的末尾应该包含如下代码段(供参考):
sigset_t pendmask;
sigemptyset(pendmask);
sigpending(pendmask); // 获得未决信号集合
pid = 0; // 表示当前无正在执行的用户命令
alarm(0); // 清除闹钟
if(sigismember(pendmask, SIGALRM)) { // 存在未决信号SIGALRM
signal(SIGALRM, SIG_IGN); // 清除未决信号SIGALRM
sigaction(SIGALRM, act, NULL); // 恢复原来的处理方法
}
实验程序
#include apue.h
#include sys/wait.h
#include setjmp.h
#include unistd.h
static volatile pid_t pid; //存放执行用户命令的子进程的ID
static sigjmp_buf jmpbuf;
static void sig_alrm(int signo);
static void sig_quit(int signo);
char buf[MAXLINE];
Sigfunc *signal(int signo, Sigfunc *func){
struct sigaction act, oact;
act.sa_handler = func;
sigemptyset( act.sa_mask);
act.sa_flags = 0;
/* 处理一个信号时,屏蔽另一个信号 */
if(signo =
原创力文档

文档评论(0)