System Call - Process

Hyungseop Lee·2023년 11월 20일
0

Process

  • Process : is an instance of a running program.
    (Not the same as "program" or "processor")

  • 여러 process들이 매우 빠르게 switching되어 수행되어지기 때문에 마치 혼자 CPU를 쓰고 있는 것처럼 보여짐

  • process가 switching되어 바뀔 때마다 process의 내용을 disk같은 곳에 저장하고,
    새로운 process의 내용을 읽어온다.
    이것을 해주는 것이 virtual memory system이라고 한다.


Context Switching

  • 프로세스A, B가 동시 수행되고 있다고 가정,
    CPU의 core가 1개만 있다고 가정.
    어떻게 여러 프로세스가 동시에 수행될 때
    혼자 CPU를 쓰는 것 같은 효과가 생길까?
    • process A가 수행되다가 process B로 switching이 일어난다. ➡️ context switching
      (kernel에 의해)
      추가로 kernel이 하는 일 :
      process A가 사용하고 있는 register값, 메모리 상태들을 저장한다. 그리고 process B의 프로세스 정보들을 복원한다.
      이러한 context switching으로 혼자 CPU를 쓰는 것 같은 효과가 생기고,
      process 정보를 memory에 저장, 복원하는 것에 의해서 memory를 혼자 쓰는 것 같은 효과가 생긴다.

Process States

ps

  • ps : 현재 실행중인 process 출력

  • ps -elf : 현재 실행중인 모든 process 출력
    init process의 PID는 항상 1

    • "ps -elf" process의 PPID = 2994
      PID=2994는 "bash"이다.
      ➡️ bash process가 "ps -elf" process를 fork()함.

top

  • top : process에 대한 자세한 정보(PID, 우선순위, CPU 점유율, memory 차지)
    • 전체 211개의 task들이 있는데,
      running state process는 1개.
      sleeping state process는 210개.
      ➡️ context switching을 통해 process들이 실행된다

man proc

  • proc : kernel data interface를 위한 가상의 file system

  • 2994/ -> bash process directory

    • fd/ : bash process가 열어놓은 file descriptor.
      0, 1, 2은 stdin, stdout, stderr이므로 항상 열어놓음
    • sched : scheduler

Process Composition


Process Table

  • Process Table :
    kernel은 어떤 프로세스가 현재 시스템에서 수행되고 있는지에 대한 정보가 필요. 그 정보를 갖고 있는 곳.

  • Each entry contains the following information about each process :

    • PID, PPID
    • UID, GID
    • state

Process Management

  • UNIX가 처음에 부팅될 때, 생기는 프로세스는 딱 하나이다. —> init process (PID = 1)

  • UNIX에서 프로세스를 만들 수 있는 유일한 방법은 기존의 프로세스를 복제하는 것.

  • 따라서 init process(parent process)를 복제해서 다른 process(child process, PPID = 1)를 생성.
    따라서 init process는 모든 process들의 조상 process가 된다

  • fork()라는 system call에 의해 process가 복제된다.
    parent process와 child process는 PID, PPID를 제외하고 모든 것이 똑같다. (code, data, stack이 모두 똑같음)

  • 우리는 fork()를 통해서 똑같은 process를 생성했는데,
    우리가 원하는 것은 만들어진 process가 어떠한 program을 수행하기 원한다.
    그래서 fork()로 생성된 child process의 code를
    우리가 원하는 code로 바꿔주는 system call이
    exec()계열의 system call들이다.

  • shell process가 실행중이므로 terminal의 console 입력부분에 커서가 깜빡깜빡..
    실행파일의 이름을 입력하면, shell process는 자기 자신을 fork()한다.
    fork()하여 만들어진 child process의 code 부분에
    exec() system call을 사용하여
    우리가 지정한 program의 code로 재할당.
    shell process는 wait() system call을 통해
    우리가 생성한 child process가 끝나기를 기다린다.
    child process가 종료되면,
    shell process가 wait하고 있다가
    깨어나서 종료된 process에 대해서 뒷처리를 해주고,
    그 다음 명령어를 입력할 수 있도록 shell prompt창에 다시 깜빡깜빡...


Process Management System Calls

  • getpid : Get a process's ID
  • getppid : Get a parent process's ID
  • fork : Duplicate a process
  • exec : Replaces the code, data, and stack of a process
  • exit : Terminate a process
  • wait : Waits for a child process

getpid(2), getppid(2)

fork(2)

fork(2) example

exec(3) family

  • execve(2) : system call
    • execl(3)
    • execv(3)
    • execle(3)
    • execlp(3)
    • execvp(3)

execve(2) example

exit(3), atexit(3)

exit(3), atexit(3) example

wait(2), waitpid(2)

wait(2), waitpid(2) status value

wait(2) example


Orphan process

  • parent와 child가 수행이 되고 있는데,
    parent가 child가 exit할 때까지 wait해야 하는데,
    wait하지 않고 먼저 종료되면,
    child process는 parent process가 없는 process가 된다.
    ➡️ 이러한 process를 Orphan process라고 한다.
    리눅스에서는 Orphan process의 PPID를 1로 세팅한다.
    Orphan process의 parent process는 init process가 된다.
    Orphan process가 exit하여 status를 return하면 init process에 전달이 된다.

Zombie process

  • parent와 child가 수행되고 있는데,
    child가 exit()했을 때, 코드를 없애고 메모리 자원도 해제했지만 완전히 종료된 것은 아니다.
    완전히 종료되기 위해서 parent process에서 wait()를 해줘야 한다.
    하지만 parent process에서 wait()를 하지 않고 다른 일을 하고 있으면,
    child process 입장에서는 exit()를 하긴 했는데 완벽하게 종료가 되지 않은 상태가 된다.
    ➡️ 이러한 process를 Zombie process라고 한다.

Example

fork(2)

  • fork()의 리턴값을 확인하여 자식과 부모 프로세스를 구분하도록 자신의 pid와 ppid를 출력하자

    parent process가 먼저 종료됨을 알 수 있다.
    == child process가 끝나기를 기다리지 않음
    ➡️ wait()로 해결

wait(2)

child process가 먼저 끝남.
parent process가 child process의 상태가 바뀌기를(끝나기를) 기다림
parent process는 child process의 status return 0을 받음.

zomebie process

  • parent process에서 wait()하기 직전에 무한 Loop를 돌려서
    child process에 대한 사후처리를 못하게 만들어서
    child process를 zombie process로 만들기
    <defunct> : child process가 zombie process가 된 것을 알 수 있다.

exit(2)

  • wait()를 해서 status code를 받으면, 원하는 101 값이 안나온다.
    왜냐하면 101은 상위 15~8 bit에 저장되어있기 때문이다.
  • 따라서 원하는 101이라는 status code를 받기 위해서는 다음의 방법1, 방법2가 있다.
    방법1 : 상위 8bit를 하위 8bit로 옮기기 위해 right shift 8번
    방법2 : WEXITSTATUS() macro를 사용하여 상위 8bit masking

race condition

  • race condition :
    해당 OS의 scheduler에 따라 동시에 실행하려는 두 process의 경쟁을 어떻게 처리하는지
    Mac OS의 가상환경에 설치한 Ubuntu에서는
    parent process 먼저 실행,
    child process 나중 실행.
    ➡️ scheduler 차이도 있지만, memory buffer도 이유가 될 수 있다(fflush).

fflush

  • fflush :
    printf()를 하면, memory buffer에 저장되었다가
    어느정도 모이면 한꺼번에 출력한다.
    하지만 fflush를 사용하여 곧바로 출력되게 하도록 할 수 있다.

execve(2)

  • 현재 process에서 execve()를 사용하여 ls -l 명령어를 실행하라

fork(2), execve(2)

  • child process를 fork를 통해 생성.
    child process가 execv()를 통해 ls -l 명령어를 실행하라

fork(2), execl(3)

  • fork(2), execl(3)을 사용하여
    system("ls -l | wc -l"); 처럼 ""안의 명령어들을 실행시켜주는
    mysystem("ls -l | wc -l")이라는 함수를 작성하라.
profile
Efficient Deep Learning Model

0개의 댓글