MSH:一个简单SH工具实现
Part1Part1 目标
命令求值函数/* * eval - Evaluate the command line that the user has just typed in * * If the user has requested a built-in command (quit,jobs,bg or fg) * then execute it immediately. Otherwise,fork a child process and * run the job in the context of the child. If the job is running in * the foreground,wait for it to terminate and then return. Note: * each child process must have a unique process group ID so that our * background children don't receive SIGINT (SIGTSTP) from the kernel * when we type ctrl-c (ctrl-z) at the keyboard. */
void eval(char *cmdline) {
char *argv[MAXARGS];
int bg;
pid_t pid;
sigset_t mask;
bg = parseline(cmdline,argv);
if(argv[0] == NULL)
return ;
if(!builtin_cmd(argv)){
sigemptyset(&mask);
sigaddset(&mask,SIGCHLD);
sigaddset(&mask,SIGINT);
sigaddset(&mask,SIGTSTP);
sigprocmask(SIG_BLOCK,&mask,NULL);
/* child proc */
if((pid = Fork()) == 0){
setpgid(0,0);
if(verbose){
pid = getpid();
printf("Child proc started with pid %dn",(int)pid);
}
sigprocmask(SIG_UNBLOCK,NULL);
if(execve(argv[0],argv,environ)<0){
printf("%s: Command not found.n",argv[0]);
exit(0);
}
}
/* parent proc */
else{
addjob(jobs,pid,bg?BG:FG,cmdline);
sigprocmask(SIG_UNBLOCK,NULL);
if(!bg){
/* Use waitfg to wait until proc(pid) is no longer a frontgroud proc. */
waitfg(pid);
}
else{
printf("[%d] (%d) %s",pid2jid(pid),cmdline);
}
}
}
return ;
}
在第一阶段的目标下,不需要在课本的基础上改多少内容,一个是对于前台的子进程不再使用 前台阻塞处理对于前台,最初实现是直接 发现其提供了 void waitfg(pid_t pid){
struct job_t *cur = getjobpid(jobs,pid);
while(cur != NULL && cur->state == FG){
cur = getjobpid(jobs,pid);
}
/* 2 cases: BG : switch to BG from FG NULL : delete from jobs */
return;
}
性能不佳,且不够优雅。每次都观察前台的 void waitfg(pid_t pid){
while(pid == fgpid(jobs))
pause();
return;
}
这样就优雅多了。 回收僵死进程需要使用 /* * sigchld_handler - The kernel sends a SIGCHLD to the shell whenever * a child job terminates (becomes a zombie),or stops because it * received a SIGSTOP or SIGTSTP signal. The handler reaps all * available zombie children,but doesn't wait for any other * currently running children to terminate. */
void sigchld_handler(int sig) {
pid_t pid;
int status;
struct job_t *job;
while((pid = waitpid(-1,&status,WNOHANG | WUNTRACED))>0){
if(WIFEXITED(status)){ /*process is exited in normal way*/
if(verbose)
printf("Job [%d] (%d) terminated normally with exit status %dn",WEXITSTATUS(status));
deletejob(jobs,pid);
}
else if(WIFSTOPPED(status)){/*process is stop because of a signal*/
printf("Job [%d] (%d) stopped by signal %dn",WSTOPSIG(status));
job = getjobpid(jobs,pid);
if(job !=NULL) job->state = ST;
}
else if(WIFSIGNALED(status)){/*process is terminated by a signal*/
printf("Job [%d] (%d) terminated by signal %dn",WTERMSIG(status));
deletejob(jobs,pid);
}
}
return;
}
其中要注意的是,如果使用了 利用
内嵌功能实现默认 /* * builtin_cmd - If the user has typed a built-in command then execute * it immediately. */
int builtin_cmd(char **argv) {
if(!strcmp(argv[0],"quit") || !strcmp( argv[0],"exit"))
exit(0);
if(!strcmp(argv[0],"jobs")){
listjobs(jobs);
return 1;
}
return 0; /* not a builtin command */
}
至此,可以通过 Part2Part2 目标
支持对前台的终止与暂停操作对 /* * sigint_handler - The kernel sends a SIGINT to the shell whenver the * user types ctrl-c at the keyboard. Catch it and send it along * to the foreground job. */
void sigint_handler(int sig){
pid_t pid = fgpid(jobs);
if(pid) kill(-pid,SIGINT);
return;
}
/* * sigtstp_handler - The kernel sends a SIGTSTP to the shell whenever * the user types ctrl-z at the keyboard. Catch it and suspend the * foreground job by sending it a SIGTSTP. */
void sigtstp_handler(int sig){
pid_t pid = fgpid(jobs);
if(pid) kill(-pid,SIGTSTP);
return;
}
添加这两个处理函数后, BG与FG功能实现从 /* jid2pid - Map job ID to process ID */
pid_t jid2pid(int jid){
if(jid>=MAXJID || jid <= 0) return 0;
return jobs[jid-1].pid;
}
因为 /* * do_bgfg - Execute the builtin bg and fg commands */
void do_bgfg(char **argv){
pid_t pid;
int jid;
struct job_t *job;
if(argv[1]== NULL){
printf("fg command requires PID or %%jobid argumentn");
return;
}
/* parse arg */
if(argv[1][0] == '%'){
/* JID */
jid = atoi(argv[1]+1);
if(jid == 0 && argv[1][1] != '0'){
/* Not number */
printf("fg command requires PID or %%jobid argumentn");
return;
}
if(!(pid=jid2pid(jid))){
/* JID not exits */
printf("%%%d: No such jobn",jid);
return;
}
}
else{
/* PID */
pid = atoi(argv[1]);
if(pid == 0 && argv[1][0] != '0'){
/* Not number */
printf("fg command requires PID or %%jobid argumentn");
return;
}
if(!(jid = pid2jid(pid))) {
printf("(%d): No such processn",pid);
return;
}
}
job = getjobjid(jobs,jid);
if(!strcmp(argv[0],"bg")){
/* bg function * The bg <job> command restarts <job> by sending it a SIGCONT signal,* and then runs it in the background. * The <job> argument can be either a PID or a JID. */
job->state = BG;
kill(-pid,SIGCONT);
printf("[%d] (%d) %s",jid,job->cmdline);
}
else{
/* fg function * The fg <job> command restarts <job> by sending it a SIGCONT signal,* and then runs it in the foreground. * The <job> argument can be either a PID or a JID. */
job->state = FG;
kill(-pid,SIGCONT);
waitfg(pid);
}
return;
}
添加这两个处理函数后,所有的 Part3Part3目标
|
- scala – 在Windows 7上运行spark-submit后无法删除临时文件
- Scala构造函数参数修饰符
- 初探Angular6.x---主从组件
- QT-窗口打印debug信息,本地日志保存,以及执行shell脚本并
- WebService开发实例 (Xfire+Spring+Hibernate)
- WebService系列博客{六}[Tcpmon的应用]
- bash – 今天的日期,减去X天的shell脚本
- angularjs – 拒绝显示在一个帧,因为它设置’X帧选项’到’
- twitter-bootstrap – 无法在twitter bootstrap中调用未定义
- 在bash中对变量进行多个正则表达式替换?