Computer-Science

Process related system calls

1. process

A program loaded in the memory.
process = body + process descriptor
body = code + data + stack

2. System calls to manage processes

What happens when a program calls fork():

3. Exercise

0) Try โ€œex0โ€ below. Who is the parent of โ€œex0โ€?

ex0.c:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(){
   int x,y;
   x=getpid();
   y=getppid();
   printf("PID:%d PPID:%d\n", x, y);
   for(;;);   // to make this process alive
}
$ gcc โ€“o ex0 ex0.c

Run โ€œex0โ€ with &. & puts process in the background so that you can issue next command to the shell.

$ ex0&
[1] 2950
PID:2950 PPID:2219

Now confirm with ps โ€“f.

$ ps  โ€“f
 UID   PID  PPID   C STIME   TTY           TIME CMD
  502  1358  4160   0  9:19AM ttys000    0:00.37 /bin/zsh -l
  502  1405     1   0  9:19AM ttys000    0:00.01 /bin/zsh -l
  502  2219  2217   0  9:24AM ttys001    0:00.61 -zsh
  502  2258     1   0  9:24AM ttys001    0:00.01 -zsh
  502  2950  2219   0  9:28AM ttys001    0:15.66 ./ex0

Now kill โ€œex0โ€.

$ kill 2950
[1]  + 2950 terminated  ./ex0

,where xxxx is the pid of โ€œex0โ€.

์œ„ ์‚ฌ์ง„์ฒ˜๋Ÿผ โ€œex0โ€๋ฅผ kill ํ•œ ํ›„, ps โ€“f๋ฅผ ํ†ตํ•ด ํ™•์ธํ•ด๋ณด๋ฉด ์ •์ƒ์ ์œผ๋กœ ์ข…๋ฃŒ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

1) Try โ€œex1โ€ below.

ex1.c:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(){
   int x;
   x=fork();
   printf("hello\n");
   for(;;);
}
$ gcc โ€“o ex1 ex1.c
$ ex1&
hello
hello
$ ps  -f
  502  1358  4160   0  9:19AM ttys000    0:00.37 /bin/zsh -l
  502  1405     1   0  9:19AM ttys000    0:00.01 /bin/zsh -l
  502  2219  2217   0  9:24AM ttys001    0:00.74 -zsh
  502  2258     1   0  9:24AM ttys001    0:00.01 -zsh
  502  4653  2219   0  9:39AM ttys001    0:08.18 ./ex1
  502  4662  4653   0  9:39AM ttys001    0:08.07 ./ex1
$ kill xxxx(pid of ex1) yyyy(pid of ex1's child)

2) Modify โ€œex1.cโ€ such that it prints its own pid and the parent pid. Confirm the result with ps -ef.

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(){
   int x;
   x=fork();
   printf("hello. my pid is %d\n", getpid());
   printf("and my parent pid is %d\n", getppid());
   for(;;);
}
$ ps -ef
  UID   PID  PPID   C STIME   TTY           TIME CMD
    0     1     0   0 ํ† 10AM ??         6:26.11 /sbin/launchd
    ...
  502 23834     1   0  2:08PM ??         3:05.88 /Applications/iTerm 2.app/Contents/MacOS/iTerm2
  502 23835 23834   0  2:08PM ??         0:00.02 /Users/oneonlee/Library/Application Support/iTerm2/iTermServer-3.4.15 /Users/oneonlee/Library/Application Support/iTerm2/iterm2-daemon-1.socket
    ...
  502  1358  4160   0  9:19AM ttys000    0:00.37 /bin/zsh -l
  502  1405     1   0  9:19AM ttys000    0:00.01 /bin/zsh -l
    0  2217 23835   0  9:24AM ttys001    0:00.36 login -fp oneonlee
  502  2219  2217   0  9:24AM ttys001    0:00.97 -zsh
  502  2258     1   0  9:24AM ttys001    0:00.01 -zsh
  502  7759  2219   0  9:57AM ttys001    0:10.25 ./ex2
  502  7760  7759   0  9:57AM ttys001    0:09.97 ./ex2
    0  8254  2219   0 10:00AM ttys001    0:00.01 ps -ef

3) Try below (โ€œex2.cโ€). Which hello is displayed by the parent and which hello is by the child?

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(){
   int x;
   x=fork();
   printf("hello: %d\n", x);
}

parent์™€ child์˜ PID๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ์ฃผ์–ด์ง„ ์ฝ”๋“œ์— for(;;); ๋ฌดํ•œ๋ฃจํ”„๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ํ”„๋กœ๊ทธ๋žจ์ด ์ข…๋ฃŒ๋˜์ง€ ์•Š๊ฒŒ ํ•˜์˜€๋‹ค.

$ gcc โ€“o ex2 ex2.c
$ ex2
hello: 36711
hello: 0

fork()๋Š” ์„ฑ๊ณตํ•  ๊ฒฝ์šฐ ์ž์‹์˜ PID๋ฅผ ๋ถ€๋ชจ์—๊ฒŒ ์ „๋‹ฌํ•˜๋ฉฐ, ์ž์‹์€ 0์„ ๋ฐ˜ํ™˜ ๋ฐ›๋Š”๋‹ค.

๋”ฐ๋ผ์„œ โ€œhello: 36711โ€๋ฅผ ์ถœ๋ ฅํ•œ ๊ฒƒ์ด parent์ด๋ฉฐ(PID:36710), โ€œhello: 0โ€๋ฅผ ์ถœ๋ ฅํ•œ ๊ฒƒ์ด child์ด๋‹ค. (PID:36711)

4) Try below (โ€œex3.cโ€) and show all ancestor processes of โ€œex3โ€ (parent, parent of parent, etc).

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(){
   int x;
   x=fork();
   printf("hello: %d\n", x);
   for(;;); // make the parent and child alive
}

$ gcc โ€“o ex3 ex3.c
$ ex3 &
hello: 36711
hello: 0
$ ps  -ef
  UID   PID  PPID   C STIME   TTY           TIME CMD
  502 35338 35336   0 10:32AM ttys001    0:00.47 -zsh
  502 36710 35338   0 10:39AM ttys001    0:06.08 ./ex3
  502 36711 36710   0 10:39AM ttys001    0:06.00 ./ex3

PPID๋ฅผ ๋”ฐ๋ผ๊ฐ€๋ฉฐ ps์˜ ์ถœ๋ ฅ๊ฐ’์„ ์ฝ์–ด๋ณด๋ฉด, zsh ํ”„๋กœ์„ธ์Šค(35338)๋กœ๋ถ€ํ„ฐ โ€œex3(36710)โ€ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ƒ์„ฑ๋˜์—ˆ์œผ๋ฉฐ โ€œex3(36710)โ€๋ถ€ํ„ฐ โ€œex3(36711)โ€ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ƒ์„ฑ๋˜์—ˆ๋‹ค.

5) Try below (โ€œex4.cโ€). Which message was displayed by the parent and which one by the child?

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(){
   int x;
   x=fork();
   if (x==0){
       printf("hello: %d\n", x);
   }else{
       printf("hi: %d \n", x);
   }
}
$ gcc โ€“o ex4 ex4.c
$ ex4

x๋Š” fork()๋กœ๋ถ€ํ„ฐ ๋ฐ˜ํ™˜๋œ ๊ฐ’์ด๊ธฐ ๋•Œ๋ฌธ์— x๊ฐ€ 0์ด๋ฉด ํ˜„์žฌ ํ”„๋กœ์„ธ์Šค๋Š” ์ž์‹ ํ”„๋กœ์„ธ์Šค์ด๊ณ , 0์ด ์•„๋‹ˆ๋ฉด ๋ถ€๋ชจ ํ”„๋กœ์„ธ์Šค์ด๋‹ค. ๋”ฐ๋ผ์„œ โ€œhiโ€๋Š” ๋ถ€๋ชจ ํ”„๋กœ์„ธ์Šค์—์„œ ์ถœ๋ ฅ๋œ ๊ฐ’์ด๊ณ , โ€œhelloโ€๋Š” ๋ณต์ œ๋œ ์ž์‹ ํ”„๋กœ์„ธ์Šค์—์„œ ์ถœ๋ ฅ๋œ ๊ฐ’์ด๋‹ค.

6) Try below (โ€œex5.cโ€). How many hellos do you see? Explain why you have that many hellos. Draw the process tree.

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(){
   int x,y;
   x=fork();
   y=fork();
   printf("hello: %d %d\n", x, y);
}
$ gcc โ€“o ex5 ex5.c
$ ex5
hello: 41139 41140
hello: 41139 0
hello: 0 41141
hello: 0 0

7) Try below (โ€œex6.cโ€). How many hellos do you see? Explain why you have that many hellos.

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(){
    int x,y;
    x=fork();
    printf("hello: %d\n", x);
    y=fork();
    printf("hello: %d\n", y);
}

$ gcc โ€“o ex6 ex6.c
$ ex6
hello: 44973
hello: 44974
hello: 0
hello: 0
hello: 44975
hello: 0

8) Try below (โ€œex7.cโ€). When you run โ€œex7โ€, how many processes run at the same time? Which process finishes first and which process finishes last? Show the finishing order of the processes. Run โ€œex7โ€ again and compare the finishing order with that of the first run.

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main(){
   int x, i;
   for(i=0;i<5;i++){
      x=fork();
      if (x==0){ // child
         int k;
         for(k=0;k<10;k++){
            printf("%d-th child running %d-th iteration \n", i, k);
            fflush(stdout);         // to make printf work immediately
            // sleep(1);              // sleep 1 second
        }
        printf("\n\n")
        exit(0);   // child exits after 10 iterations
      }
   }
   // now parent
   printf("parent exits\n");
}
$ ./ex9
0-th child running 0-th iteration
1-th child running 0-th iteration
3-th child running 0-th iteration
parent exits
4-th child running 0-th iteration
2-th child running 0-th iteration
0-th child running 1-th iteration
1-th child running 1-th iteration
3-th child running 1-th iteration
4-th child running 1-th iteration
2-th child running 1-th iteration
0-th child running 2-th iteration
1-th child running 2-th iteration
3-th child running 2-th iteration
4-th child running 2-th iteration
2-th child running 2-th iteration
0-th child running 3-th iteration
1-th child running 3-th iteration
3-th child running 3-th iteration
4-th child running 3-th iteration
2-th child running 3-th iteration
0-th child running 4-th iteration
1-th child running 4-th iteration
3-th child running 4-th iteration
4-th child running 4-th iteration
2-th child running 4-th iteration
0-th child running 5-th iteration
1-th child running 5-th iteration
3-th child running 5-th iteration
4-th child running 5-th iteration
2-th child running 5-th iteration
0-th child running 6-th iteration
1-th child running 6-th iteration
3-th child running 6-th iteration
4-th child running 6-th iteration
2-th child running 6-th iteration
0-th child running 7-th iteration
1-th child running 7-th iteration
3-th child running 7-th iteration
4-th child running 7-th iteration
2-th child running 7-th iteration
0-th child running 8-th iteration
1-th child running 8-th iteration
3-th child running 8-th iteration
4-th child running 8-th iteration
2-th child running 8-th iteration
0-th child running 9-th iteration
1-th child running 9-th iteration
3-th child running 9-th iteration
4-th child running 9-th iteration
2-th child running 9-th iteration

fork()๋ฅผ ์ด 5๋ฒˆ ์ˆ˜ํ–‰ํ•˜๋ฏ€๋กœ ์ตœ์ข…์ ์œผ๋กœ๋Š” ํ•˜๋‚˜์˜ ๋ถ€๋ชจ ํ”„๋กœ์„ธ์Šค์™€ 5๊ฐœ์˜ ์ž์‹ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค. ๋ถ€๋ชจ ํ”„๋กœ์„ธ์Šค๋Š” โ€œparent exitsโ€๋ฅผ ์ถœ๋ ฅํ•˜๊ณ  ์ž์‹ ํ”„๋กœ์„ธ์Šค๋ณด๋‹ค ๋จผ์ € ์ข…๋ฃŒ๋œ๋‹ค. ์ด๋•Œ ์ž์‹ ํ”„๋กœ์„ธ์Šค๋Š” ๋ชจ๋‘ ๋ถ€๋ชจ๋ฅผ ์žƒ์–ด๋ฒ„๋ฆฐ ๊ณ ์•„ ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋˜์–ด PPID๊ฐ€ init ํ”„๋กœ์„ธ์Šค์˜ PID์ธ 1์„ ๊ฐ€๋ฆฌํ‚ค๊ฒŒ ๋œ๋‹ค.

์ž์‹ ํ”„๋กœ์„ธ์Šค๋Š” 0๋ถ€ํ„ฐ 9๊นŒ์ง€ ์ˆœํšŒํ•˜๋ฉฐ printf๋กœ ๋ฌธ์ž์—ด์„ ์ถœ๋ ฅํ•œ๋‹ค.

์ด๋•Œ fflush(stdout)๋Š” ํ‘œ์ค€์ถœ๋ ฅ์ŠคํŠธ๋ฆผ์„ ๋น„์›Œ์ฃผ๋Š” ์—ญํ• ๋กœ, ๋ฒ„ํผ์— ๋ฌธ์ž์—ด์„ ๋„ฃ๊ณ  ๊ธฐ๋‹ค๋ฆฌ์ง€ ๋ง๊ณ  ๋ฐ”๋กœ ์ถœ๋ ฅํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค.

sleep(1) ์ž์‹ ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋ถ€๋ชจ ํ”„๋กœ์„ธ์Šค๋ณด๋‹ค ๋‚˜์ค‘์— ์ข…๋ฃŒ๋จ์„ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•ด ํ”„๋กœ์„ธ์Šค ์‹คํ–‰ ์‹œ๊ฐ„์— ๋”œ๋ ˆ์ด๋ฅผ ๋„ฃ์€ ๊ฒƒ์ด๋‹ค.

ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋ฐ˜๋ณต๋ฌธ ์ˆœํšŒ๋ฅผ ๋งˆ์ณค๋‹ค๋ฉด exit(0)๋ฅผ ํ†ตํ•ด ์ž์‹ ํ”„๋กœ์„ธ์Šค๋ฅผ ์ข…๋ฃŒํ•œ๋‹ค.

๋”ฐ๋ผ์„œ ํ”„๋กœ๊ทธ๋žจ์€ ์ด 5๊ฐœ์˜ ์ž์‹ ํ”„๋กœ์„ธ์Šค๋กœ๋ถ€ํ„ฐ 5*10๋ฒˆ printf๋ฅผ ํ˜ธ์ถœํ•  ๊ฒƒ์ด๋‹ค.

9) If you delete exit(0) in โ€œex7.cโ€, how many processes will be created? Confirm your answer by modifying the code such that each process displays its own pid.

$ ./ex7-1
0-th child running 0-th iteration(pid: 79605)
1-th child running 0-th iteration(pid: 79606)
2-th child running 0-th iteration(pid: 79607)
parent exits
3-th child running 0-th iteration(pid: 79608)
4-th child running 0-th iteration(pid: 79609)
0-th child running 1-th iteration(pid: 79605)
2-th child running 1-th iteration(pid: 79607)
3-th child running 1-th iteration(pid: 79608)
4-th child running 1-th iteration(pid: 79609)
1-th child running 1-th iteration(pid: 79606)
0-th child running 2-th iteration(pid: 79605)
3-th child running 2-th iteration(pid: 79608)
2-th child running 2-th iteration(pid: 79607)
4-th child running 2-th iteration(pid: 79609)
1-th child running 2-th iteration(pid: 79606)
0-th child running 3-th iteration(pid: 79605)
2-th child running 3-th iteration(pid: 79607)
4-th child running 3-th iteration(pid: 79609)
1-th child running 3-th iteration(pid: 79606)
3-th child running 3-th iteration(pid: 79608)
2-th child running 4-th iteration(pid: 79607)
4-th child running 4-th iteration(pid: 79609)
1-th child running 4-th iteration(pid: 79606)
0-th child running 4-th iteration(pid: 79605)
3-th child running 4-th iteration(pid: 79608)
4-th child running 5-th iteration(pid: 79609)
1-th child running 5-th iteration(pid: 79606)
3-th child running 5-th iteration(pid: 79608)
0-th child running 5-th iteration(pid: 79605)
2-th child running 5-th iteration(pid: 79607)
1-th child running 6-th iteration(pid: 79606)
3-th child running 6-th iteration(pid: 79608)
0-th child running 6-th iteration(pid: 79605)
4-th child running 6-th iteration(pid: 79609)
2-th child running 6-th iteration(pid: 79607)
0-th child running 7-th iteration(pid: 79605)
3-th child running 7-th iteration(pid: 79608)
2-th child running 7-th iteration(pid: 79607)
4-th child running 7-th iteration(pid: 79609)
1-th child running 7-th iteration(pid: 79606)
3-th child running 8-th iteration(pid: 79608)
2-th child running 8-th iteration(pid: 79607)
4-th child running 8-th iteration(pid: 79609)
1-th child running 8-th iteration(pid: 79606)
0-th child running 8-th iteration(pid: 79605)
0-th child running 9-th iteration(pid: 79605)
3-th child running 9-th iteration(pid: 79608)
1-th child running 9-th iteration(pid: 79606)
4-th child running 9-th iteration(pid: 79609)
2-th child running 9-th iteration(pid: 79607)
parent exits
parent exits
4-th child running 0-th iteration(pid: 79635)
2-th child running 0-th iteration(pid: 79638)
1-th child running 0-th iteration(pid: 79636)
3-th child running 0-th iteration(pid: 79637)
parent exits
parent exits
3-th child running 0-th iteration(pid: 79639)
4-th child running 0-th iteration(pid: 79640)
2-th child running 0-th iteration(pid: 79641)
4-th child running 0-th iteration(pid: 79642)
3-th child running 0-th iteration(pid: 79643)
parent exits
...
$ ./ex7-1 | grep -c "iteration"
310

๋งŒ์•ฝ exit(0))๋ฅผ ์ œ๊ฑฐํ•œ๋‹ค๋ฉด ์ž์‹ ํ”„๋กœ์„ธ์Šค๊ฐ€ 10๋ฒˆ printf๋ฅผ ํ•œ ์ดํ›„์— ๋‹ค์‹œ ์ƒ์œ„ ๋ฐ˜๋ณต๋ฌธ์œผ๋กœ ๋Œ์•„์™€ ์ƒˆ๋กœ์šด ์ž์‹ ํ”„๋กœ์„ธ์Šค๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

๊ฐ€์žฅ ๋ง๋‹จ์˜ ์ž์‹๋งŒ printf๋ฅผ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๊ฐ€์žฅ ๋ง๋‹จ์˜ ์ž์‹ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์•„๋‹ˆ๋”๋ผ๋„ fork()๋ฅผ ํ†ตํ•ด ์ƒˆ๋กœ์šด ํ”„๋กœ์„ธ์Šค๋ฅผ ๊ณ„์† ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด๋Š” ์ด๋ถ„๋ฒ•์œผ๋กœ ์ฆ์‹ํ•˜๋Š” ์„ธํฌ ๊ฐ™์ด ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๋‹ค. 5ํšŒ ๋ฐ˜๋ณต ์‹œ 31(= 2^0+2^1+2^2+2^3+2^4)๊ฐœ์˜ ์ž์‹ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ƒ์„ฑ๋˜๋ฉฐ, ๋”ฐ๋ผ์„œ 31๊ฐœ์˜ ์ž์‹ ํ”„๋กœ์„ธ์Šค๋กœ๋ถ€ํ„ฐ 310๋ฒˆ printf๊ฐ€ ํ˜ธ์ถœ๋  ๊ฒƒ์ด๋‹ค.


4. Extra practice

1. Write a program that creates a child. The parent and child both print their PIDโ€™s, but make sure the child always runs first.

$ ./child_first
child: 19019
parent: 19018

See child_first.c (Ref Exercise 3)

2. Write program that creates 3 children and let them print their PIDโ€™s.

$ ./pid_of_children
Child(0)'s PID: 28899
Child(1)'s PID: 28900
Child(2)'s PID: 28901

See pid_of_children.c