make && ./sdriver.pl -t trace15.txt -s ./tshref -a "-p -v"
make && ./sdriver.pl -t trace15.txt -s ./tsh -a "-p -v"
trace*.txt
Do nothing.
quit
command.int builtin_cmd(char **argv) {
if (!strcmp(argv[0], "quit"))
exit(0);
/* other builtin commands */
return 0;
}
⚠️ addjob()
and deletejob()
has more arguments than the textbook version.
void eval(char *cmdline)
{
char *argv[MAXARGS];
int bg;
pid_t pid;
sigset_t mask_all, mask_one, prev_one;
bg = parseline(cmdline, argv);
if (argv[0] == NULL)
return; /* ignore empty cmdline */
if (builtin_cmd(argv))
return;
Sigfillset(&mask_all);
/* Block SIGCHLD */
Sigemptyset(&mask_one);
Sigaddset(&mask_one, SIGCHLD);
Sigprocmask(SIG_BLOCK, &mask_one, &prev_one);
if ((pid = Fork()) == 0) { /* Child Process */
Sigprocmask(SIG_SETMASK, &prev_one, NULL); /* Unblock SIGCHLD */
Setpgid(0, 0); /* Put the child in a new process group whose ID
== the child's PID. */
if (execve(argv[0], argv, environ) < 0) {
printf("%s: Command not found\n", argv[0]);
exit(1);
}
}
Sigprocmask(SIG_BLOCK, &mask_all, NULL); /* Block all */
addjob(jobs, pid, 1+bg, cmdline);
Sigprocmask(SIG_SETMASK, &prev_one, NULL); /* recover */
if (!bg)
waitfg(pid);
}
In waitfg()
, use sigsuspend()
to wait:
void waitfg(pid_t pid)
{
sigset_t mask_all, prev_all;
pid_t fg_pid;
Sigfillset(&mask_all);
while (1) {
Sigprocmask(SIG_BLOCK, &mask_all, &prev_all);
fg_pid = fgpid(jobs);
if (fg_pid == pid) {
Sigsuspend(&prev_all);
Sigprocmask(SIG_SETMASK, &prev_all, NULL);
}
else {
Sigprocmask(SIG_SETMASK, &prev_all, NULL);
break;
}
}
if (verbose) {
printf("waitfg: Process (%d) no longer the fg process\n", pid);
fflush(stdout);
}
}
void eval(char *cmdline) {
/* ... */
Sigprocmask(SIG_BLOCK, &mask_all, NULL); /* Block all */
addjob(jobs, pid, 1+bg, cmdline);
if (bg) {
printf("[%d] (%d) %s", pid2jid(pid), pid, cmdline);
fflush(stdout);
}
Sigprocmask(SIG_SETMASK, &prev_one, NULL); /* recover */
if (!bg)
waitfg(pid);
}
jobs
builtin command.int builtin_cmd(char **argv) {
sigset_t mask_all, prev_all;
Sigfillset(&mask_all);
/* ... */
if (!strcmp(argv[0], "jobs")) {
Sigprocmask(SIG_BLOCK, &mask_all, &prev_all);
listjobs(jobs);
Sigprocmask(SIG_SETMASK, &prev_all, NULL);
return 1;
}
/* ... */
}
SIGINT
to FG job.void sigint_handler(int sig) {
int olderrno = errno;
sigset_t mask_all, prev_all;
pid_t pid;
char buf[MAXLINE]; int pos = 0; /* local buffer for sprintf() */
if (verbose)
Sio_puts("sigint_handler: entering\n");
Sigfillset(&mask_all);
Sigprocmask(SIG_BLOCK, &mask_all, &prev_all);
pid = fgpid(jobs);
Sigprocmask(SIG_SETMASK, &prev_all, NULL);
Kill(pid, sig); /* to be improved in #11 */
if (verbose) {
pos += sprintf(buf + pos, "sigint_handler: Job (%d) killed\n", pid);
pos += sprintf(buf + pos, "sigint_handler: exiting\n");
Sio_puts(buf);
}
errno = olderrno;
}
SIGINT
only to FG job.Do nothing.
SIGTSTP
only to FG job.Similar to #6, just one more thing:
void sigtstp_handler(int sig) {
/* ... */
job->state = ST; /* to be improved in #16 */
/* ... */
}
bg
builtin commandfg
builtin commandSIGINT
to every process in FG process groupSimilar to #6, just one change:
Kill(-pid, sig); /* forward signal to FG process group (see #6) */
SIGTSTP
to every process in FG process groupMain test.
Move job->state = ST;
from sigtstp_handler()
to sigchld_handler()
.