Sometimes zombie or stopped process may hang around because of
faulty code that created them.
It is useful to know these commands to manually identify and/or
get rid of them:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <sys/types.h>
4 #include <unistd.h>
5 #include <sys/wait.h>
6 #include <string.h>
7 #include <fcntl.h>
8 #include <signal.h>
9 #include <errno.h>
10 #include "csapp.h"
11 void handler(int sig)
12 {
13 int status;
14 pid_t pid;
15
16 pid = waitpid(-1, &status, 0);
17
18 if ( pid < 0 ) {
19 printf("waitpid error: %s\n", strerror(errno));
20 } else {
21 printf("child %d terminated\n", pid);
22 }
23 }
24
25 int main()
26 {
27 int i;
28 pid_t pid;
29
30 Signal(SIGCHLD, handler);
31 for(i = 0; i < 5; i++) {
32 if ( (pid = fork()) == 0 ) {
33 exit(10+i);
34 }
35 }
36
37 printf("parent waits in infinite loop: (ctrl-c to end)\n");
38 while(1) {
39 }
40
41 return 0;
42 }
1
2 void handler(int sig)
3 {
4 int status;
5 pid_t pid;
6
7 pid = waitpid(-1, &status, 0);
8
9 if ( pid < 0 ) {
10 printf("waitpid error: %s\n", strerror(errno));
11 } else {
12 printf("child %d terminated ", pid);
13 if (WIFEXITED(status)) {
14 printf("with exit value: %d\n", WEXITSTATUS(status));
15 } else {
16 printf("(did not terminate normally)\n");
17 }
18 }
19 }
20
21 int main()
22 {
23 int i;
24 pid_t pid;
25
26 Signal(SIGCHLD, handler);
27 for(i = 0; i < 5; i++) {
28 if ( (pid = fork()) == 0 ) {
29 exit(10+i);
30 }
31 }
32
33 printf("parent waits in infinite loop: (ctrl-c to end)\n");
34 while(1) {
35 }
36
37
38 return 0;
39 }
1
2 void handler(int sig)
3 {
4 int status;
5 pid_t pid;
6
7 pid = waitpid(-1, &status, 0);
8
9 if ( pid < 0 ) {
10 printf("waitpid error: %s\n", strerror(errno));
11 } else {
12 printf("child %d terminated\n", pid);
13 if (WIFEXITED(status)) {
14 printf("child exit value: %d\n", WEXITSTATUS(status));
15 } else {
16 printf("(did not terminate normally)\n");
17 }
18 }
19 }
20
21 int main()
22 {
23 int i;
24 pid_t pid;
25
26 Signal(SIGCHLD, handler);
27 for(i = 0; i < 5; i++) {
28 if ( (pid = fork()) == 0 ) {
29 sleep(1);
30 printf("child %d exiting\n", getpid());
31 exit(10+i);
32 }
33 }
34
35 printf("parent waits in infinite loop: (ctrl-c to end)\n");
36 while(1) {
37 }
38 return 0;
39 }
1
2 void handler(int sig)
3 {
4 int status;
5 pid_t pid;
6
7 while( (pid = waitpid(-1, &status, 0)) > 0 ) {
8 printf("child %d terminated ", pid);
9 if (WIFEXITED(status)) {
10 printf("with exit value: %d\n", WEXITSTATUS(status));
11 } else {
12 printf("(did not terminate normally)\n");
13 }
14 }
15 if ( pid < 0 ) {
16 printf("waitpid error: %s\n", strerror(errno));
17 }
18 }
19
20 int main()
21 {
22 int i;
23 pid_t pid;
24
25 Signal(SIGCHLD, handler);
26 for(i = 0; i < 5; i++) {
27 if ( (pid = fork()) == 0 ) {
28 sleep(1);
29 printf("child %d exiting\n", getpid());
30 exit(10+i);
31 }
32 }
33 printf("parent waits in infinite loop: (ctrl-c to end)\n");
34
35 while(1) {
36 }
37 return 0;
38 }
1
2 void handler(int sig)
3 {
4 int status;
5 pid_t pid;
6
7 while( (pid = waitpid(-1, &status, 0)) > 0 ) {
8 printf("child %d terminated ", pid);
9 if (WIFEXITED(status)) {
10 printf("with exit value: %d\n", WEXITSTATUS(status));
11 } else {
12 printf("(did not terminate normally)\n");
13 }
14 }
15 if ( pid < 0 && errno != ECHILD) {
16 printf("waitpid error: %s\n", strerror(errno));
17 }
18 }
19
20 int main()
21 {
22 int i;
23 pid_t pid;
24
25 Signal(SIGCHLD, handler);
26 for(i = 0; i < 5; i++) {
27 if ( (pid = fork()) == 0 ) {
28 sleep(1);
29 printf("child %d exiting\n", getpid());
30 exit(10+i);
31 }
32 }
33 printf("parent waits in infinite loop: (ctrl-c to end)\n");
34
35 while(1) {
36 }
37 return 0;
38 }
1
2 pid_t pid;
3 int counter = 0;
4
5 void handler1(int sig)
6 {
7 counter++;
8 printf("counter = %d\n", counter);
9 fflush(stdout);
10 kill(pid, SIGUSR1);
11 }
12
13 void handler2(int sig)
14 {
15 counter += 3;
16 printf("counter = %d\n", counter);
17 exit(0);
18 }
19
20 int main()
21 {
22
23 Signal(SIGUSR1, handler1);
24
25 if ((pid = fork()) == 0) {
26 Signal(SIGUSR1, handler2);
27 kill(getppid(), SIGUSR1);
28 while(1) {
29 }
30 } else {
31 pid_t p;
32 int status;
33
34 if ((p = wait(&status)) > 0) {
35 counter += 2;
36 printf("counter = %d\n", counter);
37 }
38 }
39
40 return 0;
41 }
1
2 pid_t pid;
3 int counter = 0;
4
5 void handler1(int sig)
6 {
7 counter++;
8 printf("counter = %d\n", counter);
9 fflush(stdout);
10 kill(pid, SIGUSR1);
11 }
12
13 void handler2(int sig)
14 {
15 counter += 3;
16 printf("counter = %d\n", counter);
17 exit(0);
18 }
19
20 int main()
21 {
22 sigset_t s;
23
24 Signal(SIGUSR1, handler1);
25
26 sigemptyset(&s);
27 sigaddset(&s, SIGUSR1);
28 sigprocmask(SIG_BLOCK, &s, 0);
29
30 if ((pid = fork()) == 0) {
31 sigprocmask(SIG_UNBLOCK, &s, 0);
32 Signal(SIGUSR1, handler2);
33 kill(getppid(), SIGUSR1);
34 while(1) {
35 }
36 } else {
37 pid_t p;
38 int status;
39 sigprocmask(SIG_UNBLOCK, &s, 0);
40 if ((p = wait(&status)) > 0) {
41 counter += 2;
42 printf("counter = %d\n", counter);
43
44 }
45 }
46
47 return 0;
48 }
1
2 void sigint_handler(int sig)
3 {
4 printf("pid %d got SIGINT, terminating\n", getpid());
5 exit(0);
6 }
7
8
9 int main()
10 {
11 pid_t pid;
12
13 Signal(SIGINT, sigint_handler);
14 if ( (pid = fork()) == 0 ) {
15 printf("child pid = %d, gid = %d\n", getpid(), getpgrp());
16 pause();
17 }
18 printf("parent pid = %d, gid = %d\n", getpid(), getpgrp());
19 pause();
20
21 return 0;
22 }
1
2 pid_t pid;
3
4 void sigint_handler(int sig)
5 {
6 printf("pid %d got SIGINT, terminating\n", getpid());
7 exit(0);
8 }
9
10
11 int main()
12 {
13
14 Signal(SIGINT, sigint_handler);
15 if ( (pid = fork()) == 0 ) {
16 setpgid(0,0);
17 printf("child pid = %d, gid = %d\n", getpid(), getpgrp());
18 pause();
19 }
20 printf("parent pid = %d, gid = %d\n", getpid(), getpgrp());
21 pause();
22
23 return 0;
24 }
1
2 pid_t cpid;
3
4 void sigint_handler(int sig)
5 {
6 printf("pid %d got SIGINT, ", getpid());
7 if (cpid != 0 ) {
8 printf("sent SIGINT to child %d, then ", cpid);
9 kill(cpid, SIGINT);
10 }
11 printf("exited\n");
12 exit(0);
13 }
14
15
16 int main()
17 {
18
19 Signal(SIGINT, sigint_handler);
20 if ( (cpid = fork()) == 0 ) {
21 setpgid(0,0);
22 printf("child pid = %d, gid = %d\n", getpid(), getpgrp());
23 pause();
24 }
25
26 printf("parent pid = %d, gid = %d\n", getpid(), getpgrp());
27 pause();
28
29 return 0;
30 }
Your shell should be able to stop the foreground process if the
user types ctrl-z.
Your shell can do this by forwarding the
SIGTSTP signal to the foreground job.
The signal should be forwarded to all processes in the
foreground job, not just the process group leader.
To restart the job later when the shell command is fg or bg,
send a SIGCONT signal to all processes in the process group of
the stopped job.
Some possible user input commands for job control (not all
correct):
Some correct commands (assuming the pid and job numbers are valid
fg 1400
fg %2
fg
Some invalid commands
fg 99999999
fg a
fg
In each case when do_bgfg(argv) is called, what will be
in the string array argv?
C functions - scanf, fscanf, sscanf[14] [top]
#include <stdio.h>
int scanf(const char *format, ...);
int fscanf(FILE *stream, const char *format, ...);
int sscanf(const char *str, const char *format, ...);
Examples
int ret;
int n,m;
ret = scanf("%d%d", &n, &m);
The return value is the number of successful conversions.
Parsing Problem using sscanf[15] [top]
argv[0] = "fg";
argv[1] = "%2"; or argv[1] = "1400";
argv[2] = NULL;
int pid;
int jid;
int ret;
ret = sscanf(argv[1], "%d", &pid);
or
ret = sscanf(argv[1], "%%%d", &jid);
If ret is 0 for one of these, the conversion failed. So
try the other one.
tsh.c and job control[16] [top]
int addjob(struct job_t *jobs, pid_t pid, int state, char *cmdline);
The shell will need to call this each function to add a job the
process it creates for any command that is not built in.
Where does the job id get created? (by addjob)
Is the job id an index into the jobs array? (no)
How do you get the job entry if you know the process id? the
job id?
struct job_t { /* The job struct */
pid_t pid; /* job PID */
int jid; /* job ID [1, 2, ...] */
int state; /* UNDEF, BG, FG, or ST */
char cmdline[MAXLINE]; /* command line */
};
struct job_t jobs[MAXJOBS]; /* The job list */
struct job_t *getjobpid(struct job_t *jobs, pid_t pid);
struct job_t *getjobjid(struct job_t *jobs, int jid);
Example: If you know the pid how do you change the state
to BG:
struct job_t *p;
p = getjobpid(jobs, pid);
if ( p != NULL ) {
p->state = BG;
}
Always pointers are not NULL before trying to access what it
points to!
The return value of this function could be NULL if the pid is
invalid. E.g., the user entered an incorrect pid or the job was
not correctly added to the job list, etc.
pid_t fgpid(struct job_t *jobs);
This function returns the pid of the foreground process
if there is a foreground process.
If there currently is no foreground process, this function
returns 0. So be careful!
A file named Makefile is included in the
shlab-handout.tar file for the shell lab.
The Makefile also has rules to help you run each of the
16 tests.
For example, to print the instructions to run test 1, type
make test01
and then follow the instructions.
Using etags in emacs[21] [top]
In the directory containing the tsh.c file, create an
etags index:
etags tsh.c
This will create a file named TAGS. You only need to do
this once.
In emacs, search for a tag by typing M-. (Alt
plus the "." or if that doesn't work, the ESC key and "."
Then at the mini-prompt area at the bottom of the emacs window,
type the full name or a prefix of
- global variable
- function name
- preprocessor defined symbol (e.g. #define MAXARGS)