๐Ÿงญ KAIST JUNGLE/Pintos

[PintOS] User Program - System Call2 (Project 2, TIL)

seungineer = seungwoo + engineer 2024. 5. 14. 03:35

KAIST PintOS ๊ฐ•์˜ ๋ฐ Instruction, ํ•œ์–‘๋Œ€ PintOS Slides๋ฅผ ์ฐธ๊ณ ํ•˜๋ฉฐ ํ•™์Šตํ•œ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•˜์˜€์Šต๋‹ˆ๋‹ค.

ํ•™์Šต ๋„์ค‘ ์ž‘์„ฑํ•œ ๋‚ด์šฉ์ด๋ผ ํ‹€๋ฆฐ ๋‚ด์šฉ์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๋””๋ฒ„๊น…

fork() ํ•จ์ˆ˜ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐ์„œ ์‹œ๊ฐ„์„ ๋„ˆ๋ฌด ๋งŽ์ด ์ผ๋‹ค. ์œ„ ์งค์ฒ˜๋Ÿผ ๋ฒ„๊ทธ๋ฅผ ๊ณ ์น˜๋ฉด, ๋‹ค๋ฅธ ๋ฐ์„œ ๋ฒ„๊ทธ๊ฐ€ ๋‚ฌ๊ณ , ๊ทธ ๋ฒ„๊ทธ๋ฅผ ๊ณ ์น˜๋ฉด ์ด์ „ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๊ฐ€ ํ†ต๊ณผ๊ฐ€ ์•ˆ ๋˜๋Š” ์ผ์ด ์—„์ฒญ ๋งŽ์•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋ฌดํ•œ ๋ฒ„๊ทธ์˜ ๊ตด๋ ˆ ๋์— 'ALL PASSED' ๋ฌธ๊ตฌ๋ฅผ ๋ดค์„ ๋•Œ์˜ ๊ฐ๋™์„ ์•„์ง๋„ ์žŠ์ง€ ๋ชป ํ•˜๊ฒ ๋‹ค(์งœ๋ฆฟํ•ด).

ํ”„๋กœ์„ธ์Šค ๊ณ„์ธต ๊ตฌ์กฐ ๊ฐœ์š”

Process์˜ ์ •๋ณด์— ๋ถ€๋ชจ์™€ ์ž์‹ field๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์ด๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์ œ์ž‘ํ•œ๋‹ค. ์ด๋•Œ, project1์—์„œ ์‚ฌ์šฉ๋˜์—ˆ๋˜ semaphore ๊ฐœ๋…์ด ์‚ฌ์šฉ๋œ๋‹ค. Process ๊ด€๋ จ system call์—๋Š” fork(), exit(), exec(), wait()์ด ์žˆ๋‹ค. ํ•˜๋‚˜ํ•˜๋‚˜ ๋งŒ๋“ค์–ด๊ฐ€๋ฉฐ ์œ ์˜ํ•ด์•ผ ํ•  ์ , ์•Œ์•„์•ผ ํ•  ์ ์„ ์ •๋ฆฌํ•œ๋‹ค.

 

exec

์ด ํ•จ์ˆ˜๋Š” ํ˜„์žฌ process๋ฅผ ์ž…๋ ฅ ๋ฐ›์€ ์‹คํ–‰ ํŒŒ์ผ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ํ•จ์ˆ˜์ด๋‹ค. ์ƒˆ๋กœ์šด process๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋ฉฐ, process๊ฐ€ ํ˜„์žฌ ๊ฐ–๊ณ  ์žˆ๋Š” context๋ฅผ ์‹คํ–‰ํ•˜๊ณ ์ž ํ•˜๋Š” ํŒŒ์ผ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๋Š๋‚Œ์ด๋‹ค. fork์™€ ์ž์ฃผ ํ•จ๊ป˜ ์“ฐ์ด๋Š” ์‹œ์Šคํ…œ ์ฝœ์ด๋‹ค.

๊ตฌํ˜„

  • ์ธ์ž๋กœ ๋ฐ›์€ cmd_line์˜ ์ฃผ์†Œ ์œ ํšจ์„ฑ ํ™•์ธ(check_address()) 
    • ์ธ์ž์˜ ์ €์žฅ๋œ ์œ„์น˜๋Š” '์œ ์ € ์˜์—ญ'์ด์–ด์•ผ๋งŒ ํ•จ
  • palloc_get_page() ํ•จ์ˆ˜์™€ strlcpy() ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด cmd_line_copy ๋ณ€์ˆ˜๋กœ ๋ณต์‚ฌ
    • cmd_line_copy ๋ณ€์ˆ˜ ์ƒ์„ฑ ์ด์œ  : caller vs load์˜ race condition ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด
  • ์ดํ›„ process_exec() ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ cmd_line์˜ ํ”„๋กœ์„ธ์Šค๋ฅผ load()
    • ์ด๋Š” stack์— ์Œ“์ž„
  • ์˜ˆ์™ธ ์ฒ˜๋ฆฌ
    • ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น ์‹คํŒจ โžก๏ธ exit(-1)
    • process_exec() return -1 โžก๏ธ exit(-1)
int exec(const char *cmd_line)
{
	check_address(cmd_line);

	char *cmd_line_copy;
	cmd_line_copy = palloc_get_page(0);
	if (cmd_line_copy == NULL) // ์˜ˆ์™ธ ์ฒ˜๋ฆฌ
		exit(-1);
	strlcpy(cmd_line_copy, cmd_line, PGSIZE);

	if (process_exec(cmd_line_copy) == -1) // ์˜ˆ์™ธ ์ฒ˜๋ฆฌ
		exit(-1); 
}

 

fork

CMU, Introduction to Computer System, spring 2009

Pintos Instruction์—์„œ....

%RBX, %RSP, %RBP,  %R12 - %R15๋ฅผ ์ œ์™ธํ•œ ๋‚˜๋จธ์ง€ ๋ ˆ์ง€์Šคํ„ฐ๊ฐ’์€ ๋ณต์ œํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค. ๋ฐ˜๋“œ์‹œ ์ž์‹ ํ”„๋กœ์„ธ์Šค์˜ process id๋ฅผ ๋ฐ˜ํ™˜ํ•ด๋ผ. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์œ ํšจํ•œ pid๊ฐ€ ์•„๋‹ˆ๋‹ค. ์ž์‹ ํ”„๋กœ์„ธ์Šค์—์„œ, ๋ฆฌํ„ด๊ฐ’์€ ๋ฐ˜๋“œ์‹œ 0์ด์–ด์•ผ ํ•œ๋‹ค. ์ž์‹ ํ”„๋กœ์„ธ์Šค๋Š” ๋ฐ˜๋“œ์‹œ ๋ถ€๋ชจ ํ”„๋กœ์„ธ์Šค๋กœ๋ถ€ํ„ฐ ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ, ๊ฐ€์ƒ ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„ ๋“ฑ์„ ํฌํ•จํ•œ ์ž์›์„ ๋ณต์‚ฌํ•ด์™€์•ผ ํ•œ๋‹ค.

๋ถ€๋ชจ ํ”„๋กœ์„ธ์Šค๋Š” ์ž์‹ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ๋ณต์ œ๋œ ๊ฒƒ์„ ์•Œ๊ณ  ๋‚˜์„œ fork๋กœ๋ถ€ํ„ฐ ๋ฆฌํ„ดํ•ด์•ผ ํ•œ๋‹ค. ์ฆ‰, ๋งŒ์•ฝ ์ž์‹ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ž์›์„ ๋ณต์ œํ•˜๋Š”๋ฐ ์‹คํŒจํ•˜๋ฉด ๋ถ€๋ชจ ํ”„๋กœ์„ธ์Šค์˜ fork() ํ˜ธ์ถœ์€ ๋ฐ˜๋“œ์‹œ TID_ERROR๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•œ๋‹ค. ์ด ํ…œํ”Œ๋ฆฟ์€ threads/mmu.c ๋‚ด์— ์žˆ๋Š” pml4_for_each() ๋ฅผ ์‚ฌ์šฉํ•ด ์ „์ฒด user memory ๊ณต๊ฐ„์„ ๋ณต์ œํ•˜๋Š”๋ฐ, ๋Œ€์‘ํ•˜๋Š” ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ” ๊ตฌ์กฐ์ฒด๋ฅผ ํฌํ•จํ•œ๋‹ค. ํ•˜์ง€๋งŒ ๋นˆ ๋ถ€๋ถ„(pte_for_each_func์—์„œ)์„ ์ฑ„์›Œ์•ผ ํ•œ๋‹ค.

 

fork ์‹œ์Šคํ…œ ์ฝœ์€ ํ˜„์žฌ process์™€ ์™„์ „ํžˆ ๋™์ผํ•œ process๋ฅผ ํ•˜๋‚˜ ๋” ๋งŒ๋“œ๋Š” ์‹œ์Šคํ…œ ์ฝœ์ด๋‹ค. ๋™์ผํ•˜๊ฒŒ ๋งŒ๋“ ๋‹ค๋Š” ์˜๋ฏธ๋ฅผ ์‰ฝ๊ฒŒ ์ƒ๊ฐํ•˜๋ฉด, ๋ถ€๋ชจ process์˜ context๋ฅผ ์ž์‹์ด ์•Œ๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ž์‹ process๋Š” main() ํ•จ์ˆ˜์—์„œ๋ถ€ํ„ฐ ๋‹ค์‹œ ์‹œ์ž‘ํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋ถ€๋ชจ process๊ฐ€ ๋งˆ์ง€๋ง‰์œผ๋กœ ์‹คํ–‰ํ•œ ์ฝ”๋“œ๋ถ€ํ„ฐ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. Pintos์—์„œ๋Š” ํ•˜๋‚˜ ๋” ๋งŒ๋“  process๋ฅผ '์ž์‹ process'๋ผ๊ณ  ํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ์™„์ „ํžˆ ๋™์ผํ•œ process๋ฅผ ์–ด๋–ป๊ฒŒ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ์„๊นŒ? fork ํ•จ์ˆ˜์˜ return ๊ฐ’์œผ๋กœ pintos์—์„œ๋Š” ๊ตฌ๋ถ„ํ•œ๋‹ค.

process_fork() ํ•จ์ˆ˜์˜ return value
pid ๊ฐ’์— ๋‹ด๊ธฐ๊ฑฐ๋‚˜ TID_ERROR ๊ฐ’์ด return ๋˜๋Š”๋ฐ, ์ด ๊ฐ’์€ ์•„๋ž˜ ๋ฒ”์œ„์— ํ•ด๋‹นํ•  ๋•Œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋œป์„ ๊ฐ–๋Š”๋‹ค.
1. ์Œ์ˆ˜ : fork๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์™„๋ฃŒ๋˜์ง€ ์•Š์•„ ์ž์‹ process๊ฐ€ ๋งŒ๋“ค์–ด์ง€์ง€ ์•Š์•˜์Œ์„ ์˜๋ฏธ
2. 0 : ์ƒˆ๋กœ ๋งŒ๋“ค์–ด์ง„ ์ž์‹ process๋Š” 0์„ return ๋ฐ›์Œ์œผ๋กœ์จ ์ž์‹ process์ž„์„ ํ™•์ธ
3. ์–‘์ˆ˜ : ์ž์‹ process๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ๋งŒ๋“ค์–ด์กŒ์„ ๋•Œ, ๋ถ€๋ชจ process๊ฐ€ pid ๊ฐ’์„ return ๋ฐ›์Œ

CMU, Introduction to Computer System, spring 2009

output
linux> ./fork
parent: x=0
child : x=2

๋งŒ์•ฝ ๊ฐ๊ฐ์˜ process์—์„œ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๋ฉด, fork() ํ•จ์ˆ˜๋ฅผ ๋งŒ๋‚ฌ์„ ๋•Œ, ์ž์‹ process์—์„œ๋Š” 0์ด return ๋˜๊ณ , ์ดํ›„ ๋ถ€๋ชจ process์—์„œ๋Š” pid๊ฐ€ return ๋˜๋ฉฐ, ๊ฐ๊ฐ์˜ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋œ๋‹ค.

 

๋ถ€๋ชจ process์˜ context๋ฅผ ๋ณต์‚ฌํ•ด์˜จ๋‹ค๋Š” ๊ฒƒ์€ ๋ฌด์—‡์ผ๊นŒ? fork๋ผ๋Š” ์‹œ์Šคํ…œ ์ฝœ์ด ํ˜ธ์ถœ๋˜๋ฉด user ํ”„๋กœ๊ทธ๋žจ์—์„œ syscall_handler() ๋กœ ์ง„์ž…ํ•˜๊ฒŒ ๋œ๋‹ค. thread ๊ตฌ์กฐ์ฒด ๋‚ด์— ์žˆ๋Š” interrupt frame(if)์€ context switching์ด ๋ฐœ์ƒํ•  ๋•Œ๋งˆ๋‹ค ๊ฐ’์ด ๋ฐ”๋€Œ๊ฒŒ ๋œ๋‹ค. ์ฆ‰, syscall_hanlder()๋กœ user context(a.k.a ๋ถ€๋ชจ process)์˜ interrupt frame์„ ์ „๋‹ฌํ•œ๋‹ค. thread_create() ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์ž์‹ process๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ ๋ถ€๋ชจ context๋ฅผ ๋ณต์‚ฌํ•ด์˜ฌ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

๊ทธ๋Ÿฐ๋ฐ, fork ๊ณผ์ • ์ค‘์— context switching์œผ๋กœ ์ธํ•ด ๋ถ€๋ชจ process์˜ interrupt frame์ด ๋ฐ”๋€Œ๊ฒŒ ๋˜๋ฉด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ์ž์‹ process๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ํ˜„์žฌ thread์˜ interrupt frame์„ ๊ฐ€์ ธ์˜ค๋„๋ก ๊ตฌํ˜„ํ•œ๋‹ค๋ฉด context switching์œผ๋กœ ์ธํ•ด ๊ฐ€์ ธ์™€์•ผ ํ•˜๋Š” ์ž์‹ ์˜ ๋ถ€๋ชจ process interrupt frame์„ ๊ฐ€์ ธ์˜ค์ง€ ๋ชปํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค(๋ฌธ๋งฅ์ด ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ์ž์‹ process ์ฝ”๋“œ๋Š” ์—‰๋šฑํ•œ ๊ณณ์—์„œ๋ถ€ํ„ฐ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋‹ค!).

์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ interrupt frame์„ ์ €์žฅํ•˜๋Š” ์ถ”๊ฐ€ ๋ณ€์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด syscall_hanlder์— ์ง„์ž…ํ•  ๋•Œ๋งˆ๋‹ค user context์˜ interrupt frame์„ ์ €์žฅํ•ด๋‘”๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋ถ€๋ชจ process์˜ ๋ฌธ๋งฅ์„ ๊ฐ€์ ธ์™€์•ผ ํ•  ๋•Œ, ์ €์žฅ๋œ interrupt frame์„ ๊ฐ€์ ธ์˜ค๊ธฐ์— ํ˜„์žฌ thread์˜ interrupt frame์„ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ๋ณด๋‹ค ์ •ํ™•ํ•˜๋‹ค. ์ด ๊ณผ์ •์€ __do_fork() ํ•จ์ˆ˜์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

process_fork() ๊ตฌํ˜„

์ •๋ฆฌํ•˜๋ฉด 1. ๋ถ€๋ชจ process๋Š” ํ˜„์žฌ ์‹คํ–‰ ์ค‘์ธ user process์ด๊ณ  2. interrupt frame์€ system call ํ˜ธ์ถœ๋กœ ์ธํ•ด ๋ฐ”๋€Œ์—ˆ๋‹ค ๋˜ํ•œ, _if.rsp๋Š” kernel stack์— ์œ„์น˜!

์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ๊ฒƒ ์ฒ˜๋Ÿผ thread ๊ตฌ์กฐ์ฒด์— parent_if field๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , ์ž์‹ process๋ฅผ ๋‹ด์•„์ค„ ๋ฆฌ์ŠคํŠธ field๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

struct thread {
	...
	struct list child_list;             /* ์ž์‹ ํ”„๋กœ์„ธ์Šค๋ฅผ ๋‹ด์•„์ค„ ๋ฆฌ์ŠคํŠธ*/
	struct list_elem child_elem;		/* child_list์— ๋‹ด์•„์ค„ elem */ 
	...
	/* Owned by thread.c. */
	struct intr_frame tf;               /* Information for switching */
	unsigned magic;                     /* Detects stack overflow. */
	struct intr_frame parent_if;         /* ์œ ์ € ์Šคํƒ์˜ ์ •๋ณด๋ฅผ ์ธํ„ฐ๋ŸฝํŠธ ํ”„๋ ˆ์ž„ ์•ˆ์— ๋„ฃ์–ด์„œ, ์ปค๋„ ์Šคํƒ์œผ๋กœ ๋„˜๊ฒจ์ฃผ๊ธฐ ์œ„ํ•จ */ //๋ณ€๊ฒฝ์‚ฌํ•ญ - ์ž์‹์—๊ฒŒ ๋„˜๊ฒจ์ค„ intr_frame
};

 

๋ถ€๋ชจ process๊ฐ€ thread_create() ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์ž์‹ process๋ฅผ ์ƒ์„ฑํ•œ ํ›„, ์ž์‹ process๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ๋กœ๋“œ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ค์•ผ ํ•œ๋‹ค. ์ด๋•Œ, semaphore๊ฐ€ ์‚ฌ์šฉ๋œ๋‹ค. ์ž์‹ process์˜ fork_sema์— ๋Œ€ํ•ด sema_down()์„ ํ˜ธ์ถœํ•˜์—ฌ, ์ž์‹ process๊ฐ€ ์ •์ƒ ์ƒ์„ฑ๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐํ•œ๋‹ค. ์ •์ƒ ์ƒ์„ฑ ํ›„ ์ž์‹ process๋Š” sema_up()์„ ํ˜ธ์ถœํ•ด ์ž์‹ ์˜ semaphore๋ฅผ ํ•ด์ œํ•จ์œผ๋กœ์จ ๋ถ€๋ชจ process๊ฐ€ continue๋˜๋„๋ก ํ•œ๋‹ค.

 

tid_t process_fork(const char *name, struct intr_frame *if_ UNUSED) {
    /* Clone current thread to new thread.*/
    struct thread *curr = thread_current();
    
    memcpy(&curr->parent_if, if_, sizeof(struct intr_frame)); // ๋ถ€๋ชจ process if_ ๋ณต์‚ฌ -> ์ž์‹ process ์‚ฌ์šฉ ์˜ˆ์ •
    
    tid_t pid = thread_create(name, PRI_DEFAULT, __do_fork, curr); // __do_fork ํ•จ์ˆ˜๋ฅผ ์ž์‹ process ์ƒ์„ฑ ์‹œ ์‹คํ–‰ํ•จ์ˆ˜๋กœ ์ง€์ •
    if (pid == TID_ERROR)
        return TID_ERROR;
    
    struct thread *child = get_child(pid); // ์ƒ์„ฑ๋œ ์ž์‹ process์˜ thread ๊ตฌ์กฐ์ฒด ํ• ๋‹น
    sema_down(&child->fork_sema);          // ์ž์‹ process ๋กœ๋”ฉ ์™„๋ฃŒ ์ „๊นŒ์ง€ ๋ถ€๋ชจ process ๋Œ€๊ธฐ
    
    if (child->exit_status == -1)
        return TID_ERROR;
    
    return pid;
}

 

__do_fork()

Pintos ๋‚ด hint

/* TODO: Your code goes here.
 * TODO: Hint) To duplicate the file object, use `file_duplicate`
 * TODO:           in include/filesys/file.h. Note that parent should not return
 * TODO:           from the fork() until this function successfully duplicates
 * TODO:           the resources of parent.*/

 

์ž์‹ process์˜ ์ƒ์„ฑ ์ดํ›„ ๋ถ€๋ชจ process๊ฐ€ ๊ฐ€์ง„ ๊ฒƒ๊ณผ ๋™์ผํ•œ FDT(File Descriptor Table)๊ฐ€ ์ƒ์„ฑ๋˜์–ด์•ผ ํ•œ๋‹ค. ์ฃผ์–ด์ง„ Hint์—์„œ ์•Œ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ด file_duplicate() ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด file์„ ์‰ฝ๊ฒŒ ๋ณต์‚ฌํ•  ์ˆ˜ ์žˆ๋‹ค.

static void __do_fork(void *aux){
    ...
    /* FDT ๋ณต์‚ฌ */
    for (int i = 0; i < FDT_COUNT_LIMIT; i++) {
        struct file *file = parent->fdt[i];
        if (file == NULL)
            continue;
        if (file > 2)
            file = file_duplicate(file);
        current->fdt[i] = file;
    }
    current->next_fd = parent->next_fd;

    sema_up(&current->fork_sema); // ๋กœ๋“œ๊ฐ€ ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ๋˜ ๋ถ€๋ชจ ๋Œ€๊ธฐ ํ•ด์ œ
    process_init();
    ...
   }

CMU

๋งˆ์ง€๋ง‰์œผ๋กœ fork_sema๋ฅผ sema_up()ํ•˜์—ฌ ๋ถ€๋ชจ process์˜ ๋Œ€๊ธฐ๊ฐ€ ๋๋‚˜๋„๋ก ํ•œ๋‹ค.

wait

๋ถ€๋ชจ ํ”„๋กœ์„ธ์Šค๋Š” ์ž์‹ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ข…๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๋ฉˆ์ถฐ์žˆ์–ด์•ผ ํ•œ๋‹ค. ๋ถ€๋ชจ ํ”„๋กœ์„ธ์Šค๊ฐ€ wait(์ž์‹_ํ”„๋กœ์„ธ์Šค_id)๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด wait ํ•จ์ˆ˜์˜ ๋ฆฌํ„ด ๊ฐ’์œผ๋กœ ์ž์‹ ํ”„๋กœ์„ธ์Šค์˜ exit status๋ฅผ ๋ฐ›๊ฒŒ ๋œ๋‹ค(๋น„์ •์ƒ ์ข…๋ฃŒ ์‹œ exit status๋Š” -1). ๋ถ€๋ชจ ํ”„๋กœ์„ธ์Šค๋Š” ์ด๋ฅผ ํ†ตํ•ด ์ž์‹ ํ”„๋กœ์„ธ์Šค์˜ ์ข…๋ฃŒ ์—ฌ๋ถ€๋ฅผ ์•Œ ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค. ์ถ”ํ›„ ์ž์‹ ํ”„๋กœ์„ธ์Šค ์ข…๋ฃŒ ์‹œ ์ž์‹ ์ž์› ๋ฐ˜ํ™˜ ํ•  ๋•Œ ์‹ ํ˜ธ๋กœ ์‚ฌ์šฉ๋œ๋‹ค.

ํ˜„์žฌ๋Š” while(), for ๋“ฑ์œผ๋กœ ๋Œ€๊ธฐ ์ƒํƒœ๋ฅผ ๋ชจ์‚ฌ ํ•ด๋‘์—ˆ์„ํ…๋ฐ ์ด๋Š” ๋‹น์—ฐํžˆ ํ•„์š” ์—†์–ด์ง„๋‹ค. wait() ํ•จ์ˆ˜๋Š” ์‚ฌ์šฉ์ž์—๊ฒŒ ์ œ๊ณต๋˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค(API)์—ญํ• ์„ ํ•˜๋ฉฐ, process_wait() ํ•จ์ˆ˜๋Š” ์‹ค์ œ๋กœ ์ž์‹ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ข…๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋กœ์ง์„ ๊ตฌํ˜„ํ•œ๋‹ค. ์ฆ‰, ๋‘ ํ•จ์ˆ˜๋ฅผ ๊ตฌ๋ถ„(์บก์Šํ™”)ํ•˜์—ฌ์•ผ ํ•œ๋‹ค.

๊ตฌํ˜„

wait ๊ตฌํ˜„

  • wait ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ๋ฐ›์€ pid๋ฅผ process_wait() ํ•จ์ˆ˜๋กœ ๋„˜๊น€

process_wait()

  • ํ˜„์žฌ ์‹คํ–‰ ์ค‘์ธ thread๋ฅผ ๊ฐ€์ ธ์˜ด
  • ์ธ์ž๋กœ ๋ฐ›์€ pid์— ํ•ด๋‹นํ•˜๋Š” thread๋ฅผ ๊ฐ€์ ธ์˜ด
    • ์˜ˆ์™ธ ์ฒ˜๋ฆฌ : ํ•ด๋‹นํ•˜๋Š” ์ž์‹ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ -1 ๋ฐ˜ํ™˜
  • wait_sema๋ฅผ ์‚ฌ์šฉํ•ด ์ž์‹ process์˜ ์ข…๋ฃŒ๋ฅผ ๊ธฐ๋‹ค๋ฆผ
    • ์ด ๋™์•ˆ ํ˜„์žฌ thread(๋ถ€๋ชจ)๋Š” ๋Œ€๊ธฐ ์ƒํƒœ๊ฐ€ ๋จ
  • ์ž์‹ process๊ฐ€ ์ข…๋ฃŒ๋œ ๊ฒฝ์šฐ ๋ถ€๋ชจ process์˜ ์ž์‹ ๋ชฉ๋ก์—์„œ ์ œ๊ฑฐ
  • free_sema๋ฅผ ์‚ฌ์šฉํ•ด ์ž์‹ ํ”„๋กœ์„ธ์Šค์˜ ์ž์›์„ ํ•ด์ œํ•  ์ˆ˜ ์žˆ๋„๋ก semaphore๋กœ ์‹ ํ˜ธ๋ฅผ ๋ณด๋ƒ„
  • ์ž์‹ ํ”„๋กœ์„ธ์Šค์˜ exit_status ๋ฐ˜ํ™˜

์ด๋ ‡๊ฒŒ process_wait() ํ•จ์ˆ˜์—์„œ ํ”„๋กœ์„ธ์Šค ๊ฐ„ ๋™๊ธฐํ™”๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค. ํ•œ์–‘๋Œ€ ํ•€ํ† ์Šค PPT ์ž๋ฃŒ์—๋Š” semaphore๋ฅผ ํ†ตํ•ด ๋™๊ธฐํ™”๋ฅผ ๊ตฌํ˜„ํ•˜๋ผ๊ณ  ๋˜์–ด ์žˆ์–ด์„œ ์ด๋ ‡๊ฒŒ ํ–ˆ๋Š”๋ฐ, ์กฐ๊ฑด๋ณ€์ˆ˜๋กœ๋„ ๊ฐ€๋Šฅํ•  ๊ฒƒ ๊ฐ™๋‹ค. ๋‹ค๋งŒ, ์‹ ํ˜ธ๊ฐ€ ์†์‹ค๋œ๋‹ค๋˜์ง€, thread๊ฐ€ ์กฐ๊ฑด์„ ๊ฒ€์‚ฌํ•˜๊ณ  ์กฐ๊ฑด ๋ณ€์ˆ˜์—์„œ ๋Œ€๊ธฐํ•˜๋ ค๊ณ  ํ•  ๋•Œ ๋‹ค๋ฅธ thread๊ฐ€ ์‹คํ–‰๋œ๋‹ค๋“ ์ง€ ํ•˜๋Š” race condition ์ƒํ™ฉ์„ ์ ์ ˆํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•ด์ค˜์•ผ ํ•˜๊ธฐ์— ๋‚œ์ด๋„๊ฐ€ ํ›จ์”ฌ ๋†’์„ ๊ฒƒ์ด๋‹ค.

int wait(int pid)
{
	return process_wait(pid);
}
int process_wait(tid_t child_tid UNUSED) {
    struct thread *cur = thread_current();
    struct thread *child = get_child_process(child_tid);
    if (child == NULL)
        return -1;
    sema_down(&child->wait_sema);
    int exit_status = child->exit_status;
    list_remove(&child->child_elem);
    sema_up(&child->free_sema);
    return exit_status;
}

Exit

์ด ์‹œ์Šคํ…œ ์ฝœ์€ ํ˜„์žฌ ํ”„๋กœ์„ธ์Šค์˜ exit status๋ฅผ ํ˜„์žฌ thread์˜ exit_stauts์— ํ• ๋‹น ํ›„ exit๋œ process์˜ ํ• ๋‹น๋˜์–ด ์žˆ๋˜ ์ž์›์„ ๋ชจ๋‘ ํ•ด์ œํ•ด์ค€๋‹ค. thread_exit() ํ•จ์ˆ˜๊ฐ€ ๊ตฌํ˜„๋˜์–ด ์žˆ๊ธฐ์— ์‰ฝ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

void exit(int status) {
    struct thread *curr = thread_current();
    curr->exit_status = status;
    printf("%s: exit(%d)\n", curr->name, status);  // process termination message
    thread_exit();
}