diff options
| -rw-r--r-- | include/handler.h | 29 | ||||
| -rw-r--r-- | src/handler.cc | 150 | ||||
| -rw-r--r-- | src/main.cc | 173 |
3 files changed, 180 insertions, 172 deletions
diff --git a/include/handler.h b/include/handler.h new file mode 100644 index 0000000..23c9540 --- /dev/null +++ b/include/handler.h @@ -0,0 +1,29 @@ +#pragma once + +#include "global.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <errno.h> + +#include "util.h" +#include "job.h" + +namespace ov4 +{ + +void init(); +void sigchld_handler(int sig); +void sigint_handler(int sig); +void sigtstp_handler(int sig); +void sigquit_handler(int sig); +int block_all(sigset_t *prev); +int block_handler(sigset_t *prev); + +} diff --git a/src/handler.cc b/src/handler.cc new file mode 100644 index 0000000..afc1fc1 --- /dev/null +++ b/src/handler.cc @@ -0,0 +1,150 @@ +#include "handler.h" + +namespace ov4 +{ + +extern char **environ; +sigset_t BLOCK_HANDLER; + +void init() +{ + sigemptyset(&BLOCK_HANDLER); + sigaddset(&BLOCK_HANDLER, SIGINT); + sigaddset(&BLOCK_HANDLER, SIGTSTP); + sigaddset(&BLOCK_HANDLER, SIGCHLD); +} + +/* + * 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 errno_backup = errno; + + sigset_t prev; + block_handler(&prev); + + int status, pid; + atomic_debug("SIGCHLD\n"); + + while ((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) + { + if (WIFSIGNALED(status) || WIFSTOPPED(status)) + { + int jid = pid2jid(pid); + atomic_print("Job ["); + atomic_print(jid); + atomic_print("] ("); + atomic_print(pid); + atomic_print(") "); + if (!WIFSTOPPED(status) && WTERMSIG(status) == SIGINT) + atomic_print("terminated"); + else if (WIFSTOPPED(status)) + atomic_print("stopped"); + else + atomic_print("idk"); + atomic_print(" by signal "); + if (WIFSTOPPED(status)) + atomic_print(WSTOPSIG(status)); + else + atomic_print(WTERMSIG(status)); + atomic_print("\n"); + } + + if (WIFSTOPPED(status)) + { + atomic_debug("suspended pid: "); + atomic_debug(pid); + atomic_debug("\n"); + sigset_t prev_inner; + block_all(&prev_inner); + job_suspend(jobs, pid); + sigprocmask(SIG_SETMASK, &prev_inner, nullptr); + } + else { + atomic_debug("terminated pid: "); + atomic_debug(pid); + sigset_t prev_inner; + block_all(&prev_inner); + deletejob(jobs, pid); + sigprocmask(SIG_SETMASK, &prev_inner, nullptr); + } + } + + sigprocmask(SIG_SETMASK, &prev, nullptr); + + errno = errno_backup; + 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) +{ + int errno_backup = errno; + + sigset_t prev; + block_handler(&prev); + + int pid = fgpid(jobs); + if (pid != 0) + { + kill(-pid, SIGINT); + } + + sigprocmask(SIG_SETMASK, &prev, nullptr); + + errno = errno_backup; + 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) +{ + int errno_backup = errno; + + sigset_t prev; + block_handler(&prev); + + int pid = fgpid(jobs); + if (pid != 0) + { + kill(-pid, SIGTSTP); + } + + sigprocmask(SIG_SETMASK, &prev, nullptr); + + errno = errno_backup; + return; +} + +int block_all(sigset_t *prev) +{ + sigset_t set; + sigfillset(&set); + return sigprocmask(SIG_SETMASK, &set, prev); +} + +int block_handler(sigset_t *prev) +{ + return sigprocmask(SIG_BLOCK, &BLOCK_HANDLER, prev); +} + +void sigquit_handler(int sig) +{ + printf("Terminating after receipt of SIGQUIT signal\n"); + exit(1); +} + +} diff --git a/src/main.cc b/src/main.cc index ffcf52d..ba926f8 100644 --- a/src/main.cc +++ b/src/main.cc @@ -19,11 +19,11 @@ #include "util.h" #include "job.h" #include "parse.h" +#include "handler.h" using namespace std; using namespace ov4; -/* Misc manifest constants */ /* Job states */ @@ -43,7 +43,6 @@ using namespace ov4; */ /* Global variables */ -extern char **environ; /* defined in libc */ char prompt[] = "tsh> "; /* command line prompt (DO NOT CHANGE) */ char sbuf[MAXLINE]; /* for composing sprintf messages */ @@ -51,7 +50,6 @@ char sbuf[MAXLINE]; /* for composing sprintf messages */ vector<string> builtin_cmd_list = {"quit", "fg", "bg", "jobs"}; -sigset_t BLOCK_HANDLER; /* End global variables */ @@ -63,11 +61,6 @@ int builtin_cmd(char *c_str); void do_bgfg(char **argv); void waitfg(pid_t pid); -void sigchld_handler(int sig); -void sigtstp_handler(int sig); -void sigint_handler(int sig); - -void sigquit_handler(int sig); void usage(void); @@ -79,10 +72,7 @@ handler_t *Signal(int signum, handler_t *handler); // built-in commands void builtin_command_quit(); -inline int block_all(sigset_t*); -inline int block_handler(sigset_t*); -void init(); /* * main - The shell's main routine @@ -342,138 +332,6 @@ void waitfg(pid_t pid) 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 errno_backup = errno; - - sigset_t prev; - block_handler(&prev); - - int status, pid; - atomic_debug("SIGCHLD\n"); - - while ((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) - { - if (WIFSIGNALED(status) || WIFSTOPPED(status)) - { - int jid = pid2jid(pid); - atomic_print("Job ["); - atomic_print(jid); - atomic_print("] ("); - atomic_print(pid); - atomic_print(") "); - if (!WIFSTOPPED(status) && WTERMSIG(status) == SIGINT) - atomic_print("terminated"); - else if (WIFSTOPPED(status)) - atomic_print("stopped"); - else - atomic_print("idk"); - atomic_print(" by signal "); - if (WIFSTOPPED(status)) - atomic_print(WSTOPSIG(status)); - else - atomic_print(WTERMSIG(status)); - atomic_print("\n"); - } - - if (WIFSTOPPED(status)) - { - atomic_debug("suspended pid: "); - atomic_debug(pid); - atomic_debug("\n"); - sigset_t prev_inner; - block_all(&prev_inner); - job_suspend(jobs, pid); - sigprocmask(SIG_SETMASK, &prev_inner, nullptr); - } - else { - atomic_debug("terminated pid: "); - atomic_debug(pid); - sigset_t prev_inner; - block_all(&prev_inner); - deletejob(jobs, pid); - sigprocmask(SIG_SETMASK, &prev_inner, nullptr); - } - } - - sigprocmask(SIG_SETMASK, &prev, nullptr); - - errno = errno_backup; - 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) -{ - int errno_backup = errno; - - sigset_t prev; - block_handler(&prev); - - int pid = fgpid(jobs); - if (pid != 0) - { - kill(-pid, SIGINT); - } - - sigprocmask(SIG_SETMASK, &prev, nullptr); - - errno = errno_backup; - 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) -{ - int errno_backup = errno; - - sigset_t prev; - block_handler(&prev); - - int pid = fgpid(jobs); - if (pid != 0) - { - kill(-pid, SIGTSTP); - } - - sigprocmask(SIG_SETMASK, &prev, nullptr); - - errno = errno_backup; - return; -} - -/********************* - * End signal handlers - *********************/ - -/*********************************************** - * Helper routines that manipulate the job list - **********************************************/ - -/* clearjob - Clear the entries in a job struct */ - -/****************************** - * end job list helper routines - ******************************/ /*********************** @@ -526,41 +384,12 @@ handler_t *Signal(int signum, handler_t *handler) return (old_action.sa_handler); } -/* - * sigquit_handler - The driver program can gracefully terminate the - * child shell by sending it a SIGQUIT signal. - */ -void sigquit_handler(int sig) -{ - printf("Terminating after receipt of SIGQUIT signal\n"); - exit(1); -} - void builtin_command_quit() { exit(0); } -// return true if suspended, otherwise false -inline int block_all(sigset_t *prev) -{ - sigset_t set; - sigfillset(&set); - return sigprocmask(SIG_SETMASK, &set, prev); -} -inline int block_handler(sigset_t *prev) -{ - return sigprocmask(SIG_BLOCK, &BLOCK_HANDLER, prev); -} - -void init() -{ - sigemptyset(&BLOCK_HANDLER); - sigaddset(&BLOCK_HANDLER, SIGINT); - sigaddset(&BLOCK_HANDLER, SIGTSTP); - sigaddset(&BLOCK_HANDLER, SIGCHLD); -} |
