ICS shell lab总结

来源:互联网 发布:刺客信条mac版 编辑:程序博客网 时间:2024/05/15 11:56

ICS shell lab总结

lab简介

本lab的目的是实现一个支持基本shell功能和I/O重定向功能但不支持管道功能的tsh(tiny shell),本lab中基本框架已经拉好,只要实现以下功能即可。
eval():对外壳命令行求值
handler():分别对SIGINT,SIGCHLD,SIGTSTP处理。
本lab只需要通过24个trace测试点即可

eval()实现思路

eval()在CSAPP课本里面有一个naive版本,基本包括了主要功能框架。但是注意课本里和lab里面用的数据结构不完全一样,而且lab里面没有分割各个函数模块。
而且lab中要做好I/O处理和信号避免冒险的处理工作。
既然是总结,我就不重复代码了,我写一下伪代码,伪代码很紧凑,会意即可。

void eval(tok) {    bg=parseline(buf,argv);//需要一个buf,因为praseline会改变cmdline    deal_io();//处理I/O    block_sig();//堵塞信号以防冒险    if (builtin_cmd==true) {        if (strcmp(cmd,"QUIT")==0) {            deal_io();//退出前处理I/O            exit(0);        }        else {} //实现其他builtin功能    }    else {        if ((pid=fork())==0) { //child            setgpid();//另立进程组以防与父进程被一个Ctrl C同时打断            unblock_sig();//解信号阻塞            execve();//执行        }        else { //parent            addjob();//加入工作列表            unblock_sig();            /*加入后才解信号阻塞以防冒险,不然会把一个已经回收的job加入list*/            if (!bg) //fg                while (pid==fgpid());//注意这个条件            else //bg                print_info();        }    }    deal_io();//退出前处理I/O    return; }

handler()实现思路

处理SIGCHLD比较复杂,因为要考虑打印子进程信息和deletejob()的问题。注意deletejob()必须要在父进程addjob()之后,那么为了实现这一点就必须在父进程内阻塞信号。
另外,handler()内的打印函数要使用sio_I/O,因为 sio _I/O没有格式输出,虽然麻烦了点。但是一个比较好的方法是先把格式输出要printf的打印到buf内再sio _puts(),当然不这样sio _puts()和sio _putl换着来也可以。
至于另外两个信号,只需要处理前台进程给其手动发信号即可,千万不要把shell自己弄暂停了。

几个疑难问题探讨

1.如何等待前台进程运行

常见的错误用法是waitpid(),不管参数是什么都有一个问题,就是企图回收前台进程,但是如果前台进程被暂停或者改成后台了呢?
所以要用上面伪代码中的实现。

2.如何处理Unix I/O

用dup2重定向标准输出,唯一注意的是返回主程序前记得恢复被破坏的STDIN_FILENO,STDOUT _FILENO。不然会导致main()函数内打印出现错误,通不过某个trace测试(似乎是trace 20+?)。

3.如何满足lab安全性检查的要求

1.sig_handler()内是异步不安全的,所以要注意使用sio _I/O,见handler()讨论。
2.每一个系统调用函数都需要检查是否成功运行,运行失败返回对应信息。返回对应消息使用unix_error()完成,风格与课本保持了一致。有一些trace会检查系统函数返回值错误情况,因为代码已经把STDERR重定向到STDOUT,所以这样任然有效,不必要用printf打印,不然感觉很怪。
3.每一个系统调用函数都需要检查是否成功运行,运行失败返回对应信息。必然会使得主要函数代码及其冗长,所以模仿课本风格,使用带错误检查的包装函数Func()保证系统函数func(),十分优雅的处理。

0 0