CSAPP:ShellLab 实现原理整理

CSAPP附带实验中的ShellLab要求实现一个Unix下运行的Shell程序,并且能接受fg、bg、job、quit等指令和ctrl-c、ctrl-z的信号。这里并不从解题思路,而是从该程序的运行过程进行整理。

首先,不带参数启动时,Shell进程的main函数将编写好的handler注册到各个Signal上,然后通过一个不断循环的while来读取指令,在没有异常的情况下送到eval函数进行指令的解析。

int main(int argc, char **argv) // 未经修改的main函数
{
    char c;
    char cmdline[MAXLINE];
    int emit_prompt = 1; /* emit prompt (default) */

    /* Redirect stderr to stdout (so that driver will get all output
     * on the pipe connected to stdout) */
    dup2(1, 2);

    /* Parse the command line */
    while ((c = getopt(argc, argv, "hvp")) != EOF) {
        switch (c) {
        case 'h':             /* print help message */
            usage();
	    break;
        case 'v':             /* emit additional diagnostic info */
            verbose = 1;
	    break;
        case 'p':             /* don't print a prompt */
            emit_prompt = 0;  /* handy for automatic testing */
	    break;
	default:
            usage();
	}
    }

    /* Install the signal handlers */

    /* These are the ones you will need to implement */
    Signal(SIGINT,  sigint_handler);   /* ctrl-c */
    Signal(SIGTSTP, sigtstp_handler);  /* ctrl-z */
    Signal(SIGCHLD, sigchld_handler);  /* Terminated or stopped child */

    /* This one provides a clean way to kill the shell */
    Signal(SIGQUIT, sigquit_handler); 

    /* Initialize the job list */
    initjobs(jobs);

    /* Execute the shell's read/eval loop */
    while (1) {

	/* Read command line */
	if (emit_prompt) {
	    printf("%s", prompt);
	    fflush(stdout);
	}
	if ((fgets(cmdline, MAXLINE, stdin) == NULL) && ferror(stdin))
	    app_error("fgets error");
	if (feof(stdin)) { /* End of file (ctrl-d) */
	    fflush(stdout);
	    exit(0);
	}

	/* Evaluate the command line */
	eval(cmdline);
	fflush(stdout);
	fflush(stdout);
    } 

    exit(0); /* control never reaches here */
}

接着,在eval函数中,先判断命令是否为内建指令,若不是内建指令,则是需要创建一个新的子进程。子进程依靠fork创建,依靠execve切换进程的内容,同时利用pid来判断在父进程还是子进程中,从而分别执行不同的代码。在父进程内部,同时需要创建一个jobs表来记录子进程。

在这里,有两个情况需要加锁:一是父进程在整个从fork到等待子进程被回收的过程,此操作内需要发送SIGCHLD信号,保证前台只有一个子进程;而是在父进程修改jobs表前需要加锁,此操作是保证jobs表不发生冲突。

void eval(char *cmdline) 
{
    int bg;
    pid_t pid;
    sigset_t mask, mask_all, prev;
    char buf[MAXLINE];
    char *argv[MAXARGS];

    strcpy(buf, cmdline);  // 读指令至buffer
    bg = parseline(buf, argv); // 是否后台运行
    if (argv[0] == NULL) // 空行
    {
        return;
    }

    if (!builtin_cmd(argv)) // 不是内建指令
    {
        sigemptyset(&mask);
        sigaddset(&mask, SIGCHLD);
        sigfillset(&mask_all);
        sigprocmask(SIG_BLOCK, &mask, &prev); // 添加阻塞
        if ((pid = fork()) == 0) // 子进程
        {
            sigprocmask(SIG_SETMASK, &prev, NULL); // 子进程的阻塞解除
            if (setpgid(0, 0) < 0) // 初始化唯一的pid
            {
                printf("Setpgid Error!\n");
                exit(0);
            }
            if (execve(argv[0], argv, environ) < 0) // 转换进程
            {
                printf("%s: Command not found.\n", argv[0]);
                exit(0);
            }
        }
        else // 父进程
        {
            sigprocmask(SIG_BLOCK, &mask_all, NULL);
            if (bg) 
            {
                addjob(jobs, pid, BG, cmdline); // 添加至job表
            }
            else
            {
                addjob(jobs, pid, FG, cmdline); // 添加至job表
            }
            sigprocmask(SIG_SETMASK, &prev, NULL); // 对job操作完后即可解阻塞

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

在waitfg函数中等待前台子进程结束的方式,这里简单地采用了sleep+轮询

void waitfg(pid_t pid) // 等待前台子进程
{
    while (pid == fgpid(jobs))
    {
        sleep(1);
    }
    return;
}

若指令是内建指令,则通过buildin_cmd函数来进行解析

int builtin_cmd(char **argv) 
{
    if (!strcmp(argv[0],"quit"))
    {
        exit(0);
    }
    if (!strcmp(argv[0],"jobs"))
    {
        listjobs(jobs); // 输出jobs表
        return 1;
    }
    if (!strcmp(argv[0],"bg") || !strcmp(argv[0],"fg"))
    {
        do_bgfg(argv);
        return 1;
    }
    
    return 0;
}

其中quit为结束shell,jobs为输出jobs表,而bg或fg指令为将参数(pid或%jobid)所对应的进程切换到后台/前台运行。

因此,需要编写do_bgfg函数来具体执行bg和fg指令,并且发送绑定了handler的信号给子进程。

void sigchld_handler(int sig) 
{
	int old_errno = errno;	// 保存原errno
	pid_t pid;
	sigset_t mask, prev;
	int state;	// waitpid的状态
	struct job_t *job;
	
	sigfillset(&mask);
	while ((pid = waitpid(-1, &state, WNOHANG | WUNTRACED)) > 0) // while保证回收每个子进程
    {
		sigprocmask(SIG_BLOCK, &mask, &prev); // 阻塞所有信号
		if (WIFEXITED(state)) // 正常终止
        {
			deletejob(jobs, pid);
		}
        else if (WIFSIGNALED(state)) // 信号导致终止
        {
			printf("Job [%d] (%d) terminated by signal %d\n", pid2jid(pid), pid, WTERMSIG(state));		
			deletejob(jobs, pid);
		}
        else if (WIFSTOPPED(state)) // 子进程停止
        {
			job = getjobpid(jobs, pid);
            if (job == NULL)
            {
                printf("Error: (%d): No such process\n",pid);
            }
			else
            {
                job->state = ST;
            }
			printf("Job [%d] (%d) stopped by signal %d\n", job->jid, pid, WSTOPSIG(state));
		}
		sigprocmask(SIG_SETMASK, &prev, NULL);	// 解锁
	}
	errno = old_errno; // 复原errno
}

对SIGCHLD信号,需要判断发送的原因。子进程正常终止、收到信号而终止、或者STOP时都会发送该信号。因此若正常终止或信号导致终止,则从jobs表中删除;若子进程停止,则只需要将job的状态改为STOP。

同样,需要在修改前后对信号加阻塞。

void sigint_handler(int sig) // 响应ctrl-c
{
    int old_errno = errno;
    pid_t pid = fgpid(jobs);
    if (pid != 0)
    {
        kill(-pid, sig);
    }
    errno = old_errno;
    return;
}

void sigtstp_handler(int sig) // 响应ctrl-z
{
    int old_errno = errno;
    pid_t pid = fgpid(jobs);
    if (pid != 0)
    {
        kill(-pid, sig);
    }
    errno = old_errno;
    return;
}

最后是ctrl-c和ctrl-z的相应。这里都只需要从jobs表中找到该job,并且将ctrl-c或ctrl-z的signal发送给子进程即可。

配合其他的辅助函数,这个程序便可以实现简单的shell功能,与参考文件中的示例shell输出无差。

./sdriver.pl -t trace01.txt -s ./tsh -a "-p"
#
# trace01.txt - Properly terminate on EOF.
#
./sdriver.pl -t trace01.txt -s ./tshref -a "-p"
#
# trace01.txt - Properly terminate on EOF.
#
./sdriver.pl -t trace02.txt -s ./tsh -a "-p"
#
# trace02.txt - Process builtin quit command.
#
./sdriver.pl -t trace02.txt -s ./tshref -a "-p"
#
# trace02.txt - Process builtin quit command.
#
./sdriver.pl -t trace03.txt -s ./tsh -a "-p"
#
# trace03.txt - Run a foreground job.
#
tsh> quit
./sdriver.pl -t trace03.txt -s ./tshref -a "-p"
#
# trace03.txt - Run a foreground job.
#
tsh> quit
./sdriver.pl -t trace04.txt -s ./tsh -a "-p"
#
# trace04.txt - Run a background job.
#
tsh> ./myspin 1 &
[1] (19812) ./myspin 1 &
./sdriver.pl -t trace04.txt -s ./tshref -a "-p"
#
# trace04.txt - Run a background job.
#
tsh> ./myspin 1 &
[1] (19817) ./myspin 1 &
./sdriver.pl -t trace05.txt -s ./tsh -a "-p"
#
# trace05.txt - Process jobs builtin command.
#
tsh> ./myspin 2 &
[1] (19824) ./myspin 2 &
tsh> ./myspin 3 &
[2] (19826) ./myspin 3 &
tsh> jobs
[1] (19824) Running ./myspin 2 &
[2] (19826) Running ./myspin 3 &
./sdriver.pl -t trace05.txt -s ./tshref -a "-p"
#
# trace05.txt - Process jobs builtin command.
#
tsh> ./myspin 2 &
[1] (19834) ./myspin 2 &
tsh> ./myspin 3 &
[2] (19836) ./myspin 3 &
tsh> jobs
[1] (19834) Running ./myspin 2 &
[2] (19836) Running ./myspin 3 &
./sdriver.pl -t trace06.txt -s ./tsh -a "-p"
#
# trace06.txt - Forward SIGINT to foreground job.
#
tsh> ./myspin 4
Job [1] (19846) terminated by signal 2
./sdriver.pl -t trace06.txt -s ./tshref -a "-p"
#
# trace06.txt - Forward SIGINT to foreground job.
#
tsh> ./myspin 4
Job [1] (19853) terminated by signal 2
./sdriver.pl -t trace07.txt -s ./tsh -a "-p"
#
# trace07.txt - Forward SIGINT only to foreground job.
#
tsh> ./myspin 4 &
[1] (19860) ./myspin 4 &
tsh> ./myspin 5
Job [2] (19862) terminated by signal 2
tsh> jobs
[1] (19860) Running ./myspin 4 &
./sdriver.pl -t trace07.txt -s ./tshref -a "-p"
#
# trace07.txt - Forward SIGINT only to foreground job.
#
tsh> ./myspin 4 &
[1] (19874) ./myspin 4 &
tsh> ./myspin 5
Job [2] (19876) terminated by signal 2
tsh> jobs
[1] (19874) Running ./myspin 4 &
./sdriver.pl -t trace08.txt -s ./tsh -a "-p"
#
# trace08.txt - Forward SIGTSTP only to foreground job.
#
tsh> ./myspin 4 &
[1] (19886) ./myspin 4 &
tsh> ./myspin 5
Job [2] (19888) stopped by signal 20
tsh> jobs
[1] (19886) Running ./myspin 4 &
[2] (19888) Stopped ./myspin 5 
./sdriver.pl -t trace08.txt -s ./tshref -a "-p"
#
# trace08.txt - Forward SIGTSTP only to foreground job.
#
tsh> ./myspin 4 &
[1] (19898) ./myspin 4 &
tsh> ./myspin 5
Job [2] (19900) stopped by signal 20
tsh> jobs
[1] (19898) Running ./myspin 4 &
[2] (19900) Stopped ./myspin 5 
./sdriver.pl -t trace09.txt -s ./tsh -a "-p"
#
# trace09.txt - Process bg builtin command
#
tsh> ./myspin 4 &
[1] (19912) ./myspin 4 &
tsh> ./myspin 5
Job [2] (19914) stopped by signal 20
tsh> jobs
[1] (19912) Running ./myspin 4 &
[2] (19914) Stopped ./myspin 5 
tsh> bg %2
[2] (19914) ./myspin 5 
tsh> jobs
[1] (19912) Running ./myspin 4 &
[2] (19914) Running ./myspin 5 
./sdriver.pl -t trace09.txt -s ./tshref -a "-p"
#
# trace09.txt - Process bg builtin command
#
tsh> ./myspin 4 &
[1] (19926) ./myspin 4 &
tsh> ./myspin 5
Job [2] (19928) stopped by signal 20
tsh> jobs
[1] (19926) Running ./myspin 4 &
[2] (19928) Stopped ./myspin 5 
tsh> bg %2
[2] (19928) ./myspin 5 
tsh> jobs
[1] (19926) Running ./myspin 4 &
[2] (19928) Running ./myspin 5 
./sdriver.pl -t trace10.txt -s ./tsh -a "-p"
#
# trace10.txt - Process fg builtin command. 
#
tsh> ./myspin 4 &
[1] (19942) ./myspin 4 &
tsh> fg %1
Job [1] (19942) stopped by signal 20
tsh> jobs
[1] (19942) Stopped ./myspin 4 &
tsh> fg %1
tsh> jobs
./sdriver.pl -t trace10.txt -s ./tshref -a "-p"
#
# trace10.txt - Process fg builtin command. 
#
tsh> ./myspin 4 &
[1] (19955) ./myspin 4 &
tsh> fg %1
Job [1] (19955) stopped by signal 20
tsh> jobs
[1] (19955) Stopped ./myspin 4 &
tsh> fg %1
tsh> jobs
./sdriver.pl -t trace11.txt -s ./tsh -a "-p"
#
# trace11.txt - Forward SIGINT to every process in foreground process group
#
tsh> ./mysplit 4
Job [1] (19968) terminated by signal 2
tsh> /bin/ps a
  PID TTY      STAT   TIME COMMAND
 1054 tty1     Ss+    0:00 /sbin/agetty --noclear tty1 linux
 8356 pts/2    Ss+    0:00 /bin/bash
18883 pts/0    Ss     0:00 -bash
19786 pts/0    S+     0:00 sh run.sh
19964 pts/0    S+     0:00 make test11
19965 pts/0    S+     0:00 /usr/bin/perl ./sdriver.pl -t trace11.txt -s ./tsh -a -p
19966 pts/0    S+     0:00 ./tsh -p
19973 pts/0    R      0:00 /bin/ps a
21890 pts/1    Ss+    0:00 /bin/bash
./sdriver.pl -t trace11.txt -s ./tshref -a "-p"
#
# trace11.txt - Forward SIGINT to every process in foreground process group
#
tsh> ./mysplit 4
Job [1] (19978) terminated by signal 2
tsh> /bin/ps a
  PID TTY      STAT   TIME COMMAND
 1054 tty1     Ss+    0:00 /sbin/agetty --noclear tty1 linux
 8356 pts/2    Ss+    0:00 /bin/bash
18883 pts/0    Ss     0:00 -bash
19786 pts/0    S+     0:00 sh run.sh
19974 pts/0    S+     0:00 make rtest11
19975 pts/0    S+     0:00 /usr/bin/perl ./sdriver.pl -t trace11.txt -s ./tshref -a -p
19976 pts/0    S+     0:00 ./tshref -p
19985 pts/0    R      0:00 /bin/ps a
21890 pts/1    Ss+    0:00 /bin/bash
./sdriver.pl -t trace12.txt -s ./tsh -a "-p"
#
# trace12.txt - Forward SIGTSTP to every process in foreground process group
#
tsh> ./mysplit 4
Job [1] (19992) stopped by signal 20
tsh> jobs
[1] (19992) Stopped ./mysplit 4 
tsh> /bin/ps a
  PID TTY      STAT   TIME COMMAND
 1054 tty1     Ss+    0:00 /sbin/agetty --noclear tty1 linux
 8356 pts/2    Ss+    0:00 /bin/bash
18883 pts/0    Ss     0:00 -bash
19786 pts/0    S+     0:00 sh run.sh
19986 pts/0    S+     0:00 make test12
19987 pts/0    S+     0:00 /usr/bin/perl ./sdriver.pl -t trace12.txt -s ./tsh -a -p
19990 pts/0    S+     0:00 ./tsh -p
19992 pts/0    T      0:00 ./mysplit 4
19993 pts/0    T      0:00 ./mysplit 4
20000 pts/0    R      0:00 /bin/ps a
21890 pts/1    Ss+    0:00 /bin/bash
./sdriver.pl -t trace12.txt -s ./tshref -a "-p"
#
# trace12.txt - Forward SIGTSTP to every process in foreground process group
#
tsh> ./mysplit 4
Job [1] (20007) stopped by signal 20
tsh> jobs
[1] (20007) Stopped ./mysplit 4 
tsh> /bin/ps a
  PID TTY      STAT   TIME COMMAND
 1054 tty1     Ss+    0:00 /sbin/agetty --noclear tty1 linux
 8356 pts/2    Ss+    0:00 /bin/bash
18883 pts/0    Ss     0:00 -bash
19786 pts/0    S+     0:00 sh run.sh
20001 pts/0    S+     0:00 make rtest12
20002 pts/0    S+     0:00 /usr/bin/perl ./sdriver.pl -t trace12.txt -s ./tshref -a -p
20005 pts/0    S+     0:00 ./tshref -p
20007 pts/0    T      0:00 ./mysplit 4
20008 pts/0    T      0:00 ./mysplit 4
20011 pts/0    R      0:00 /bin/ps a
21890 pts/1    Ss+    0:00 /bin/bash
./sdriver.pl -t trace13.txt -s ./tsh -a "-p"
#
# trace13.txt - Restart every stopped process in process group
#
tsh> ./mysplit 4
Job [1] (20020) stopped by signal 20
tsh> jobs
[1] (20020) Stopped ./mysplit 4 
tsh> /bin/ps a
  PID TTY      STAT   TIME COMMAND
 1054 tty1     Ss+    0:00 /sbin/agetty --noclear tty1 linux
 8356 pts/2    Ss+    0:00 /bin/bash
18883 pts/0    Ss     0:00 -bash
19786 pts/0    S+     0:00 sh run.sh
20012 pts/0    S+     0:00 make test13
20013 pts/0    S+     0:00 /usr/bin/perl ./sdriver.pl -t trace13.txt -s ./tsh -a -p
20018 pts/0    S+     0:00 ./tsh -p
20020 pts/0    T      0:00 ./mysplit 4
20021 pts/0    T      0:00 ./mysplit 4
20025 pts/0    R      0:00 /bin/ps a
21890 pts/1    Ss+    0:00 /bin/bash
tsh> fg %1
tsh> /bin/ps a
  PID TTY      STAT   TIME COMMAND
 1054 tty1     Ss+    0:00 /sbin/agetty --noclear tty1 linux
 8356 pts/2    Ss+    0:00 /bin/bash
18883 pts/0    Ss     0:00 -bash
19786 pts/0    S+     0:00 sh run.sh
20012 pts/0    S+     0:00 make test13
20013 pts/0    S+     0:00 /usr/bin/perl ./sdriver.pl -t trace13.txt -s ./tsh -a -p
20018 pts/0    S+     0:00 ./tsh -p
20030 pts/0    R      0:00 /bin/ps a
21890 pts/1    Ss+    0:00 /bin/bash
./sdriver.pl -t trace13.txt -s ./tshref -a "-p"
#
# trace13.txt - Restart every stopped process in process group
#
tsh> ./mysplit 4
Job [1] (20037) stopped by signal 20
tsh> jobs
[1] (20037) Stopped ./mysplit 4 
tsh> /bin/ps a
  PID TTY      STAT   TIME COMMAND
 1054 tty1     Ss+    0:00 /sbin/agetty --noclear tty1 linux
 8356 pts/2    Ss+    0:00 /bin/bash
18883 pts/0    Ss     0:00 -bash
19786 pts/0    S+     0:00 sh run.sh
20031 pts/0    S+     0:00 make rtest13
20032 pts/0    S+     0:00 /usr/bin/perl ./sdriver.pl -t trace13.txt -s ./tshref -a -p
20035 pts/0    S+     0:00 ./tshref -p
20037 pts/0    T      0:00 ./mysplit 4
20038 pts/0    T      0:00 ./mysplit 4
20041 pts/0    R      0:00 /bin/ps a
21890 pts/1    Ss+    0:00 /bin/bash
tsh> fg %1
tsh> /bin/ps a
  PID TTY      STAT   TIME COMMAND
 1054 tty1     Ss+    0:00 /sbin/agetty --noclear tty1 linux
 8356 pts/2    Ss+    0:00 /bin/bash
18883 pts/0    Ss     0:00 -bash
19786 pts/0    S+     0:00 sh run.sh
20031 pts/0    S+     0:00 make rtest13
20032 pts/0    S+     0:00 /usr/bin/perl ./sdriver.pl -t trace13.txt -s ./tshref -a -p
20035 pts/0    S+     0:00 ./tshref -p
20046 pts/0    R      0:00 /bin/ps a
21890 pts/1    Ss+    0:00 /bin/bash
./sdriver.pl -t trace14.txt -s ./tsh -a "-p"
#
# trace14.txt - Simple error handling
#
tsh> ./bogus
./bogus: Command not found.
tsh> ./myspin 4 &
[1] (20055) ./myspin 4 &
tsh> fg
fg command requires PID or %jobid argument
tsh> bg
bg command requires PID or %jobid argument
tsh> fg a
fg: argument must be a PID or %jobid
tsh> bg a
bg: argument must be a PID or %jobid
tsh> fg 9999999
(9999999): No such process
tsh> bg 9999999
(9999999): No such process
tsh> fg %2
%2: No such job
tsh> fg %1
Job [1] (20055) stopped by signal 20
tsh> bg %2
%2: No such job
tsh> bg %1
[1] (20055) ./myspin 4 &
tsh> jobs
[1] (20055) Running ./myspin 4 &
./sdriver.pl -t trace14.txt -s ./tshref -a "-p"
#
# trace14.txt - Simple error handling
#
tsh> ./bogus
./bogus: Command not found
tsh> ./myspin 4 &
[1] (20075) ./myspin 4 &
tsh> fg
fg command requires PID or %jobid argument
tsh> bg
bg command requires PID or %jobid argument
tsh> fg a
fg: argument must be a PID or %jobid
tsh> bg a
bg: argument must be a PID or %jobid
tsh> fg 9999999
(9999999): No such process
tsh> bg 9999999
(9999999): No such process
tsh> fg %2
%2: No such job
tsh> fg %1
Job [1] (20075) stopped by signal 20
tsh> bg %2
%2: No such job
tsh> bg %1
[1] (20075) ./myspin 4 &
tsh> jobs
[1] (20075) Running ./myspin 4 &
./sdriver.pl -t trace15.txt -s ./tsh -a "-p"
#
# trace15.txt - Putting it all together
#
tsh> ./bogus
./bogus: Command not found.
tsh> ./myspin 10
Job [1] (20097) terminated by signal 2
tsh> ./myspin 3 &
[1] (20101) ./myspin 3 &
tsh> ./myspin 4 &
[2] (20103) ./myspin 4 &
tsh> jobs
[1] (20101) Running ./myspin 3 &
[2] (20103) Running ./myspin 4 &
tsh> fg %1
Job [1] (20101) stopped by signal 20
tsh> jobs
[1] (20101) Stopped ./myspin 3 &
[2] (20103) Running ./myspin 4 &
tsh> bg %3
%3: No such job
tsh> bg %1
[1] (20101) ./myspin 3 &
tsh> jobs
[1] (20101) Running ./myspin 3 &
[2] (20103) Running ./myspin 4 &
tsh> fg %1
tsh> quit
./sdriver.pl -t trace15.txt -s ./tshref -a "-p"
#
# trace15.txt - Putting it all together
#
tsh> ./bogus
./bogus: Command not found
tsh> ./myspin 10
Job [1] (20122) terminated by signal 2
tsh> ./myspin 3 &
[1] (20127) ./myspin 3 &
tsh> ./myspin 4 &
[2] (20129) ./myspin 4 &
tsh> jobs
[1] (20127) Running ./myspin 3 &
[2] (20129) Running ./myspin 4 &
tsh> fg %1
Job [1] (20127) stopped by signal 20
tsh> jobs
[1] (20127) Stopped ./myspin 3 &
[2] (20129) Running ./myspin 4 &
tsh> bg %3
%3: No such job
tsh> bg %1
[1] (20127) ./myspin 3 &
tsh> jobs
[1] (20127) Running ./myspin 3 &
[2] (20129) Running ./myspin 4 &
tsh> fg %1
tsh> quit
./sdriver.pl -t trace16.txt -s ./tsh -a "-p"
#
# trace16.txt - Tests whether the shell can handle SIGTSTP and SIGINT
#     signals that come from other processes instead of the terminal.
#
tsh> ./mystop 2
Job [1] (20147) stopped by signal 20
tsh> jobs
[1] (20147) Stopped ./mystop 2
tsh> ./myint 2
Job [2] (20156) terminated by signal 2
./sdriver.pl -t trace16.txt -s ./tshref -a "-p"
#
# trace16.txt - Tests whether the shell can handle SIGTSTP and SIGINT
#     signals that come from other processes instead of the terminal.
#
tsh> ./mystop 2
Job [1] (20163) stopped by signal 20
tsh> jobs
[1] (20163) Stopped ./mystop 2
tsh> ./myint 2
Job [2] (20168) terminated by signal 2

发表评论

邮箱地址不会被公开。 必填项已用*标注