Beispiel #1
0
/*
 * 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 tmppid = 1;
	int st;

	while( tmppid > 0 ) { // default tmppid is 1.
		tmppid = waitpid(-1, &st, WNOHANG | WUNTRACED); // wait all children and with WNOHANG | WUNTRACED. 

		if(tmppid > 0) { // When child processes returns PID.
			if(WIFEXITED(st)) // When the child exits.
				deletejob(jobs, tmppid);
			else {
				if(WIFSIGNALED(st)) { 
					if(WTERMSIG(st) == 2) // If signal is 2(that is SIGINT)
						printf("Job [%d] (%d) terminated by signal %d\n", pid2jid(tmppid), tmppid, WTERMSIG(st));
					deletejob(jobs, tmppid);
				}
				else if(WIFSTOPPED(st)) { // When child processes are stopped.
					getjobpid(jobs, tmppid)->state = ST; // Change state.
					printf("Job [%d] (%d) stopped by signal %d\n", pid2jid(tmppid), tmppid, WSTOPSIG(st));
				}
			}
		}
	}
}
Beispiel #2
0
/* 
 * 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, SIGTSTP, SIGTTIN or SIGTTOU 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 (WIFSIGNALED(status)) {
			if (WTERMSIG(status) == SIGINT) {
				printf("Job [%d] (%d) terminated by signal %d\n",
					pid2jid(pid), pid, WTERMSIG(status));
				deletejob(job_list, pid);
			}
		}
		else if (WIFSTOPPED(status)) {
			job = getjobpid(job_list, pid);
				job->state = ST;
				printf("Job [%d] (%d) stopped by signal %d\n",
					pid2jid(pid), pid, WSTOPSIG(status));
		}
		else
			deletejob(job_list, pid);
	}
	if (pid == -1 && errno != ECHILD)
		unix_error("waitpid error");
	return;
}
Beispiel #3
0
/* 
 * 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, SIGTSTP, SIGTTIN or SIGTTOU 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;
    while((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0){
        if(pid == fgpid(job_list)){
            if(tcgetpgrp(STDIN_FILENO) != shell_pid) {
                tcsetpgrp(STDIN_FILENO, shell_pid);
            }
        }
        if(WIFEXITED(status)){
            deletejob(job_list, pid);
        } else if(WIFSIGNALED(status)){
            printf("Job [%d] (%d) terminated by signal %d\n",
                   pid2jid(pid), pid, WTERMSIG(status));
            deletejob(job_list, pid);
        } else if (WIFSTOPPED(status)) {
            printf("Job [%d] (%d) stopped by signal %d\n", 
                   pid2jid(pid), pid, WSTOPSIG(status));
            getjobpid(job_list, pid)->state = ST;
        }
    }
    return;
}
Beispiel #4
0
/* 
 * 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 status;  
    pid_t pid;  
    
    while ((pid = waitpid(fgpid(jobs), &status, WNOHANG|WUNTRACED)) > 0) {  
        if (WIFSTOPPED(status)){ 
            //change state if stopped
            getjobpid(jobs, pid)->state = ST;
            int jid = pid2jid(pid);
            printf("Job [%d] (%d) Stopped by signal %d\n", jid, pid, WSTOPSIG(status));
        }  
        else if (WIFSIGNALED(status)){
            //delete is signaled
            int jid = pid2jid(pid);  
            printf("Job [%d] (%d) terminated by signal %d\n", jid, pid, WTERMSIG(status));
            deletejob(jobs, pid);
        }  
        else if (WIFEXITED(status)){  
            //exited
            deletejob(jobs, pid);  
        }  
    }  
    return; 
}
Beispiel #5
0
Datei: tsh.c Projekt: fffxj/csapp
/* 
 * 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;
  sigset_t mask_all, prev_all;
  pid_t pid;
  int status;
  
  Sigfillset(&mask_all);
  while ((pid = waitpid(-1, &status, WNOHANG|WUNTRACED)) > 0) {
    Sigprocmask(SIG_BLOCK, &mask_all, &prev_all); /* Block Signals*/
    if (WIFEXITED(status)) {    /* Exit normally */
      deletejob(jobs, pid);
    }
    if (WIFSIGNALED(status)) {  /* C-c SIGINT */
      printf("Job [%d] (%d) terminated by signal 2\n", pid2jid(pid), pid);
      deletejob(jobs, pid);     /* Note: printf first, then deletejob */
    }
    if (WIFSTOPPED(status)) {   /* C-z SIGTSTP */
      printf("Job [%d] (%d) stopped by signal 20\n", pid2jid(pid), pid);
      getjobpid(jobs, pid)->state = ST;
    }
    Sigprocmask(SIG_SETMASK, &prev_all, NULL); /* Unblock Signals*/
  }

  errno = olderrno;
  return;
}
Beispiel #6
0
void builtincont(struct cmdline_tokens *tok, int state){
  if (tok->argc < 2){
    // app_error("Usage: %s [%jid/pid]\n", tok->argv[0]);
    return;
  }
  pid_t pid;

  /* JID */
  if (tok->argv[1][0]=='%'){
    int jid = atoi((char *)(tok->argv[1] + sizeof(char)));
    pid = jid2pid(jid);
    if (!pid)
      app_error("No such jid \n");
  }
  else{
    /* PID case */
    pid = atoi(tok->argv[1]);
    if (!pid2jid(pid))
      app_error("No such pid \n");
  }
  /* Common to both JID & PID */
  Kill(-pid, SIGCONT);
  changestate(job_list, pid, state);
  if (state==BG){
    printf("[%d] (%d) %s\n", pid2jid(pid), pid,
	   getjobpid(job_list,pid)->cmdline);
  }

  if (state==FG){
    wait_for_fg(pid);
  }
}
Beispiel #7
0
/* 
 * 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, SIGTSTP, SIGTTIN or SIGTTOU 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 status;
    pid_t pid;
    
    while((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
        if(WIFEXITED(status)) {
            /* if a child job terminated normally */
            deletejob(job_list, pid);

        } else if(WIFSIGNALED(status)) {
            /* if a child job terminated by signal */
            printf("Job [%d] (%d) terminated by signal %d\n",
                pid2jid(pid), pid, WTERMSIG(status));
            deletejob(job_list, pid);

        } else if(WIFSTOPPED(status)) {
            /* if a child job is stopped, we should also update its status */
            printf("Job [%d] (%d) stopped by signal %d\n",
                pid2jid(pid), pid, WSTOPSIG(status));
            getjobpid(job_list, pid) -> state = ST;
        }
    }
        
    return;
}
Beispiel #8
0
/* 
 * 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 pid,status;
    while ((pid=waitpid(-1, &status, WNOHANG | WUNTRACED))>0)
    {
        /*If there is any child which is still running then parent will not wait for them and retuens the pids and status of reaped child with MACRO  "WNOHANG".*/
/* Also if there are any stopped ot terminated child then parent will reap them immediately with MACRO "WUNTRACED"*/ 

        if (WIFEXITED(status))/* MACRO "WIFEXITED" returns true if child terminated normally*/
            {
                deletejob(jobs, pid); /* delete job from jobtable when terminated*/                     
            }
        else if (WIFSIGNALED(status))/* MACRO "WIFSIGNALED" returns true if reaped child is terminated*/
        {
            printf("Job [%d] (%d) terminated by signal %d\n", pid2jid(pid), pid, WTERMSIG(status));/*MACRO "WTERMSIG" gives by which signal child is terminated*/           
            deletejob(jobs, pid); /* delete job from jobtable when terminated*/                     
        }
        else if (WIFSTOPPED(status))/* MACRO "WIFSTOPPED" returns true if reaped child is stopped*/
        {
            getjobpid(jobs, pid)->state = ST; /* If child process receives stop signal then it will change state of child process*/
            printf("Job [%d] (%d) stopped by signal %d\n", pid2jid(pid), pid, WSTOPSIG(status)); /*MACRO "WSTOPSIG" gives by which signal child is stopped*/
        }
    }
    return;
}
Beispiel #9
0
/* 
 * 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, SIGTSTP, SIGTTIN or SIGTTOU 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 status;
  pid_t pid; 

  while((pid = waitpid(-1, &status, WUNTRACED | WNOHANG)) > 0)
  {
  
    // If child exited normally, delete job from list
    if(WIFEXITED(status))
      deletejob(job_list, pid);

    // If child terminated because of uncaught signal, delete job from list
    else if(WIFSIGNALED(status))
    {
      printf("Job [%d] (%d) terminated by signal %d\n", 
	     pid2jid(pid), pid, WTERMSIG(status));
      
      deletejob(job_list, pid);
    }

    // If child was stopped change status to ST
    else if(WIFSTOPPED(status))
    {     
      printf("Job [%d] (%d) stopped by signal %d\n",
	     pid2jid(pid), pid, WSTOPSIG(status));

      getjobpid(job_list, pid) -> state = ST;
    }
  }

  return;

}
Beispiel #10
0
void sigchld_handler(int sig) 
{
    pid_t pid = 0;
    struct job_t *nowjob = 0;
    int status;
    while((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0)//handle all stopped or terminated children
    {
        if(WIFEXITED(status))
        {
         //   printf("pid [%d] terminated normally\n",pid);
            deletejob(jobs,pid);
        }
        else if(WIFSIGNALED(status))
        {
            printf("Job [%d] (%d) terminated by signal %d\n",pid2jid(pid),pid,WTERMSIG(status));
            deletejob(jobs,pid);
        }
        else if(WIFSTOPPED(status))
        {
            printf("Job [%d] (%d) stopped by signal %d\n", pid2jid(pid), pid, WSTOPSIG(status));
            nowjob = getjobpid(jobs,pid);
            nowjob->state = ST;
        }
    }
    if((errno != ECHILD) && (errno != 0)) 
    {
        unix_error("waitpid error");
    }   
        
    
    return;
}
Beispiel #11
0
/* 
 * 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;
	// Reap all the child process.
	while ((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
		//Handle with the 3 situation in this handler together.
		if (WIFSIGNALED(status)) {
			printf("Job [%d] (%d) terminated by Signal %d\n", pid2jid(pid),
					pid,
					WTERMSIG(status));
			deletejob(jobs, pid);
		} else if (
		WIFSTOPPED(status)) {
			struct job_t *job = getjobpid(jobs, pid);
			if (job == NULL) {
				printf("sigchld: Get job error.\n");
				return;
			}
			job->state = ST;
			printf("Job [%d] (%d) stopped by Signal %d\n", pid2jid(pid), pid,
			WEXITSTATUS(status));

		} else if (
		WIFEXITED(status)) {
			deletejob(jobs, pid);
		}

		//printf("Handler reaped child %d\n", (int)pid);
	}
	return;
}
Beispiel #12
0
void sigchld_handler(int sig) 
{
	int pid=0;
    int status=-1;
    do{     //continually reap as many children as possible, deleting them from the job list
        pid=waitpid(-1,&status,WNOHANG|WUNTRACED);   
       
        if(pid>0)//first time
        {
            if(WIFEXITED(status)){//child terminated normally, easy to handle, just delete it from the job list
                deletejob(jobs,pid);
               
            }
            else
            if(WIFSIGNALED(status)){  //what if the process was terminated by another process?
                if(WTERMSIG(status)==2)
                    printf("Job [%d] (%d) terminated by signal %d\n", pid2jid(pid), pid, WTERMSIG(status));
                deletejob(jobs,pid);
            }
            else if(WIFSTOPPED(status)){    //what if the process was stopped by another process?
                getjobpid(jobs, pid)->state=ST;
                printf("Job [%d] (%d) stopped by signal %d\n", pid2jid(pid), pid, WSTOPSIG(status));
            }
        }        
    }
    while(pid>0);
}
Beispiel #13
0
/* 
 * 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, SIGTSTP, SIGTTIN or SIGTTOU 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 status;
    pid_t pid;
    int olderrno = errno; // store errno in handler

    /*
     * Reap child with the pid if the child is stopped or terminated
     * If a child is terminated normally, delete the child from the job list
     * If a child is stopped by a signal, set the job status as stopped
     * If a child is terminated by a signal that was not caught, delete the child from the job list
     */
    while ((pid = waitpid(-1, &status, WNOHANG|WUNTRACED)) > 0) {

        if (WIFEXITED(status)) {

            deletejob(job_list, pid); // the child ternimated normally

        } else if (WIFSTOPPED(status)) {

            /*
             * Avoid printf() in handler, use helper function to write the output to stdout
             */
            sio_puts("Job [");
            sio_putl(pid2jid(pid));
            sio_puts("] (");
            sio_putl(pid);
            sio_puts(") stopped by signal ");
            sio_putl(WSTOPSIG(status));
            sio_puts("\n");

            getjobpid(job_list, pid) -> state = ST; // the child was stopped by a signal 

        } else if (WIFSIGNALED(status)) { // the child was terminated by a signal that was not caught

            /*
             * Avoid printf() in handler, use helper function to write the output to stdout
             */
            sio_puts("Job [");
            sio_putl(pid2jid(pid));
            sio_puts("] (");
            sio_putl(pid);
            sio_puts(") terminated by signal ");
            sio_putl(WTERMSIG(status));
            sio_puts("\n");

			deletejob(job_list, pid);

        }

    }

    errno = olderrno;
    return;
}
Beispiel #14
0
/* 
 * 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 status;
    waitpid(-1, &status, 0);
    return;
    */
    
    //printf("...in sigchild\n");
    fflush(stdout);
    int status = 1;
    pid_t pid;
    while ( ( pid = waitpid(-1, &status, WNOHANG | WUNTRACED) ) > 0 )
    {
        if (WIFSTOPPED(status))
        {
            int jid = pid2jid(pid);
            getjobpid(jobs, pid)->state = ST;
            printf("%s [%d] (%d) %s %d %s", "Job", jid, pid, "stopped by signal", SIGSTOP, "\n");
        }
        else
        {
            int jid = pid2jid(pid);
            int jdel = deletejob(jobs, pid);
            if (jdel)
            {
                if (sig != 17)
                {
                    //printf("MADE IT!\n");
                    printf("%s [%d] (%d) %s %d %s", "Job", jid, pid, "terminated by signal", SIGINT, "\n");
                }
            }
            else
            {
                printf("error deleting job\n");
                fflush(stdout);
                exit(1);
            }  
        }
        
    }
    if (pid == -1)
    {
        //printf("...no processes\n");
    }
    else if (pid < -1)
    {
        printf("error in sigchild\n");
        fflush(stdout);
        exit(1);
    }
    
    return;
}
Beispiel #15
0
/*
 * 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 status;
	if (verbose) printf ("sigchld_handler: entering\n");

	/* wait until some child is terminated */
	pid_t pid_ch, jid_ch ;
	while ((pid_ch = waitpid (-1, &status, WUNTRACED | WNOHANG)) > 0) {	// wait any terminated child
	    	jid_ch = pid2jid (pid_ch);
	    	if (verbose) printf ("sigchld_handler: Job [%d] (%d) deleted\n", jid_ch, pid_ch);
		if (WIFEXITED (status)) {		// case 1: child process terminated normally
			if (verbose) printf ("sigchld_handler: Job [%d] (%d) terminates OK (status 0)\n", jid_ch, pid_ch);
			deletejob (jobs, pid_ch);
		}
		else if (WIFSIGNALED (status)) {	// case 2: child process terminated via a signal that was not caught
			deletejob (jobs, pid_ch);
			printf ("Job [%d] (%d) terminated by signal %d\n", jid_ch, pid_ch, WTERMSIG (status));	
		}
		else if (WIFSTOPPED (status)) {		// case 3: child process stopped
		    	struct job_t *stopped = getjobpid (jobs, pid_ch);
			stopped->state = ST;

			printf ("Job [%d] (%d) stopped by signal %d\n", jid_ch, pid_ch, WSTOPSIG (status));
		}

	}

	if (verbose) printf ("sigchld_handler: exiting\n");

	return;
}
Beispiel #16
0
/* 
 * waitfg - Block until process pid is no longer the foreground process
 */
void waitfg(pid_t pid)
{
	int status;
	if ((pid = waitpid(pid, &status, WUNTRACED)) < 0)
	{
		perror("waitfg error:");
		exit(0);
	}
	else
	{
		if (WIFSTOPPED(status))
		{
			int jid = pid2jid(pid);	
			printf("Job [%d] %d stopped by signal: Stopped\n",jid,(int)pid);
		}
		else if (WIFEXITED(status))
		{
			deletejob(jobs,pid);
		}
		else if (WIFSIGNALED(status))
		{
			printf("Job %d terminated by signal: Interrupt\n",(int)pid);
			deletejob(jobs,pid);
		}
	}
    return;
}
Beispiel #17
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=parseline(cmdline,argv);
        int  p=builtin_cmd(&argv[0]);
	int childpid;
	bg++;                //because the background process is defined as  2 and foreground as 1
        sigset_t set;
        sigemptyset(&set);
        sigaddset(&set,SIGCHLD);
        sigaddset(&set,SIGINT);
        sigaddset(&set,SIGTSTP);
        if(!p)
        {       
                if((childpid=fork())==0)
		{
			setpgid(0,0); //Changing group id
			execve(argv[0], argv, NULL);
                        printf("Command not found\n");//If incase there is no command
		        exit(0);
		}
                else
		{    
			sigprocmask(SIG_BLOCK,&set,NULL); //masking if incase child executes first
		        addjob(jobs,childpid,bg,cmdline);
                        sigprocmask(SIG_UNBLOCK,&set,NULL);//remove mask
                        if(bg==1) 
                        	waitfg(childpid);
	           	else
                   		printf("[%d] (%d) %s",pid2jid(childpid),childpid,cmdline);
                }
	}
	return;
}
Beispiel #18
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]; /* argv for execve() */
    int bg;
    pid_t pid;

    bg = parseline(cmdline, argv);
    if(argv[0] == NULL) return; /* ignore empty lines */

    if(!builtin_cmd(argv))
    {
        if((pid = fork()) < 0) unix_error("eval(): fork() error");

        if(pid == 0) /* child runs user job */
	{
            if(setpgid(0,0) < 0) unix_error("eval(): setpgid() error");

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

	addjob(jobs,pid,(bg == 1 ? BG : FG),cmdline);

	sigprocmask(SIG_UNBLOCK,&mask,NULL);

	if(!bg) waitfg(pid);
	else printf("[%d] (%d) %s",pid2jid(pid),pid,cmdline);
    }

    return;
}
Beispiel #19
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 ground = parseline(cmdline, (char **)&argv); */
	char buf[MAXLINE];      // Holds modified command line
	strcpy(buf, cmdline);
	int ground = parseline(buf, argv);

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

	if (!builtin_cmd((char **)&argv)) {
		sigset_t mask;
		sigemptyset(&mask);
		sigaddset(&mask, SIGCHLD);
		sigprocmask(SIG_BLOCK, &mask, NULL);
		pid_t pid = __fork();

		if (pid != 0) {
			addjob(jobs, pid, ground ? BG : FG, cmdline);
			sigprocmask(SIG_UNBLOCK, &mask, NULL);
			if (!ground) waitfg(pid);
			else printf("[%d] (%d) %s", pid2jid(pid), pid, cmdline);
		} else {
			__setpgid(0, 0);
			sigprocmask(SIG_UNBLOCK, &mask, NULL);
			if (execve(argv[0], argv, environ) < 0) {
				printf("%s: Command not found\n", argv[0]);
				exit(0);
			}
		}
	}

	return;
}
Beispiel #20
0
/* 
 * 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, SIGTSTP, SIGTTIN or SIGTTOU 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;
    int old_err = errno;

    while((pid = waitpid(-1, &status, WNOHANG|WUNTRACED)) > 0 ) {
        if(WIFSTOPPED(status)) {
            job = getjobpid(job_list, pid);
            //Assume that pointer job is not NULL
            safe_printf("Job [%d] (%d) stopped by signal %d\n", job->jid, job->pid, WSTOPSIG(status));
            job->state = ST;
        }
        else if(WIFSIGNALED(status)) {
            safe_printf("Job [%d] (%d) terminated by signal %d\n", pid2jid(pid), pid, WTERMSIG(status));
            deletejob(job_list,pid);
        }
        else if(WIFEXITED(status)) 
            deletejob(job_list,pid);
    }

    if( pid < 0 && errno != ECHILD && errno != EINTR ) {
        safe_printf("waitpid error: %s\n", strerror(errno));
        _exit(1);
    }

    errno = old_err;
    return;
}
Beispiel #21
0
/* 
 * 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, SIGTSTP, SIGTTIN or SIGTTOU 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 jid;
	int status;
	while((pid=waitpid(-1,&status,WNOHANG | WUNTRACED))>0)
	{
		jid=pid2jid(pid);

		if(WIFEXITED(status))
		{
			deletejob(job_list,pid);
		}
		if(WIFSIGNALED(status))
		{
			printf("Job [%d] (%d) terminated by signal 2\n",jid,pid);
			deletejob(job_list,pid);
		}
		if(WIFSTOPPED(status))
		{
			printf("Job [%d] (%d) stopped by signal 20\n",jid,pid);
			getjobpid(job_list,pid)->state=ST;
		}
	}
    return;
}
Beispiel #22
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];
	char buf[MAXLINE];
	int bg;
	sigset_t mask;
	pid_t pid;
	
	strcpy(buf, cmdline);
	bg = parseline(buf, argv);
	if(argv[0] == NULL)
		return;

	if(!builtin_cmd(argv)){
		
		//block signal
		if(sigemptyset(&mask) < 0)
			unix_error("sigemptyset error");
		if(sigaddset(&mask, SIGCHLD) < 0)
			unix_error("sigaddset error");
		if(sigprocmask(SIG_BLOCK, &mask, NULL) < 0)
			unix_error("sigprocmask error");

		if((pid = fork()) == 0){

			//set pid group to be the same as the current pid
			if(setpgid(0,0) < 0)
				unix_error("eval: set pid group error");

			//unblock siganl
			if(sigprocmask(SIG_UNBLOCK, &mask, NULL) < 0)
				unix_error("sigprocmask error");

			//execute program
			if(execve(argv[0], argv, environ)<0){
				printf("%s: Command not found.\n", argv[0]);
				exit(1);
			}
		}
		
		if(!bg){
			addjob(jobs, pid, FG, cmdline);

			//unblock siganl
			if(sigprocmask(SIG_UNBLOCK, &mask, NULL) < 0)
				unix_error("sigprocmask error");
			waitfg(pid);
		}else{
			addjob(jobs, pid, BG, cmdline);

			//unblock siganl
			if(sigprocmask(SIG_UNBLOCK, &mask, NULL) < 0)
				unix_error("sigprocmask error");
			printf("[%d] (%d) %s", pid2jid(pid), pid, cmdline);
		}
	}
    return;
}
Beispiel #23
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.  
 *
 * Requires:
 *   "cmdline" is a NUL ('\0') terminated string with a trailing
 *   '\n' character.  "cmdline" must contain less than MAXARGS
 *   arguments.
 *
 * Effects:
 *   A built-in command is executed immediately. Otherwise, it attempts 
 *   to fork a child process and execute the job. If necessary, the 
 *   executable program is searched through the directories of the 
 *   search path. If not found, an error is thrown. If the job is
 *   running as a foreground job, it waits until completion.  
 */
static void
eval(const char *cmdline) 
{
	char *argv[MAXARGS];
	int bg = parseline(cmdline, argv);
	pid_t pid;
	sigset_t mask;
	
	// Checks command line is not empty.
	if (!argv[0]) {
		return;
	}

	// Checks that the command is not a built-in command.
	if(!builtin_cmd(argv)){
		sigemptyset(&mask);
		sigaddset(&mask, SIGCHLD);
		sigprocmask(SIG_BLOCK, &mask, NULL);

		// A child is forked. 
		pid = fork();
		if (pid == 0) {
			// Put child in new group whose ID is identical to child’s PID.
			setpgid(0, 0);
			sigprocmask(SIG_UNBLOCK, &mask, NULL);

			if (execve(argv[0], argv, environ) == -1) {
				int index = 0;
				// Run through directories in search path to execute program.
				while (argv[0][0] != '.' && index < directoryCount) {
					if (execve(strcat(directories[index],argv[0]), argv, environ) != -1) {
						break;
					}
					index++;
				}
				// Command not found.
				char *print;
				asprintf(&print, "%s: Command not found\n", argv[0]);
				sio_error(print);
			} 
		}
	

		if (bg == 0) {
			addjob(jobs,pid,FG,cmdline);
			sigprocmask(SIG_UNBLOCK, &mask, NULL);
			// Wait for foreground jobs to complete.
			waitfg(pid);
		}
		else {
			addjob(jobs,pid,BG,cmdline);
			sigprocmask(SIG_UNBLOCK, &mask, NULL);
			printf("[%d] (%d) %s", pid2jid(pid), pid, cmdline); 
		}
	}
 
	return;
}
Beispiel #24
0
/*
 * do_bgfg - Execute the builtin bg and fg commands
 */
void do_bgfg(char **argv)
{
	struct job_t* job = NULL;
	sigset_t mask;
	int jid = 0;
    int fg = !strcmp(argv[0],"fg");
	if(argv[1] == NULL){
		printf("%s command requires PID or %%jobid argument\n", argv[0]);
		return;
	}
	//used to save a bit of repetition when returning after an error
	int done = 0;

	//SIGCHLD handler could delete the job before it is or read edited
	//giving us a seg fault so we must protect it while reading and editing state
	sigemptyset(&mask);
	sigaddset(&mask, SIGCHLD);
	sigprocmask(SIG_BLOCK, &mask, NULL);
	if(isdigit(argv[1][0])){
		pid_t pid = atoi(argv[1]);
		jid = pid2jid(pid);
		if(jid == 0){
			printf("(%d): No such process\n", pid);
			done = 1;
		}
	}else if(argv[1][0]=='%'){
		argv[1]++;
		jid = atoi(argv[1]);
		if(getjobjid(jobs, jid) == NULL){
			printf("%%%s: No such job\n", argv[1]);
			done = 1;
		}
	}else{
		printf("%s: argument must be a PID or %%jobid\n", argv[0]);
		done = 1;
	}
	if(done){
		sigprocmask(SIG_UNBLOCK, &mask, NULL);
		return;
	}
	job = getjobjid(jobs, jid);
	if(kill(-job->pid,SIGCONT) < 0){
		printf("Could not continue child process\n");
		sigprocmask(SIG_UNBLOCK, &mask, NULL);
		return;
	}
	//sets state to 1 if fg 2 if bg
	job->state = !fg + 1;
	if(fg){
		sigprocmask(SIG_UNBLOCK, &mask, NULL);
		waitfg(job->pid);
	}else{
		printf("[%d] (%d) %s",job->jid,job->pid, job->cmdline);	
		sigprocmask(SIG_UNBLOCK, &mask, NULL);
	}
    return;
}
Beispiel #25
0
/* 
 * 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 status;
    pid_t pid;
    while((pid = waitpid(-1, &status, WNOHANG|WUNTRACED)) > 0){
	if(WIFEXITED(status))
	    deletejob(jobs, pid);
	else if(WIFSTOPPED(status)){  //if it's stopped...
	    getjobpid(jobs, pid)->state = ST;
	    printf("Job [%d] (%d) stopped by signal %d\n",pid2jid(pid),pid,SIGTSTP);
	}
	else if(WIFSIGNALED(status)){  //if it's terminated...
	    printf("Job [%d] (%d) terminated by signal %d\n",pid2jid(pid),pid,SIGINT);
	    deletejob(jobs, pid);
	}
    }
    return;
}
Beispiel #26
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 = parseline(cmdline, argv);
    int rbic = builtin_cmd(argv);

    if (!rbic)
    {
        pid_t child = fork();
        //printf("forked\n");
        
        if (child)
        {      
            //PARENT    
            if (bg)
            {
                int ret = addjob(jobs, child, BG, cmdline); //returns an int
                if (ret)
                {
                    int jid = pid2jid(child);
                    printf("[%d] (%d) %s", jobs[jid-1].jid, jobs[jid-1].pid, jobs[jid-1].cmdline);
                }
                else
                {
                    printf("addjobfailed\n");
                }
            }
            else
            {
                int ret = addjob(jobs, child, FG, cmdline); //returns an int
                if (!ret)
                {
                    printf("addjobfailed\n");
                }
                waitfg(child);
            }
        }
        else if( child < 0 )
        {
            //ERROR
            exit(1); 
        }
        else
        {
            //CHILDS
            setpgid( 0, 0 );
            int rc = execv( argv[0], argv );
            if (rc == -1)
            {
                printf( "execv error %d\n", errno);
                exit(1);
            }
        }
    }
    return;
    
}
Beispiel #27
0
/*
 * 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 fg_pid = fgpid(jobs);
	if(fg_pid == 0)
        return ;
	printf("Job [%d] (%d) terminated by signal %d\n", pid2jid(fg_pid), fg_pid, sig);
	kill(-fg_pid, SIGINT);
	deletejob(jobs, fg_pid);
	return;
}
/*
 * This helper function can handle the "bg" command
 * 1. Get the pid and jid.
 * 2. Set the job state to BG.
 * 3. Print the infomation.
 * 4. Send the SIGCONT signal.
 */
void dobg(char **argv)
{
    pid_t pid;
    int jid;
    pid = getargvpid(argv);
    jid = pid2jid(pid);
    job_list[jid - 1].state = BG;
    printf("[%d] (%d) %s\n", jid, pid, job_list[jid - 1].cmdline);
    Kill(pid, SIGCONT);
}
Beispiel #29
0
/*
 * 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 != 0) { //check if it is the shell or a child process
        printf("Job [%d] (%d) stopped by signal 20 \n", pid2jid(pid), pid);
        getjobpid(jobs, pid)->state = ST; //job state changed to ST (stopped)
        kill(-pid, SIGTSTP); //send SIGTSTP signal to stop the process
    }
    return;
}
Beispiel #30
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;
}