ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

CSAPP--ShellLab

2021-11-27 10:31:57  阅读:156  来源: 互联网

标签:CSAPP return -- pid jid argv job jobs ShellLab


ShellLab

一、 Lab介绍

CSAPP的ShellLab是实现一个自己的shell程序,完成之后可以熟练掌握UNIX关于进程的系统调用(例如fork、waitpid等),熟悉Linux的信号机制,而且这个Lab非常有趣。

二、 Lab实现

实现这个Lab主要是完成以下几个函数的编写:
在这里插入图片描述

eval实现

void eval(char *cmdline) 
{
    char *argv[MAXARGS];
    char buf[MAXLINE];
    int bg; // Should the job run in bg or fg
    pid_t pid;
    sigset_t mask_all,mask_one,prev_mask;
    
    strcpy(buf,cmdline);
    
    bg = parseline(buf,argv);
    
    if( argv[0] == NULL ){
        return; // Ignore empty lines
    }
    
    if( !builtin_cmd(argv) ){
        
        sigemptyset(&mask_one);
        sigfillset(&mask_all);
        sigaddset(&mask_one,SIGCHLD);
        
        // 父进程在创建子进程时,不要响应子进程结束中断,故添加SIGCHLD到阻塞队列
        sigprocmask(SIG_BLOCK,&mask_one,&prev_mask);
        if( (pid = fork()) == 0 ){ // Child process
            // 将子进程单独放入一个进程组里面,否则在删除job的时候可能删除shell进程的别的子进程
            setpgid(0, 0);
            // 取消阻塞,这一步非常关键,因为子进程继承了父进程的阻塞队列,故应该将子进程的阻塞队列清空
            sigprocmask(SIG_SETMASK,&prev_mask,NULL);
            if( execve(argv[0],argv,environ) < 0 ){
                printf("%s: Command not found.\n",argv[0]);
                exit(1);
            }
        }
        
        // 给 addjob 加锁,保证原子操作(因为jobs是一个全局变量,而有些中断的处理器也会对jobs进行操作,这样就不安全了)
        sigprocmask(SIG_BLOCK,&mask_all,NULL);
        addjob(jobs,pid,bg ? BG : FG,cmdline);
        sigprocmask(SIG_SETMASK,&prev_mask,NULL);
        
        // Parent process waits for foreground job to terminate
        if( !bg ){
            
            waitfg(pid);
            
        }else {
            
            printf("[%d] (%d) %s",pid2jid(pid),pid,cmdline);
            
        }
    }
    
    return;
}

buildin_cmd实现

int builtin_cmd(char **argv) 
{
    if( !strcmp(argv[0],"quit") ){
        kill(getpid(),SIGQUIT);
        return 1;
    }else if( !strcmp(argv[0],"jobs") ){
        listjobs(jobs);
        return 1;
    }else if( !strcmp(argv[0],"&") ){
        return 1;
    }else if( !strcmp(argv[0],"bg") || !strcmp(argv[0],"fg") ){
        do_bgfg(argv);
        return 1;
    }
    return 0;     /* not a builtin command */
}

do_bgfg实现

void do_bgfg(char **argv) 
{
    struct job_t* job;
    char* flag;
    int jid;
    pid_t pid;
    
    flag = argv[1];
    
    if( flag == NULL ){
        printf("%s command requires PID or %%jobid argument",argv[0]);
        return;
    }
    
    // if it is a jid
    if( flag[0] == '%' ){
        jid = atoi(&flag[1]);
        job = getjobjid(jobs,jid);
        if( job == NULL ){
            printf("(%s)No such job\n",flag);
            return;
        }else{
            // get the pid if a valid job for later to kill
            pid = job->pid;
        }
    }else if(isdigit(flag[0])){ // if it is a pid
        pid = atoi(flag);
        // get jid
        jid = pid2jid(pid);
        // get job
        job = getjobjid(jobs,jid);
        if( job == NULL ){
            printf("(%d)No such process\n",pid);
            return;
        }
    }else{
        printf("%s: argument must be a PID or %%jobid\n",argv[0]);
        return;
    }
    
    // kill for each time
    kill(-pid,SIGCONT);
    
    if( !strcmp("fg",argv[0]) ){
        // wait for fg
        job->state = FG;
        waitfg(job->pid);
    }else{
        // print for bg
        printf("[%d] (%d) %s\n",job->jid,job->pid,job->cmdline);
        job->state = BG;
    }
    
}

waitfg实现

void waitfg(pid_t pid)
{
    struct job_t* job = getjobpid(jobs,pid);
    
    if( job == NULL ){
        return;
    }
    
    while( pid == fgpid(jobs) ){ // spin
        sleep(1);
    }
}

sigchld_handler实现

void sigchld_handler(int sig) 
{
    int old_errno = errno;
    
    pid_t pid;
    int status;
    
    while( (pid = waitpid(-1,&status,WNOHANG | WUNTRACED)) > 0 ){ // 因为上面提示信息说明不要等待任何子进程终止,所以这里 options 使用 WNOHANG | WUNTRACED
        // enter here means that one of child has changed status
        if( WIFEXITED(status) ){ // exit normally or call exit(0) or call exit(1)
            // delete terminated child
            deletejob(jobs,pid);
            
        }else if( WIFSIGNALED(status) ){ // terminated by received a signal
            
            int jid = pid2jid(pid);
            
            printf("Job [%d] (%d) terminated by signal %d\n",jid,pid,WTERMSIG(status));
            
            deletejob(jobs,pid);
            
        }else if( WIFSTOPPED(status) ){ // stop
        
            struct job_t* job = getjobpid(jobs,pid);
            
            job->state = ST;
        
            int jid = pid2jid(pid);
            
            printf("Job [%d] (%d) stopped by signal %d\n",jid,pid,WSTOPSIG(status));
            
        }
        
    }
    
    
    errno = old_errno;
    return;
}

sigint_handler实现

void sigint_handler(int sig) 
{
    int old_errno = errno;
    pid_t pid = fgpid(jobs);
    
    if( pid == 0 ){
        return;
    }
    
    kill(-pid,sig);
    
    errno = old_errno;
}

sigstp_handler实现

void sigtstp_handler(int sig) 
{
    int old_errno = errno;
    pid_t pid = fgpid(jobs);
    
    if( pid == 0 ){
        return;
    }
    
    kill(-pid,sig);
    errno = old_errno;
}

标签:CSAPP,return,--,pid,jid,argv,job,jobs,ShellLab
来源: https://blog.csdn.net/MAIHCBOY/article/details/121572879

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有