CSAPP的shelllab

做了csapp的shelllab,最开始真的是一点思路都没有。

1、要认真看给的文档,我是用谷歌翻译然后再中英文对照着看(不翻译我看的太慢,不中英对照看的会更蒙)。
2、要把书上的代码看懂。

我参考的文章,跟着一步一步做

做的时候对waitfg、还有3个处理函数很困惑。

1、
``void waitfg(pid_t pid)
{
while(fgpid(jobs))
{
sleep(0);
}
return;
}`
当子进程是前台进程,父进程tsh必须等到子进程完成后才能重新输入命令行(可以用ctrl+c、ctrl+z打断),父进程怎么接受到子进程完成这个消息?子进程是前台进程,子进程完成,说明前台进程就没有了,fgpid(jobs)函数刚好返回就是前台进程的pid,没有就返回0。

子进程完成后就会发送一个SIGCHLD信号给父进程tsh,父进程调用sigchld_handler处理函数,就用waitpid函数回收进程,同时删除jobs数组中的子进程。

2、`void sigint_handler(int sig)
{
pid_t pid;

pid = fgpid(jobs);
if(pid!=0)
{   
    kill(-pid,sig);
}
return;

}

tsh这个简单shell它是运行在shell上,当键入ctrl+c,内核会发送一个SIGINT给前台进程,运行tsh,shell的前台进程就是tsh,tsh就会收到SIGINT信号后,就运行sigint_handler处理函数,就把SIGINT信号发送给在tsh上运行的前台程序,所以用kill(-pid,sig)发送给前台进程组。

加pid !=0这个判断,是因为当tsh上没有运行前台进程,pid的值就是0,表明当前运行的是父进程tsh,更真正的shell一样,键入ctrl+c不会发生任何事,只会另起一行 user >。如果不加pid !=0,当在shell上./tsh后,键入ctrl+c会停在那,原因不知道?就好像是通过处理函数sigint_handler自己给自己发了个终止信号。

我的代码

void eval(char *cmdline) 
{
    sigset_t mask,prev_mask;
    
    char *argv[MAXARGS];
    int argc;
    char buf[MAXLINE];
    int bg;
    pid_t pid;
    strcpy(buf,cmdline);
    bg=parseline(buf,argv,&argc);
    
    if(argv[0]==NULL)
        return;
    if(!builtin_cmd(argv,argc))
    {
        //fork前要诸塞信号
        sigemptyset(&mask);
        sigfillset(&mask);
        sigprocmask(SIG_BLOCK,&mask,&prev_mask);

        if((pid=fork())==0)
        {
            sigprocmask(SIG_SETMASK,&prev_mask,NULL);
            setpgid(0,0);
            if(execve(argv[0],argv,environ)<0)
            {
                printf("%s :Command not found.\n",argv[0]);
                return;
            }
        }
        if(!bg)
        {
            addjob(jobs,pid,FG,cmdline);
            sigprocmask(SIG_SETMASK,&prev_mask,NULL);
            waitfg(pid);
        }
        else
        {
            addjob(jobs,pid,BG,cmdline);
            sigprocmask(SIG_SETMASK,&prev_mask,NULL);
            printf("[%d] (%d) %s",pid2jid(pid),pid,cmdline);
        }
    }
    return;
}

/* 
 * parseline - Parse the command line and build the argv array.
 * 
 * Characters enclosed in single quotes are treated as a single
 * argument.  Return true if the user has requested a BG job, false if
 * the user has requested a FG job.  
 */
int parseline(const char *cmdline, char **argv,int *a) 
{
    static char array[MAXLINE]; /* holds local copy of command line */
    char *buf = array;          /* ptr that traverses command line */
    char *delim;                /* points to first space delimiter */              
    int bg;                     /* background job? */

    strcpy(buf, cmdline);
    buf[strlen(buf)-1] = ' ';  /* replace trailing '\n' with space */
    while (*buf && (*buf == ' ')) /* ignore leading spaces */
	buf++;

    /* Build the argv list */
    int argc = 0;
    if (*buf == '\'') {
	buf++;
	delim = strchr(buf, '\'');
    }
    else {
	delim = strchr(buf, ' ');
    }

    while (delim) {
	argv[argc++] = buf;
	*delim = '\0';
	buf = delim + 1;
	while (*buf && (*buf == ' ')) /* ignore spaces */
	       buf++;

	if (*buf == '\'') {
	    buf++;
	    delim = strchr(buf, '\'');
	}
	else {
	    delim = strchr(buf, ' ');
	}
    }
    argv[argc] = NULL;
    
    if (argc == 0)  /* ignore blank line */
	return 1;

    /* should the job run in the background? */
    if ((bg = (*argv[argc-1] == '&')) != 0) {
	argv[--argc] = NULL;
    }
    *a=argc;
    return bg;
}

/* 
 * builtin_cmd - If the user has typed a built-in command then execute
 *    it immediately.  
 */
int builtin_cmd(char **argv,int argc) 
{
    if(!strcmp(argv[0],"quit"))
    {
        exit(0);
    }
    if(!strcmp(argv[0],"jobs"))
    {
        listjobs(jobs);
        return 1;
    }
    if(!strcmp(argv[0],"bg")||!strcmp(argv[0],"fg"))
    {
        do_bgfg(argv,argc);
        return 1;
    }
    return 0;     /* not a builtin command */
}

/* 
 * do_bgfg - Execute the builtin bg and fg commands
 */
void do_bgfg(char **argv,int argc) 
{
    if(argc!=2)
    {
        printf("%s command requires PID or %%jobid argument\n",argv[0]);
        fflush(stdout);
        return;
    }
    pid_t pid;
    int jid;
    struct job_t*cur_job;
    char *cmd=argv[1];
    if(cmd[0]=='%')
    {
        jid=atoi(&cmd[1]);
        //atoi函数只要字符串不是整数,就返回0
        if(jid==0&&strcmp(&cmd[1],"0"))
        {
            printf("%s argument must be a PID or %%jobid\n",argv[0]);
            fflush(stdout);
            return;
        }
        cur_job=getjobjid(jobs,jid);
        if(cur_job==NULL)
        {
            printf("%%%d No such job\n",jid);
            fflush(stdout);
            return;
        }
        pid=cur_job->pid;
    }
    else
    {
        pid=atoi(&cmd[1]);
        if(pid==0&&strcmp(&cmd[1],"0"))
        {
            printf("%s argument must be a PID or %%jobid\n",argv[0]);
            fflush(stdout);
            return;
        }
        cur_job=getjobpid(jobs,pid);
        if(cur_job==NULL)
        {
            printf("(%d) No such process\n",pid);
            fflush(stdout);
            return;
        }
    }
    kill(-pid,SIGCONT);
    if(!strcmp(argv[0],"bg"))
    {
        
        cur_job->state=BG;
        printf("[%d] (%d) %s",pid2jid(pid),pid,cur_job->cmdline);
        fflush(stdout);
    }
    else
    {
        cur_job->state=FG;
        printf("[%d] (%d) %s",pid2jid(pid),pid,cur_job->cmdline);
        fflush(stdout);
        waitfg(pid);
    }
    
    return;
}

/* 
 * waitfg - Block until process pid is no longer the foreground process
 */
void waitfg(pid_t pid)
{
    while(fgpid(jobs))
    {
        sleep(0);
    }
    return;
}

/*****************
 * Signal handlers
 *****************/

/* 
 * 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) 
{
    int olderrno=errno;
    int status;
    sigset_t mask_all,prev_all;
    pid_t pid;
    sigfillset(&mask_all);
    while((pid=waitpid(-1,&status,WNOHANG|WUNTRACED))>0)
    {
        sigprocmask(SIG_BLOCK,&mask_all,&prev_all);
        if(WIFEXITED(status)){
            deletejob(jobs,pid);
        }
        else if(WIFSTOPPED(status))
        {
            getjobpid(jobs,pid)->state=ST;
            printf("Job [%d] [%d] stopped by signal %d\n",pid2jid(pid),pid,WSTOPSIG(status));
        }
        else if(WIFSIGNALED(status))
        {
            printf("Job [%d] [%d] terminated by signal %d\n",pid2jid(pid),pid,WTERMSIG(status));
            deletejob(jobs,pid);
        }
        sigprocmask(SIG_SETMASK,&prev_all,NULL);
    }
    
    errno=olderrno;
    return;
}

/* 
 * 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;
    
    pid = fgpid(jobs);
    if(pid!=0)
    {
        kill(-pid,sig);
    }
    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 fg_pid = fgpid(jobs);
    if(fg_pid!=0)
    {
        kill(-fg_pid,sig);
    }
    return;
}

在测试trace14和15的时候,总会多打一些。不知道为什么

./sdriver.pl -t trace14.txt -s ./tsh -a “-p”

trace14.txt - Simple error handling

tsh> ./bogus
./bogus :Command not found.
tsh> ./myspin 4 &
[1] (10101) ./myspin 4 &
tsh> fg
fg command requires PID or %jobid argument
tsh> bg
bg command requires PID or %jobid argument
tsh> fg a
fg argument must be a PID or %jobid
tsh> bg a
bg argument must be a PID or %jobid
tsh> fg 9999999
(999999) No such process
tsh> bg 9999999
(999999) No such process
tsh> fg %2
%2 No such job
tsh> fg %1
[1] (10101) ./myspin 4 &
Job [1] [10101] stopped by signal 20
tsh> bg %2
%2 No such job
tsh> bg %1
[1] (10101) ./myspin 4 &
tsh> jobs
[1] (10101) Running ./myspin 4 &
tsh> ./myspin 4 &
[1] (10114) ./myspin 4 &
tsh> fg
fg command requires PID or %jobid argument
tsh> bg
bg command requires PID or %jobid argument
tsh> fg a
fg argument must be a PID or %jobid
tsh> bg a
bg argument must be a PID or %jobid
tsh> fg 9999999
(999999) No such process
tsh> bg 9999999
(999999) No such process
tsh> fg %2
%2 No such job
tsh> fg %1
[1] (10114) ./myspin 4 &入代码片`

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值