https://github.com/parkjbdev/SCE213_OS/tree/os-pa1

Logic

mash.c

flowchart LR
  initialize --> while --> get_command --command--> parse_command -- nr_tokens, tokens --> run_command --> free_command_tokens --> if_terminate
  if_terminate{{run_command != 0}} --true--> while
  if_terminate --false--> finalize

mash.c์—์„œ๋Š” command๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์ „์— command๋ฅผ ์ž…๋ ฅ๋ฐ›๊ณ , ์ด๋ฅผ parser.c์— ์ •์˜๋œ parse_command ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๊ณต๋ฐฑ์„ ๊ธฐ์ค€์œผ๋กœ command๋ฅผ ํ† ํฐํ™”ํ•˜์—ฌ run_command์— ์ „๋‹ฌํ•˜์—ฌ command๋ฅผ ์‹คํ–‰ํ•œ ๋’ค, ๋ฉ”๋ชจ๋ฆฌ์—์„œ token๋“ค์„ ํ•ด์ œํ•˜๋Š” ๊ณผ์ •์„ ๊ฑฐ์นœ๋‹ค. ์œ„ flowchart์— ๊ทธ ๊ณผ์ •๊ณผ ์ธ์ž๋“ค์˜ ์ „๋‹ฌ์„ ๋ชจ์‹ํ™”ํ•ด๋‘์—ˆ๋‹ค.

pa1.c

flowchart TD
START --> strcmp{{"tokens[0]"}}
strcmp --exit--> exit[return 0]
strcmp --cd--> cd[builtin_cd]
strcmp --alias--> alias[builtin_alias]
strcmp --else--> replace_alias --> execute

pa1.c ์—์„œ๋Š” ์šฐ์„  ์ฒซ๋ฒˆ์งธ ์ž…๋ ฅ๋œ ํ† ํฐ tokens[0]๊ฐ€ builtin function์ธ์ง€ ํŒ๋‹จํ•˜์—ฌ, builtin function์ผ ๊ฒฝ์šฐ nr_tokens์— ๋”ฐ๋ผ ์˜ฌ๋ฐ”๋ฅธ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์˜€๋‹ค. builtin function์ด ์•„๋‹ ๊ฒฝ์šฐ, ์ฆ‰, ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•ด์•ผ ๋  ๊ฒฝ์šฐ์—๋Š” ์šฐ์„  alias๋กœ ๋“ฑ๋ก๋œ token์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์—ฌ ์ด๋ฅผ ๋Œ€์ฒดํ•˜๋Š” ๊ณผ์ •์„ ๊ฑฐ์นœ ํ›„ executeํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์‹คํ–‰ํ•˜๊ฒŒ ๋œ๋‹ค. ์œ„๋Š” ๊ฐ„๋‹จํ•œ flowchart์ด๋‹ค. ๊ฐ๊ฐ์˜ ํ•จ์ˆ˜์˜ ๋™์ž‘๊ณผ์ •์— ๋Œ€ํ•ด์„œ๋Š” ์•„๋ž˜์— ๊ธฐ์ˆ ํ•˜์˜€๋‹ค.

Features

Builtin Command - cd

cd ๊ธฐ๋Šฅ์€ ํ˜„์žฌ์˜ working directory๋ฅผ ๋ฐ”๊พธ๋Š” ๋ช…๋ น์–ด๋กœ, builtin_cd ํ•จ์ˆ˜๋กœ ์‹คํ–‰๋˜๋Š”๋ฐ, ์ธ์ž๋กœ ๋ณ€๊ฒฝํ•  ๋””๋ ‰ํ† ๋ฆฌ์˜ ์ฃผ์†Œ dir์ด ์ž…๋ ฅ๋˜๋ฉด, ์ด์— ๋งž๋Š” ๊ณณ์œผ๋กœ ์ด๋™ํ•œ๋‹ค.

์ „๋‹ฌ๋œ ์ธ์ž๊ฐ€ ~์ผ ๊ฒฝ์šฐ getenv ๋ฅผ ์ด์šฉํ•˜์—ฌ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๋ชฉ๋ก์ค‘์—์„œ $HOME ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ์ฐพ์•„ home directory ๋กœ ์ด๋™ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์˜€๋‹ค. ๋˜, cd๋งŒ ์ž…๋ ฅ๋˜์—ˆ์„ ๋•Œ ์—ญ์‹œ home directory๋กœ ์ด๋™ํ•ด์•ผ ํ•˜๋Š”๋ฐ, ์ด๋Š” run_command ํ•จ์ˆ˜์—์„œ ์ „๋‹ฌ๋œ ์ธ์ž๊ฐ€ 1๊ฐœ์ผ ๋•Œ์—๋Š” builtin_cd("~")๊ฐ€ ์‹คํ–‰๋˜๋„๋ก ํ•˜์—ฌ ์˜๋„ํ•œ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์˜€๋‹ค.

cd ๋ช…๋ น์–ด๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์‹คํ–‰๋˜์—ˆ์„ ๋•Œ์— builtin_cd ํ•จ์ˆ˜๋Š” 1์„ ๋ฐ˜ํ™˜ํ•˜๊ณ , ๊ทธ๋ ‡์ง€ ์•Š์„ ๊ฒฝ์šฐ perror๋ฅผ ํ†ตํ•œ ์—๋Ÿฌ๋ฉ”์„ธ์ง€์™€ ํ•จ๊ป˜ -1์„ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ํ•˜์˜€๋‹ค.

์ถ”๊ฐ€๊ตฌํ˜„ - ์ด์ „ directory ์ด๋™: -

์ถ”๊ฐ€์ ์œผ๋กœ ์ „๋‹ฌ๋œ ์ธ์ž๊ฐ€ -์ผ ๊ฒฝ์šฐ ์ด์ „ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ €์žฅํ•ด๋‘๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜์˜€๋‹ค. ์ด๋ฅผ ์œ„ํ•ด ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ด๋™ํ•  ๋•Œ๋งˆ๋‹ค, ํ™˜๊ฒฝ๋ณ€์ˆ˜์— ๋“ฑ๋ก๋œ $PWD๊ฐ’๊ณผ $OLDPWD๊ฐ’์„ setenv๋ฅผ ํ†ตํ•ด ๋‹ค์‹œ ์„ค์ •ํ•˜์—ฌ ์ฃผ์—ˆ๋‹ค.

Lessons Learned

cd ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๋ฉฐ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ์ฝ๊ณ  ์“ฐ๋Š” getenv, setenv ํ•จ์ˆ˜, current working directory๋ฅผ ์ฝ๊ณ  ๋ณ€๊ฒฝํ•˜๋Š” getcwd, chdir ํ•จ์ˆ˜๋ฅผ ์•Œ๊ฒŒ๋˜์—ˆ๋‹ค.

Builtin Command - alias

alias ๊ธฐ๋Šฅ์€ ๊ธฐ์กด์— run_command๋กœ ์ž…๋ ฅ๋œ tokens ์ค‘์— alias๋กœ ๋“ฑ๋ก๋˜์–ด ์žˆ๋Š” token๋“ค์„ ๋งค์น˜๋˜๋Š” token๋“ค๋กœ ๋Œ€์ฒดํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜์˜€๋‹ค.

์ด๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด์„œ ํ•˜๋‚˜์˜ alias์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๋‹ด๋Š” ๊ตฌ์กฐ์ฒด Alias ๋ฅผ ์ •์˜ํ•˜์˜€์œผ๋ฉฐ, ํ•ด๋‹น ๊ตฌ์กฐ์ฒด์˜ member๋กœ, ๋Œ€์ฒด๋  ๋ฌธ์ž์—ด alias, ํ•ด๋‹น alias์— ๋Œ€ํ•ด ๋Œ€์ฒด์‹œ์ผœ์•ผ ํ•  ํ† ํฐ๋“ค์˜ ๋ฐฐ์—ด tokens, tokens ๋ฐฐ์—ด์˜ ๊ธธ์ด๋ฅผ ์ €์žฅํ•˜๋Š” nr_tokens๋ฅผ ์ •์˜ํ•˜์˜€๋‹ค. ์ƒˆ๋กœ์šด alias๋ฅผ ๋™์ ํ• ๋‹นํ•˜๊ฑฐ๋‚˜ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œํ•  ๋•Œ, ํŽธ์˜๋ฅผ ์œ„ํ•ด new_alias, delete_alias ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜์—ฌ ์ด์šฉํ•˜์˜€๋‹ค. ๋˜, ์—ฌ๋Ÿฌ alias ์ •๋ณด๋“ค์„ ์ €์žฅํ•˜๋Š” Alias์˜ ๋ฐฐ์—ด Alias **aliases ๊ณผ ์ด alias๋“ค์˜ ๊ฐœ์ˆ˜ alias_cnt๋ฅผ ์ •์˜ํ•˜์˜€๋‹ค. ์ด๋ฅผ ๊ฐ„๋‹จํ•œ ๋‹ค์ด์–ด๊ทธ๋žจ์œผ๋กœ ๋‚˜ํƒ€๋‚ด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

classDiagram
  class Alias {
    char* alias
    int nr_tokens
    char **tokens
    new_alias()
    delete_alias()
    print_alias()
  }

  class Aliases {
    int alias_cnt
    Alias **aliases
    builtin_alias_add()
    builtin_alias_print()
  }

์ƒˆ๋กœ์šด alias ์ถ”๊ฐ€๊ณผ์ • - builtin_alias_add

์ƒˆ๋กœ์šด alias๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ์ผ๋ จ์˜ ๊ณผ์ •์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

flowchart LR
  builtin_alias_add --> found
  found{find_alias}
  found -- not found --> increase_alias_cnt[alias_cnt++] --> realloc_aliases[realloc aliases] --> add_alias[add new alias]
  found -- found --> replace_alias[replace tokens and nr_tokens]

์ฆ‰, alias๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ ์ „์—, find_alias ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด aliases ๋ฐฐ์—ด์— ๊ธฐ์กด์— ๋“ฑ๋ก๋œ ๊ฐ™์€ ์ด๋ฆ„์˜ alias๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธํ•œ ํ›„, ๊ฐ™์€ alias๊ฐ€ ์กด์žฌํ•  ๊ฒฝ์šฐ ์ด๋ฅผ ์ƒˆ๋กœ์šด tokens์™€ nr_tokens๋กœ ๋Œ€์ฒดํ•˜๊ณ , ๊ธฐ์กด์— ๊ฐ™์€ alias๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ ์ƒˆ๋กœ์šด alias๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด aliases ๋ฐฐ์—ด์„ alias_cnt+1 ๋งŒํผ ์žฌํ• ๋‹นํ•ด์ฃผ์–ด ์ƒˆ๋กœ์šด alias๋ฅผ ๋“ฑ๋กํ•ด์ฃผ๋Š” ๊ณผ์ •์„ ๊ฑฐ์นœ๋‹ค.

alias ์ถœ๋ ฅ - builtin_alias_print

builtin_alias_print ํ•จ์ˆ˜๋Š” ์ดˆ๊ธฐ์—๋Š” ๋ชจ๋“  alias๋“ค์„ ์ถœ๋ ฅํ•˜๋Š” ํ•จ์ˆ˜๋กœ ๋งŒ๋“ค์—ˆ์œผ๋‚˜, ๊ฐœ๋ณ„ alias์— ๋Œ€ํ•ด์„œ ์ถœ๋ ฅํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ฐœ์„ ํ•˜์˜€๋‹ค. ์ด๋ฅผ ์œ„ํ•ด run_command์—์„œ alias๋งŒ ์ž…๋ ฅ๋˜์–ด token์ด 1๊ฐœ ์ž…๋ ฅ๋œ ๊ฒฝ์šฐ, alias์™€ ํ•จ๊นจ token์ด 2๊ฐœ ์ž…๋ ฅ๋œ ๊ฒฝ์šฐ, ์ฆ‰ alias ll๊ณผ ๊ฐ™์€ ๊ฒฝ์šฐ๋ฅผ ๋‚˜๋ˆ„์–ด builtin_alias_add์— ์ธ์ž๋กœ ์ „๋‹ฌํ•˜์˜€๋‹ค. ํ•ด๋‹น ํ•จ์ˆ˜์— NULL๊ฐ’์ด ๋“ค์–ด์˜ฌ ๊ฒฝ์šฐ, ๋ชจ๋“  alias๋“ค์„ ์ถœ๋ ฅํ•˜๋„๋ก ํ•˜์˜€๊ณ , ๋ฌธ์ž์—ด์ด ๋“ค์–ด์˜ฌ ๊ฒฝ์šฐ ํ•ด๋‹นํ•˜๋Š” alias๋ฅผ find_alias๋ฅผ ํ†ตํ•ด ์ฐพ์•„์„œ ์ถœ๋ ฅํ•˜๋„๋ก ํ•˜์˜€๋‹ค.

alias replacement

builtin commands๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ, execute์„ ํ†ตํ•˜์—ฌ command๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์ „์—, tokens๋ฅผ ์ˆœํšŒํ•˜๋ฉฐ alias๋กœ ๋Œ€์ฒดํ•  token์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ณผ์ •์„ ๊ฑฐ์นœ๋‹ค. alias๋กœ ๋Œ€์ฒดํ•  token์ด ์กด์žฌํ•œ๋‹ค๋ฉด, ์ด๋ฅผ ๋Œ€์ฒดํ•˜๊ธฐ ์œ„ํ•ด์„œ tokens[] ๋ฐฐ์—ด์˜ ๋’ท๋ถ€๋ถ„์„ alias์˜ token ๊ฐœ์ˆ˜๋งŒํผ ๋ฏธ๋ฃจ๋Š” ์ž‘์—…์„ ์ง„ํ–‰ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  alias๊ฐ€ ์žˆ๋˜ index๋ถ€ํ„ฐ ๋ฏธ๋ค„์ง„ ๋งŒํผ์˜ index์— alias token๋“ค์„ ๋„ฃ๋Š”๊ณผ์ •์„ ์ง„ํ–‰ํ•œ๋‹ค.

์ตœ์ข…์ ์œผ๋กœ, aliasing ๋œ token๋“ค์˜ aliasing์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด for loop์„ ์ˆœํšŒํ•˜๋Š” iterator i๋ฅผ ๋ฐ€์–ด๋‚ธ ์ธ๋ฑ์Šค๋งŒํผ ์ฆ๊ฐ€์‹œ์ผœ ์ฃผ์—ˆ๋‹ค. (ex. alias hello hi hello; echo hello world ์˜ ์‹คํ–‰๊ฒฐ๊ณผ๋Š” hi hello world ์—ฌ์•ผ ํ•จ, re-aliasing์„ ํ•  ๊ฒฝ์šฐ ๋ฌดํ•œํžˆ ๊ธด ๋ฌธ์ž์—ด์ด ์ƒ์„ฑ๋จ)

๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ

์ตœ์ข…์ ์œผ๋กœ ์‰˜์„ terminateํ•˜๊ธฐ ์ „์— ๋™์ ํ• ๋‹นํ•œ aliases์˜ ๊ฐœ๋ณ„ element์™€ aliases์„ finalize ํ•จ์ˆ˜์—์„œ ํ•ด์ œํ•ด์ฃผ์—ˆ๋‹ค.

Lessons Learned

alias ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๋ฉฐ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋™์ ์œผ๋กœ ํ• ๋‹นํ•˜๊ณ  ํ•ด์ œํ•˜๋Š” ๊ณผ์ •์„ ํ†ตํ•ด ํฌ์ธํ„ฐ์™€ ์ด๋ฅผ ํ™œ์šฉํ•œ ๋™์ ๊ธธ์ด๋ฅผ ๊ฐ€์ง„ ๋ฐฐ์—ด์— ๋Œ€ํ•œ ์ดํ•ด๋„๋ฅผ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์—ˆ๋‹ค. ํŠนํžˆ, ๋ฌธ์ž์—ด์„ ๋ณต์‚ฌํ•  ๋•Œ, ๊ธฐ์กด์—๋Š” malloc์„ ํ†ตํ•ด ๋ฌธ์ž์—ด์„ ์ €์žฅํ•˜๋Š” ๊ณต๊ฐ„์„ ๋™์ ์œผ๋กœ ๋งŒ๋“ค๊ณ , ์—ฌ๊ธฐ์— strcpy๋ฅผ ํ†ตํ•ด ๋ณต์‚ฌํ•˜๊ณ ๋Š” ํ•˜์˜€๋Š”๋ฐ, ์ด๋ฅผ ํ•œ๋ฒˆ์— ํ•ด์ฃผ๋Š” strdup์ด๋ผ๋Š” ์œ ์šฉํ•œ ํ•จ์ˆ˜๋ฅผ ์•Œ๊ฒŒ๋˜์—ˆ๋‹ค.

Execution & Pipe Implementation - execute

์ƒˆ๋กœ์šด ํ”„๋กœ์„ธ์Šค์˜ ์‹คํ–‰๊ณผ pipelining ๋ถ€๋ถ„์˜ logic์—์„œ ๊ฒน์น˜๋Š” ๋ถ€๋ถ„์ด ๋ฐœ์ƒํ•˜์—ฌ ๊ฐ™์€ section์œผ๋กœ ํฌํ•จํ•œ๋‹ค.

์šฐ์„  execute์„ ์‹คํ–‰ํ•˜๊ธฐ ์ „์—, tokens์™€ nr_tokens๋ฅผ ์ž…๋ ฅ๋ฐ›์•„ ์ด๋ฅผ ํŒŒ์ดํ”„๋ผ์ธ ๊ธฐํ˜ธ | ๋‹จ์œ„๋กœ ๋‚˜๋ˆ„์–ด command ๋‹จ์œ„๋กœ ํ† ํฐ๋“ค์„ ๋ถ„๋ฆฌ์‹œ์ผฐ๋‹ค. ํ•ด๋‹น ๊ณผ์ •์€ parse_commands์—์„œ ์ˆ˜ํ–‰๋œ๋‹ค. ๋ช…๋ น์–ด ๋‹จ์œ„๋กœ ๋ถ„๋ฆฌ๋œ ํ† ํฐ๋“ค์„ ์ €์žฅํ•˜๋Š” ๊ตฌ์กฐ์ฒด Command ๋ฅผ ์ •์˜ํ•˜์˜€์œผ๋ฉฐ, ์—ฌ๋Ÿฌ ๋ช…๋ น์–ด๋“ค์— ๋Œ€ํ•œ list ์™€ ๋ช…๋ น์–ด์˜ ๊ฐฏ์ˆ˜ nr_commands ๊ฐ€ ์ •์˜๋œ ๊ตฌ์กฐ์ฒด Commands ๋ฅผ ์ •์˜ํ•˜์˜€๋‹ค. parse_commands ์˜ ๊ฒฐ๊ณผ๋กœ commands๋ฅผ ๋ฐ›์•„, commands->list[i]->tokens ๋‹จ์œ„๋ณ„๋กœ exec_command ์—์„œ execvp ๋ฅผ ํ†ตํ•ด ์‹คํ–‰ํ•˜๊ฒŒ ๋œ๋‹ค.

Execution

Pipelining์ด ์—†๋Š” execution์˜ ๊ฒฝ์šฐ ์ด์ „์— pipeline์„ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์€ ์ƒํƒœ์ธ 50783ff4 ์ปค๋ฐ‹์˜ 170๋ผ์ธ ๋˜๋Š”, ์ตœ์ข… ์ปค๋ฐ‹์˜ execution ํ•จ์ˆ˜์˜ ๋งˆ์ง€๋ง‰ fork์ดํ›„ ๊ณผ์ •์—์„œ ์ด์ค‘์œผ๋กœ ๊ฐ์‹ธ์ง„ if ๋ฌธ์„ ์ œ์™ธํ•˜๊ณ  ์ฝ”๋“œ๋ฅผ ์ฐธ์กฐํ•˜๋ฉด ๋œ๋‹ค. ์ฆ‰, ํ”„๋กœ๊ทธ๋žจ์ด ์‹คํ–‰๋˜๋Š” ์ „์ฒด์ ์ธ ๊ณผ์ •์€ fork๋ฅผ ์ง„ํ–‰ํ•˜์—ฌ ํ”„๋กœ์„ธ์Šค๋ฅผ ๋ณต์‚ฌํ•œ ๋’ค, child process์—์„œ๋Š” execvpํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํ”„๋กœ์„ธ์Šค๋ฅผ ์‹คํ–‰์‹œํ‚ค๊ณ , exitํ•˜๋Š” ๊ณผ์ •์„ ๊ฑฐ์น˜๊ณ , parent process์—์„œ๋Š” child process๊ฐ€ exit๋˜๋Š” ๊ฒƒ์„ wait ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๋Œ€๊ธฐํ•œ๋‹ค. ๊ทธ ๊ณผ์ •์„ flowchart๋กœ ํ‘œํ˜„ํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

flowchart LR
  START -->
  last_fork{{pid=fork}}
  last_fork --pid<0--> fork_error[fork_failed]
  last_fork --pid==0--> child[Child]
  child --> execute --> exit
  last_fork --pid>0--> par[Parent] --> wait
  wait-.-exit
  wait --> RETURN

PipeLining

flowchart TD
START -->
parse_commands --> pipe --> is_last_command{{no pipeline?}} --false-->for_commands
is_last_command--true-->last_command

for_fork_par_close_write --> last_command --> last_fork{{pid=fork}}
last_fork --pid<0--> fork_error[fork_failed]
last_fork --pid==0--> child[Child]
child --> were_pipelines{{pipeline exists?}}
were_pipelines --false-->execute-->exit
were_pipelines --true-->child_dup_read
child_dup_read["dup2 pipe_fd[0] as STDIN"] --> close_read[close read end of pipe] --> execute
last_fork --pid>0--> par[Parent] --> wait
wait-.-exit
wait --> RETURN


subgraph for commands except last one
  direction TB
  for_commands[for commands except last one]-->for_fork{{pid=fork}}
  for_fork --pid<0 --> for_fork_error[fork failed]
  for_fork --pid==0--> for_fork_child[Child] --> is_first_command
  for_fork --pid>0--> for_fork_par[Parent] --> for_fork_par_wait[wait] --> for_fork_par_close_write[close write end of pipe] --> for_commands
  for_exit -.- for_fork_par_wait

  subgraph child_process
    direction TB
    is_first_command{{is it first command?}} --true--> for_child_dup_read["dup2 pipe_fd[0] as STDIN"]
    -->for_child_dup_write
    is_first_command --false-->for_child_dup_write["dup2 pipe_fd[1] as STDOUT"]-->close_child_read[close read end of the pipe]-->for_execute[execute] --> for_exit[exit]
    end
  end

TestCase์—๋Š” ํŒŒ์ดํ”„๋ผ์ด๋‹์ด ํ•˜๋‚˜์ธ ์ผ€์ด์Šค๋งŒ ์กด์žฌํ•˜๋Š”๊ฒƒ ๊ฐ™์•˜์œผ๋‚˜, Multi Pipeline์„ ์ง€์›ํ•˜๊ธฐ ์œ„ํ•ด command ๋‹จ์œ„๋ณ„๋กœ for loop์„ ์ˆœํšŒํ•˜๋ฉฐ ํ”„๋กœ์„ธ์Šค๋ฅผ ์‹คํ–‰์‹œ์ผฐ๋‹ค. ๊ทธ ๊ณผ์ •์„ flowchart๋กœ ๊ทธ๋ ค๋ณด์•˜์œผ๋‚˜, ๊ณผ์ •์— ๋น„ํ•ด ๋” ๋ณต์žกํ•˜๊ฒŒ ๋ณด์ด๋ฏ€๋กœ, ์ฒจ๋ถ€ํ•˜์ง€๋Š” ์•Š์•˜๋‹ค. (gitlab REPORT.md ์ฐธ์กฐ)

์ „์ฒด์ ์ธ ํ๋ฆ„์€ ์•ž์—์„œ ์–ธ๊ธ‰ํ•œ Execution ๊ณผ์ •๊ณผ ๋™์ผํ•˜๋‚˜, pipe ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด pipe๋ฅผ ์ƒ์„ฑํ•˜๊ณ  dup2๋ฅผ ํ†ตํ•ด pipe์˜ read end๋ฅผ stdin์œผ๋กœ ํ˜น์€ pipe์˜ write end๋ฅผ stdout์œผ๋กœ ์ง€์ •ํ•˜๋Š” ๊ณผ์ •, pipe๋ฅผ ์—ฌ๋‹ซ๋Š” ๊ณผ์ • ๋“ฑ์ด ์ถ”๊ฐ€๋œ๋‹ค. ์ผ๋ฐ˜์ ์ธ ๋Œ€๋ถ€๋ถ„์˜ ํ”„๋กœ์„ธ์Šค๋“ค์€ ์ž…๋ ฅ๊ณผ ์ถœ๋ ฅ์„ stdin์—์„œ ๋ฐ›๊ฑฐ๋‚˜ stdout์œผ๋กœ ์ถœ๋ ฅํ•˜๊ธฐ ๋•Œ๋ฌธ์—, pipe๋ฅผ ์ด์šฉํ•˜์—ฌ ์ž…๋ ฅ๊ณผ ์ถœ๋ ฅ์„ ๋‹ค๋ฅธ ํ”„๋กœ์„ธ์Šค์— ์ „๋‹ฌํ•˜๋Š” ๋ฐ์— dup2 ํ•จ์ˆ˜๊ฐ€ ์‚ฌ์šฉ๋œ๋‹ค.

์ž์‹ ํ”„๋กœ์„ธ์Šค์—์„œ๋Š” ๋จผ์ €, pipe๋ฅผ ์ƒ์„ฑํ•œ ๋’ค, |์„ ํ†ตํ•ด ๊ตฌ๋ถ„๋œ ๋ช…๋ น์–ด ๋‹จ์œ„๋กœ ํ”„๋กœ์„ธ์Šค๋ฅผ ์‹คํ–‰ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ , child process์—์„œ, dup2 ๋ฅผ ์ด์šฉํ•˜์—ฌ stdin์œผ๋กœ ๋“ค์–ด์™”์„ ์ž…๋ ฅ ๋Œ€์‹  pipe์˜ read_end์ธ pipe_fd[0]์—์„œ ์ž…๋ ฅ์„ ๋ฐ›์•„์˜ค๊ณ , stdout์— ์ถœ๋ ฅ๋  ์ถœ๋ ฅ์„ pipe์˜ write_end์ธ pipe_fd[1]์— ์ž…๋ ฅ๋˜๋„๋ก ํ•œ๋‹ค. ๋‹จ, ์ฒซ๋ฒˆ์งธ๋กœ ์‹คํ–‰ํ•˜๋Š” ํ”„๋กœ์„ธ์Šค์ผ ๊ฒฝ์šฐ์—๋Š” stdin์—์„œ ๋ฐ›์•„์˜ฌ ์ž…๋ ฅ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— stdin ๋Œ€์‹  pipe_fd[0]์—์„œ ์ž…๋ ฅ์„ ๋ฐ›์•„์˜ค๋Š” ๋™์ž‘์€ ์ƒ๋žตํ•œ๋‹ค. ์ž…๋ ฅ์„ ๋ฐ›์•„์˜จ ๋’ค์—๋Š” ์ถœ๋ ฅ์„ pipe์˜ write_end์— ์ž‘์„ฑํ•˜๊ธฐ ์œ„ํ•ด์„œ read_end๋ฅผ ๋‹ซ์•„์ค€๋‹ค.

๋ถ€๋ชจ ํ”„๋กœ์„ธ์Šค์—์„œ๋Š” ์ž์‹ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์‹คํ–‰๋œ ๋’ค, pipe์˜ write_end์ธ pipe_fd[1]์„ ๋‹ซ์•„์ฃผ์–ด pipe์— EOF์ž„์„ ์ „๋‹ฌํ•˜๋„๋ก ํ•˜์˜€๋‹ค.

์ฆ‰, ์ „์ฒด์ ์œผ๋กœ ๋ณด์•˜์„ ๋•Œ, ํŒŒ์ดํ”„๋ผ์ธ์„ ํ†ตํ•˜์—ฌ n๊ฐœ์˜ command๊ฐ€ ์ž…๋ ฅ๋˜์—ˆ์„ ๋•Œ, ๊ฐ command๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด n๋ฒˆ์˜ fork๊ฐ€ ์ผ์–ด๋‚œ๋‹ค.

์˜ˆ์‹œ๋กœ, ls -al | wc -l | cat ์™€ ๊ฐ™์€ ๋ช…๋ น์–ด๋ฅผ ์ž…๋ ฅํ•˜์˜€์„ ๋•Œ, command ๋ณ„๋กœ ์ด๋ฅผ [["ls", "-al"], ["wc", "-l"], ["cat"]] ์™€ ๊ฐ™์ด parsing ํ•ด๋‚ด๊ณ , ์ˆœ์ฐจ์ ์œผ๋กœ ls -al ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด fork ํ›„ execvp ํ•œ ๊ฒฐ๊ณผ๋ฅผ pipe_fd[1]์— ๋„ฃ๊ณ , pipe_fd[0]์—์„œ wc -l์ด ์ด๋ฅผ ์ฝ์–ด์™€ fork ํ›„ execvp ํ•˜์—ฌ ์‹คํ–‰ํ•œ ๊ฒฐ๊ณผํ•œ pipe_fd[1]์— ๋„ฃ๊ณ , pipe_fd[0]์—์„œ cat์ด ์ด๋ฅผ ์ฝ์–ด์™€ fork ํ›„ execvp ํ•œ ๊ฒฐ๊ณผ๋ฅผ ์ตœ์ข…์ ์œผ๋กœ stdout์œผ๋กœ ์ถœ๋ ฅํ•œ๋‹ค. ์ฆ‰ ์ด์™€ ๊ฐ™์€ ๊ฒฝ์šฐ์—์„œ๋Š” 3๋ฒˆ์˜ fork๋ฅผ ํ†ตํ•ด ํ”„๋กœ์„ธ์Šค๊ฐ€ ์‹คํ–‰๋˜์—ˆ๋‹ค.

์ด์™€ ๊ฐ™์€ ๊ณผ์ •์„ ๊ฑฐ์ณ ์ด์ „ ํ”„๋กœ์„ธ์Šค์˜ ์ถœ๋ ฅ์ด ํŒŒ์ดํ”„์— ์ž‘์„ฑ๋˜๊ณ , ์ด๋ฅผ ๋‹ค์Œ ํ”„๋กœ์„ธ์Šค๊ฐ€ ํŒŒ์ดํ”„์—์„œ ์ฝ์–ด์™€ pipelining์ด ๊ตฌํ˜„๋  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์˜€๋‹ค.

Lessons Learned

ํ”„๋กœ์„ธ์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ณผ์ •์— ๋Œ€ํ•ด์„œ ์•Œ๊ฒŒ ๋˜์—ˆ๋‹ค. ๋‹จ์ˆœํžˆ exec๋ฅผ ํ†ตํ•ด ํ”„๋กœ์„ธ์Šค๋ฅผ ๋ฐ”๋กœ ์‹คํ–‰ํ•˜๊ฒŒ ๋  ๊ฒฝ์šฐ์—๋Š”, ์ƒˆ๋กœ์šด ํ”„๋กœ์„ธ์Šค๋กœ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ, ํ˜„์žฌ ์‚ฌ์šฉ์ค‘์ธ ํ”„๋กœ์„ธ์Šค์—์„œ ์ƒˆ๋กœ์šด ํ”„๋กœ์„ธ์Šค๊ฐ€ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์—, ์ด์ „์˜ ์ƒํƒœ๋ฅผ ์ €์žฅํ•œ ์ƒํƒœ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค. ์ด๋ฅผ ์œ„ํ•ด fork๋ผ๋Š” ๊ณผ์ •์„ ๊ฑฐ์ณ ํ˜„์žฌ ํ”„๋กœ์„ธ์Šค๋ฅผ ๊ทธ๋Œ€๋กœ ๋ณต์ œํ•œ ์ž์‹ ํ”„๋กœ์„ธ์Šค๋ฅผ ์ƒ์„ฑํ•œ ๋’ค, ์ž์‹ ํ”„๋กœ์„ธ์Šค์—์„œ exec๋ฅผ ํ†ตํ•ด ์‹คํ–‰ํ•˜๊ฒŒ ๋œ๋‹ค. ์ž์‹ ํ”„๋กœ์„ธ์Šค๊ฐ€ exitํ•˜๋ฉด, wait์„ ํ†ตํ•ด ๋ถ€๋ชจํ”„๋กœ์„ธ์Šค๋Š” ์ž์‹ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋๋‚ฌ์Œ์„ ํ™•์ธํ•˜๊ณ  ๊ทธ๋Œ€๋กœ ๋™์ž‘์„ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํŒŒ์ดํ”„๋ผ์ธ์œผ๋กœ ์—ฐ๊ฒฐ๋œ inter process communication ๊ธฐ๋ฒ•์— ๋Œ€ํ•ด์„œ๋„ ์ง์ ‘ ํŒŒ์ดํ”„ ์‚ฌ์šฉํ•ด๋ณด๋ฉฐ ์•Œ ์ˆ˜ ์žˆ์—ˆ๋‹ค. pipe file descriptor์˜ 0๋ฒˆ์งธ index๋Š” pipe์˜ read end๋กœ pipe์—์„œ ์ฝ์–ด์˜ค๋Š” ์—ญํ• ์„, 1๋ฒˆ์งธ index๋Š” pipe์˜ write end๋กœ pipe์— ์ž…๋ ฅํ•˜๋Š” ์—ญํ• ์„ ํ•œ๋‹ค. ํŒŒ์ดํ”„๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ, dup2๋ฅผ ์ด์šฉํ•˜์—ฌ stdin์˜ ์ž…๋ ฅ์„ pipe์˜ read end์—์„œ ์ž…๋ ฅ๋ฐ›๊ณ , stdout์˜ ์ถœ๋ ฅ์„ pipe์˜ write end์— ์ž‘์„ฑํ•จ์œผ๋กœ์จ pipe๋ฅผ ํ†ตํ•˜์—ฌ ํ”„๋กœ์„ธ์Šค๊ฐ„ ํ†ต์‹ ์„ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ๋””๋ฒ„๊น… ์ค‘์— ๊ฐ€๋” ํ”„๋กœ๊ทธ๋žจ์ด ๊ฐ€๋งŒํžˆ ๋ฉˆ์ถฐ์žˆ๋Š” ๊ฒฝ์šฐ๊ฐ€ ์กด์žฌํ•˜์˜€๋Š”๋ฐ, ์ด๋Š” ํŒŒ์ดํ”„๋ฅผ ์ •์ƒ์ ์œผ๋กœ ๋‹ซ์•„์ฃผ์ง€ ์•Š์•„ EOF๋ฅผ ๋Œ€๊ธฐํ•˜๋˜ ์ƒํ™ฉ์ด์˜€์Œ์„ ์•Œ ์ˆ˜ ์žˆ์—ˆ๋‹ค.