Exemple #1
0
/*
 * 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)
{
    int bg;              /* should the job run in bg or fg? */
    struct cmdline_tokens tok;
    sigset_t prev, mask_all;
    int state;
    pid_t pid;
    struct job_t *job_ins;

    /* Parse command line */
    bg = parseline(cmdline, &tok);

    if (bg == -1) /* parsing error */
        return;
    if (tok.argv[0] == NULL) /* ignore empty lines */
        return;

    /* Fig. 8.40 */
    if (!builtin_command(&tok)) {
        Sigemptyset(&mask_all);
        Sigaddset(&mask_all, SIGCHLD);
        Sigaddset(&mask_all, SIGINT);
        Sigaddset(&mask_all, SIGTSTP);
        Sigprocmask(SIG_BLOCK, &mask_all, &prev); /* Block at beginning */

        if ((pid = Fork()) == 0) { /* Child process */
            Sigprocmask(SIG_SETMASK, &prev, NULL); /* Unblock inside child */
	    Setpgid(0, 0); /* one proc and shell in pgrp */

	    open_dup2_in(tok.infile);
	    open_dup2_out(tok.outfile);
	    if (execve(tok.argv[0], tok.argv, environ) < 0) {
	        printf("%s: Command not found.\n", tok.argv[0]);
	        exit(0);
	    }
	}

        /* Parent process */

        state = bg ? BG : FG;
        addjob(job_list, pid, state, cmdline);
        job_ins = getjobpid(job_list, pid);

        Sigprocmask(SIG_SETMASK, &prev, NULL); /* Unblock 3 signals */

        if (bg) {
            printf("[%d] (%d) %s", pid2jid(pid), pid, cmdline);
        } else {
            wait_fg_job(job_ins -> state);
        }
    }

    return;
}
/* 
 * 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]; /* Argument list execve() */
    char buf[MAXLINE];   /* Holds modified command line */
    int bg;              /* Should the job run in bg or fg? */
    pid_t pid;           /* Process id */
    sigset_t mask;

    strcpy(buf, cmdline);
    bg = parseline(buf, argv);
    if (argv[0] == NULL) {
      return; /* Ignore empty lines */
    }

    if (!builtin_cmd(argv)) {
        /* Block SIGCHLD, SIGINT,	 
	and SIGSTP until the job to be run is on the list */
        Sigemptyset(&mask);
        Sigaddset(&mask, SIGCHLD);
        Sigaddset(&mask, SIGINT);
        Sigaddset(&mask, SIGTSTP);
        Sigprocmask(SIG_BLOCK, &mask, NULL); 

        if ((pid = Fork()) == 0) { /* Child runs user job */
            Setpgid(0, 0); // give the child a new group
            /* unblock signals for child */
            Sigprocmask(SIG_UNBLOCK, &mask, NULL); 
            if (execve(argv[0], argv, environ) < 0) {
                printf("%s: Command not found.\n", argv[0]);
                exit(0);
            }
        }

        addjob(jobs, pid, bg?BG:FG, cmdline);
        if (bg) {
            // Notify user that job is running in the background
            printf("[%i] (%i) %s", getjobpid(jobs, pid)->jid, pid, cmdline);
        }
	Sigprocmask(SIG_UNBLOCK, &mask, NULL); /* Unblock signals */

        if (!bg) {
            /* Parent waits for foreground job to terminate */
            waitfg(pid);
        }
    }

    return;
}
Exemple #3
0
/* 
 * 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];                                                        //arguments for execve()
    int bg;                                                                     //Determines whether the job will run in foreground or background
    pid_t pid;                                                                  //Contains the process id
    struct job_t *jd;
    sigset_t mask;                                                              //The signal set which has to be bloacked before adding the job to jobs

    bg = parseline(cmdline, argv);                                              //Copies contents of cmdline into argv and returns whether the job should run in background or foreground

    Sigemptyset(&mask);                                                         //Generate an empty signal set in mask
    Sigaddset(&mask, SIGCHLD);                                                  //Add SIGCHLD to the signal set to be blocked
    Sigaddset(&mask, SIGINT);                                                   //Add SIGINT to the signal set to be blocked
    Sigaddset(&mask, SIGTSTP);                                                  //Add SIGTSTP to the signal set to be blocked

    if(!builtin_cmd(argv)){                                                     //Checks whether command is built-in and executes it if yes, else enters if block
        Sigprocmask(SIG_BLOCK, &mask, NULL);                                    //Blocked the signal set
        if((pid = Fork()) == 0){                                                //Run user process in a child
            Sigprocmask(SIG_UNBLOCK, &mask, NULL);                              //Unblock the signal sets in child
            Setpgid(0,0);                                                       //New jobs should have new process ids else signal will kill shell also          
            if(execve(argv[0], argv, environ) < 0){                             //executes user command if successful
                printf("%s: Command not found.\n", argv[0]);                    //Throw error if execution unsuccessful
                exit(0);
            }
        }

        if(!bg){                                                                //If process is foreground, parent waits for the job to terminate
            addjob(jobs, pid, FG, cmdline);                                     //Add the process to jobs
            Sigprocmask(SIG_UNBLOCK, &mask, NULL);                              //Unblock the signal set afet adding the job
            waitfg(pid);                                                        //Parent waits for the foreground process to terminate}
        }

        else{                                                                   //If process is a background
            addjob(jobs, pid, BG, cmdline);                                     //Add the process to jobs
            Sigprocmask(SIG_UNBLOCK, &mask, NULL);                              //Unblock the signal set afet adding the job
            jd = getjobpid(jobs, pid);                                          //Get the jobpid
            printf("[%d] (%d) %s", jd->jid, jd->pid, jd->cmdline);              //Print the details of background job
        }
    }
    return;
}
Exemple #4
0
/*
 * 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;

    // will return 1 if background job
    bg = parseline(cmdline, argv);

    //Error checking for no input
    if (argv[0] == NULL){
      return;
    }

    if(!builtin_cmd(argv)){
      pid = fork();
      // child runs the current user job
      if(pid == 0){
        Setpgid(0,0); //CSAPP function

        //Checks to see if the argument is valid or not
        if(execve(argv[0], argv, environ) < 0){
          printf("%s: command is not found.\n", argv[0]);
          exit(0);
        }
      }

      // Parent waits for foreground to terminate before running
      if(!bg){
        //Foreground
        addjob(jobs, pid, FG, cmdline);
        waitfg(pid);
      } else {
        //Background
        addjob(jobs, pid, BG, cmdline);
        printf("[%d] (%d) %s",pid2jid(pid),pid,cmdline);
      }
    }

    return;
}
Exemple #5
0
/* 
 * 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) 
{
    int bg;              /* should the job run in bg or fg? */
    struct cmdline_tokens tok;
    pid_t pid;
    sigset_t mask;

    /* Parse command line */
    bg = parseline(cmdline, &tok); 

    if (bg == -1) return;               /* parsing error */
    if (tok.argv[0] == NULL)  return;   /* ignore empty lines */
    
    sigemptyset(&mask);
    sigaddset(&mask,SIGCHLD);
    sigaddset(&mask,SIGINT);
    sigaddset(&mask,SIGTSTP);
    sigprocmask(SIG_BLOCK,&mask,NULL);
    
    if(!builtin_handler(tok))
      {
	if((pid=Fork())==0)
	  {
	    /*restore default handlers*/
	    Signal(SIGINT,SIG_DFL);
	    Signal(SIGTSTP,SIG_DFL);
	    sigprocmask(SIG_UNBLOCK,&mask,NULL);
	    
	    /*Put child process in its own group*/
	    Setpgid(0,0);

	    IO_redirection(tok);
	      
	    Execve(tok.argv[0],tok.argv,environ);
	    
	  }
	else /*Shell Processing*/
	  {
	    if(bg)
	      {
		addjob(job_list,pid,BG,cmdline);
		printf("[%d] (%d) %s\n", pid2jid(pid), pid, cmdline);
		sigprocmask(SIG_UNBLOCK,&mask,NULL);
		
	      }
	    else
	      {
		addjob(job_list,pid,FG,cmdline);
		sigprocmask(SIG_UNBLOCK,&mask,NULL);
		while(fgpid(job_list) != 0)
		  {
		  }

		
	      }
	  }
      }

    


}
Exemple #6
0
/*
 * 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 (SIGSTP) from the kernel
 *    when we type ctrl-c (ctrl-z) at the keyboard.
 */
void eval(char *cmdline)
{
    char *argv[MAXARGS], buf[MAXLINE];
    int bg, status, state;
    volatile pid_t pid;
    int jid;
    sigset_t mask_all, mask_one, prev_one;

    Log("EVAL [0]\n", 9);

    strcpy(buf, cmdline);
    bg = parseline(buf, argv);

    if (argv[0] == NULL) {
        return;
    }

    Log("EVAL [1]\n", 9);

    if (builtin_cmd(argv)) {
        return;
    }

    Log("EVAL [2]\n", 9);

    Sigfillset(&mask_all);
    Sigemptyset(&mask_one);
    Sigaddset(&mask_one, SIGCHLD);

    Sigprocmask(SIG_BLOCK, &mask_one, &prev_one);

    pid = Fork();

    if (pid == CHILD) {
        Sigprocmask(SIG_SETMASK, &prev_one, NULL);
        Setpgid(0, 0);
        Log("EVAL [3]\n", 9);
        Execve(argv[0], argv, environ);
    }

    Sigprocmask(SIG_BLOCK, &mask_all, NULL);

    state = bg ? BG : FG;

    Log("EVAL [4]\n", 9);

    status = addjob(jobs, pid, state, cmdline);

    Log("EVAL [5]\n", 9);

    /* Stores jid while process has not been removed */
    jid = getjobpid(jobs, pid)->jid;

    atomic_fggpid = bg ? 0 : pid;

    Log("EVAL [5a]\n", 10);

    Sigprocmask(SIG_SETMASK, &prev_one, NULL);

    Log("EVAL [5b]\n", 10);

    /* Handle errors when generating a new job */
    if (!status) {
        return;
    }

    /* Parent waits for foreground job to terminate */
    if (!bg) {
        Log("EVAL [6]\n", 9);
        waitfg(pid);
    }
    else {
        Log("EVAL [7]\n", 9);
        printf("[%d] (%d) %s", jid, pid, cmdline);
    }
}
Exemple #7
0
/*
 * 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)
{
    int bg;              /* should the job run in bg or fg? */
    struct cmdline_tokens tok;

    /* Parse command line */
    bg = parseline(cmdline, &tok);
    if (bg == -1) return;               /* parsing error */
    if (tok.argv[0] == NULL)  return;   /* ignore empty lines */

    /* Built-in Command */
    if (tok.builtins!=BUILTIN_NONE){
      builtin_command(&tok);
      return;
      }

    /* Common tasks for both foreground and background */

    pid_t pid;
    sigset_t mask;
    Sigemptyset(&mask);
    Sigaddset(&mask, SIGCHLD);
    Sigaddset(&mask, SIGINT);
    Sigaddset(&mask, SIGTSTP);
    /* Block signal receving in parent */
    Sigprocmask(SIG_BLOCK, &mask, NULL);

    if ((pid=Fork())==0){
      /* Unblock signal receiving in child */
      Sigprocmask(SIG_UNBLOCK, &mask, NULL);
      /* Changes the child's process group from the shell's */
      Setpgid(0,0);

      /* Change the input and output file descriptors */
      IOredirection(&tok);

      Execve(tok.argv[0], tok.argv, environ);
      /* Command not found */
      printf("Executable file not found\n");
      exit(0);
    }

    /* Foreground job*/
    if (!bg){
      if (!addjob(job_list, pid, FG, cmdline))
	return;
      Sigprocmask(SIG_UNBLOCK, &mask, NULL);
      wait_for_fg(pid);
      return;
    }

    /* Background job */
    if (bg){
      if (!addjob(job_list, pid, BG, cmdline))
	return;
      Sigprocmask(SIG_UNBLOCK, &mask, NULL);
      printf("[%d] (%d) %s\n", pid2jid(pid), pid, cmdline);
    }
    return;
}
/* 
 * 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) 
{
    int bg;        /* should the job run in bg or fg? */
    struct cmdline_tokens tok;
    pid_t pid;     /* if the pid is 0, it is the child. */
    int jid;       /* if the child runs in background, 
                      we should know the jid and print the infomation */

/*
 * Use new_mask to mask three signals.
 * Before the child process execve(), we should unblock these signals.
 * When it comes to parent process, we should set the old_mask set to
 * it after we add the job in job_list.
 */
    sigset_t new_mask, old_mask;

    /* Parse command line */
    bg = parseline(cmdline, &tok); 
/*
 * Maybe there are some more errors that we should return.
 * I did not meet them. If I met an error condition, I will
 * make an improvement as soon as possible.
 */
    if (bg == -1) return;               /* parsing error */
    if (tok.argv[0] == NULL)  return;   /* ignore empty lines */

/*
 * As it is said in the writeup, If the first word is a built-in command, the
 * shell immediately executes the command in the current process. Otherwise, 
 * the word is assumed to be the pathname of an executable program. In this 
 * case, the shell forks a child process, then loads and runs the program in
 * the context of the child.
 * 1. If it is a built-in command, builtinCommand function will handle it.
 * 2. If it is a executable program, the function returns 0.
 * 3. Then, we should block the signals before we fork a child.
 * 4. Put the child in a new process group.
 * 5. Set the I/O Redirection and make the signal default.
 * 6. Execute the program and exit.
 * 7. Add the job and unblock the signals in parent.
 * 8. If the child runs in foreground, wait for it.  
 */
    if (!builtinCommand(tok)) {
        Sigemptyset(&new_mask);
        Sigaddset(&new_mask, SIGCHLD);
        Sigaddset(&new_mask, SIGINT);
        Sigaddset(&new_mask, SIGTSTP);
        Sigprocmask(SIG_BLOCK, &new_mask, &old_mask);

        if (0 == (pid = Fork())) {
            int fdout, fdin;
            Setpgid(0, 0);
            dup2(fdout = getfd(OUT, tok.outfile), STDOUT_FILENO);
            dup2(fdin = getfd(IN, tok.infile), STDIN_FILENO);
            if (!bg) {
                tcsetpgrp(STDIN_FILENO, getpgrp());
            }
            Signal(SIGCHLD, SIG_DFL);
            Signal(SIGINT, SIG_DFL);
            Signal(SIGTSTP, SIG_DFL);
            Sigprocmask(SIG_UNBLOCK, &new_mask, NULL);
            if (execve(tok.argv[0], tok.argv, environ) < 0) {
                printf("%s: Command not found.\n", tok.argv[0]);
                exit(0);
            }
            if (STDOUT_FILENO != fdout) {
                close(fdout);
            }
            if (STDIN_FILENO != fdin) {
                close(fdin);
            }
            exit(0);
        }
        if (bg) {
            addjob(job_list, pid, BG, cmdline);
            Sigprocmask(SIG_SETMASK, &old_mask, NULL);
            jid = pid2jid(pid);
            printf("[%d] (%d) %s\n", jid, pid, cmdline);
        }
        else {
            addjob(job_list, pid, FG, cmdline);
            Sigprocmask(SIG_SETMASK, &old_mask, NULL);
/*
 * If the child runs in foreground, we should wait for it. I think it is
 * the most tricky thing in this shell lab. I test everything I know. Then,
 * I found the sigsuspend() function had the best performance.
 * 1. pause(). 
 *    It is the first way I think about. When I do manually from the
 *    command line, It is OK. However, when it comes to trace file, sometimes
 *    it is OK, sometimes it will cause an error.
 * 2. sleep(1), usleep(n), or something like these.
 *    Although Michael said that we cannot use sleep, I do not know what to do
 *    and what the performance is. So, I test it. When I ran it from the 
 *    command line, I could not find any wrong. When it comes to the trace 
 *    files, there are lots of errors. It seems that it is not a good way. -_-b
 * 3. sleep(0), sleep(0), sleep(0)...
 *    When I found the information in the Internet, someone said 3 or more 
 *    sleep(0) could be a good choice for wait. The fact is that it can pass
 *    a lot of trace files, but the performance is not stable. Also, I think 
 *    it will waste the CPU resource.
 * sigsuspend() is the only way that I found could pass the ./sdriver. If there
 * is annother better way, I will be very interested in it. If you would like 
 * to tell a better solution, I will be very happy.
 */
            while (fgpid(job_list)) {
                sigsuspend(&old_mask);
            }
        }
    }
    return;
}