fork()
+ exec()
In the following problems, assume fork()
and execv()
always succeed.
You can obtain the solutions from CLAC by checking out the following repo:
git clone ~j-hui/cs3157-pub/examples/fork-exec-puzzles
exec-demo
Consider the following program, exec-demo
, which is implemented as follows:
int main(int argc, char **argv) {
assert(argc == 3);
int n1 = atoi(argv[1]);
int n2 = atoi(argv[2]);
if (n1 > 0) {
char s1[100]; sprintf(s1, "%d", n1 - 1); argv[1] = s1;
char s2[100]; sprintf(s2, "%d", n2 + n1); argv[2] = s2;
execv(*argv, argv);
printf("%d\n", n1);
}
printf("%d\n", n2);
return 0;
}
Write the output when exec-demo
is run with arguments 4
and 100
, i.e.:
./exec-demo 4 100
fork()
ing with some numbersConsider the following programs, which both print a fixed number of lines:
// 12.2.1
int main(void) {
pid_t pid = fork();
if (pid) {
waitpid(pid, NULL, 0);
printf("3\n");
}
sleep(2);
printf("1\n");
return 0;
}
// 12.2.2
int main(void) {
int p1, p2, p3, x;
p1 = fork(); sleep(1); p2 = fork(); sleep(1); p3 = fork();
x = (p1 != 0) + (p2 != 0) + (p3 != 0);
printf("%d\n", x);
return 0;
}
// 12.2.3
int main(int argc, char **argv) {
if (argc != 2) {
char *a[] = { argv[0], "1", NULL };
execv(*a, a);
}
int n = atoi(argv[1]);
if (n > 3)
return 0;
sleep(1);
printf("%d\n", n);
sprintf(argv[1], "%d", n + 1);
pid_t pid = fork();
execv(*argv, argv);
if (pid) {
waitpid(pid, NULL, 0);
printf("%d\n", 0);
}
return 0;
}
Each program is run with no arguments; for each program, answer the following:
0
printed?1
printed?2
printed?3
printed?4
printed?Specify UNPREDICTABLE
if the answer may change from run to run.
fffork()
Write the output of the following C program:
void print_char(char c) {
fwrite(&c, 1, 1, stderr);
}
static int i = 3;
void fffork(char **a) {
if (*a) {
pid_t pid = fork();
if (pid == 0) {
// child process
i--;
fffork(a + 1);
print_char(a[0][i]);
} else {
// parent process
waitpid(pid, NULL, 0); // no status & no options
print_char('0');
print_char('\n');
}
}
}
int main(void) {
char *a[4] = { "123", "456", "789", NULL };
fffork(a);
return 0;
}
Also draw a diagram of all fffork()
processes, at the moment when the first
character is printed on screen. Draw your diagram using the same style as the
f
option of the ps
command, i.e., as a process tree.
Label each process with process IDs. Assume that the first fffork
process’s
process ID is 2000, and that each subsequent fffork
processes increments the
process ID by 1.
For each process, indicate the values of the variable i
and what the pointer
a
is pointing to at that moment.
eeexec()
Consider the following C program, eeexec.c
:
void eeexec(char *cmd, int n) {
if (n > 0) {
printf("A %d\n", n);
eeexec(cmd, n - 1);
char buf[100];
sprintf(buf, "%d", n - 1);
char *a[3] = { cmd, buf, NULL };
execv(*a, a);
printf("B %d\n", n);
}
}
int main(int argc, char **argv) {
assert(argc == 2);
eeexec(argv[0], atoi(argv[1]));
printf("C %s\n", argv[1]);
return 0;
}
The program is built and run as follows:
$ gcc -o eeexec eeexec.c
$ ./eeexec 4
Specify UNPREDICTABLE
if the answer may change from run to run;
specify HANG
if the program runs forever without terminating.