Here is the source code of my program
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <string.h>
#include <locale.h>
#include <errno.h>
int main(int argc, char* argv[]) {
printf("Hello world (pid:%d)!\n", (int)getpid());
int pipefd[2];
int pipe_ret = pipe(pipefd);
if (pipe_ret == -1) {
printf("%s\n", strerror_l(errno, uselocale((locale_t)0)));
exit(1);
}
int rc1 = fork();
if (rc1 < 0) { // fork failed; exit
fprintf(stderr, "fork failed\n");
exit(1);
}
else if (rc1 == 0) { // child (new process)
printf("Hello, I am child (pid:%d)!\n", (int)getpid());
dup2(pipefd[0], STDIN_FILENO);
close(pipefd[1]);
int j = 0;
while (j < 1) {
scanf("%d", &j);
printf("I am child %d and I have just read %d from the other child.\n",(int)getpid(), j);
}
}
else { // parent goes down this path (main)
printf("Hello, I am parent of %d (pid:%d).\n", rc1, (int)getpid());
int rc2 = fork();
if (rc2 < 0) { // fork failed; exit
fprintf(stderr, "fork failed\n");
exit(1);
}
else if (rc2 == 0) { // child (new process)
printf("Hello, I am child (pid:%d)!\n", (int)getpid());
dup2(pipefd[1], STDOUT_FILENO);
close(pipefd[0]);
for (int i = 0; i < 2; i++) {
printf("%d\n", i);
sleep(1);
}
}
else {
printf("Hello, I am parent of %d (pid:%d).\n", rc2, (int)getpid());
wait(NULL); // Wait for any child process to finish
wait(NULL); // Wait for the other child process to finish
}
}
return 0;
}
I want to trace in which order the parent and child processes switch. Yet I want to do that from the outside of the program. For this purpose, I first use this command.
perf record -e cs ./5_8
I have the following output.
Hello world (pid:9460)!
Hello, I am parent of 9462 (pid:9460).
Hello, I am parent of 9463 (pid:9460).
Hello, I am child (pid:9463)!
Hello, I am child (pid:9462)!
I am child 9462 and I have just read 0 from the other child.
I am child 9462 and I have just read 1 from the other child.
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.002 MB perf.data (13 samples) ]
It makes me think there are 13 context switches in total. Then to see the order, I use this command.
perf script -F comm,pid,event,time -f
I have this output.
5_8 9460 3151.197904: cs:
5_8 9460 3151.198436: cs:
5_8 9460 3151.198811: cs:
5_8 9460 3151.199271: cs:
5_8 9460 3151.199720: cs:
5_8 9460 3151.200381: cs:
5_8 9460 3151.201129: cs:
5_8 9463 3151.201185: cs:
5_8 9462 3151.201219: cs:
5_8 9463 3152.201512: cs:
5_8 9460 3152.201765: cs:
5_8 9460 3153.202438: cs:
5_8 9460 3153.203312: cs:
So the first question is why there are subsequent context switches between the process with PID 9460 (the parent) and itself. And why are there so many of them? How would one interpret them based on the source code?
The second question is whether the following interpretation is correct:
The first context switch of 9463 (the child who writes in the pipe) is after it popped in the first number (0) and invoked sleep().
The first context switch of the process with PID 9462 (the child that reads from the pipe) occurs after it has read the first number (0) and started waiting for the following number.
The second context switch of 9463 (the child who writes in the pipe) is after it popped in the second number (1) and invoked sleep().
There is no need for the second context switch for the process with PID 9462 (the child that reads from the pipe) since it terminates having read the second number.