exit() 와 exec()

신준우·2023년 6월 4일
0

시스템 프로그래밍

목록 보기
8/12

복습

  • 우린 좀 더 발전된 두번째 쉘을 만들어냈었다!

exit(), _exit()

  • 위 두 함수, 이전의 내용들을 배우면서 조금씩 보긴 했을것이다
    ex) exit(1)이라던지... exit(17)이라던지...
  • 프로세스는 exit()를 통해 종료될 수 있다
  • exit이라는 system call은 어떻게 작동하는지 확인해보자
    1. 모든 스트림을 비운다
    버퍼링된 모든 출력을 비운다고 생각하자
    2. atexit()및 on_exit()로 등록된 함수를 호출
    3. 현재 시스템에 대한 exit()와 관련된 다른 함수를 실행
    4. 그후, exit()을 호출
  • _exit()의 커녈 동작
    1. 종료 프로세스에 할당된 모든 메모리를 해제한다
    2. 종료 프로세스가 열었던 모든 파일을 닫는다
    3. 다른 프로세스에 의해 필요한 커널을 위한 모든 데이터 구조 해제

atexit() vs on_exit()

  • 위에 등록된 함수라고 얘기한 두 함수이다
  • 비교를 통해서 좀 더 알아보자

함수의 원형은 다음과 같다

atexit()on_exit()
int atexitint on_exit
(void(*function)(void));(void(*function)(int, void*) void *arg);

상세설명

POSIX에 의해 정의된다SunOS4에 의해 정의됨
어떠한 매개변수도 없다이벤트 넘버와 들어가야하는 매개변수, 즉 인자가 필요하다

프로세스의 종료

exit을 통해 자식프로세스에서 전달된 인수는 어떻게 처리 될까?

  • 자식 프로세스에서 exit()을 통해 전달된 인수는 해당 값이 부모 프로세스에 의해 wait을 통해 검색될 때 까지 커널에 저장된다
  • parent가 현재 wait하고 있지 않다면, exit value는 커널에 남아있으며, 부모 프로세스가 자식 프로세스의 종료를 알리기 위해 wait을 호출할때까지 유지한다
  • 그 후, parent는 종료값을 받는다

결국 exit함수의 반환값은, 프로세스가 다 종료된 후에 인자를 받게 된다는 뜻이다

좀비 프로세스

  • 좀비 프로세스란 무엇일까?
  • 말 그대로다! exit에 의해 종료는 선언되었지만, exit의 반환값이 전달이 안된 경우의 프로세스를 의미한다!
  • child 프로세스에서 주로 일어나는 현상이다
  • wait에 의해 exit값이 전달되면 좀비 프로세스는 사라진다
  • 에러 혹은 자원 누수로 인해 발생하는 경우가 대다수이다

자, 이제 프로세스가 종료될때의 과정들을 어느정도 알아 보았다!

한번 _exit()을 뜯고 맛봐보자

_exit()

PURPOSE현재 프로세스를 종료시킨다
INCLUDE#include <unistd.h>, #include <stdlib.h>
USAGEvoid_exit(int status)
ARGSstatus return value
RETURNSnothing
SEE ALSOatexit(3), exit(3), on_exit(3)
  • 좀 더 상세한 절차를 알아보자!
    - 현재 프로세스를 종료시킨다
  • 전반적인 clean-up operations 즉 링요한 종료과정들을 거친다
    1. 모든 파일 탐색기와 모든 디렉토리 탐색기를 전부 닫는다
    2. parent 프로세스는 children이 존재하기 전에 존재하면, children은 정상적으로 실행된다, orphan이 되지 않게 말이다!
    • 자식 프로세스들이 계속 실행될 수 있도록, 부모 프로세스의 모든 자식들은 부모 pid를, 부팅시 가장 처음 실행되는 init프로세스의 pid로 초기화한다.
    • 이러면 자식 프로세스들은 init프로세스의 자식 프로세스가 되어 계속 실행된다
    • 여기서 얘기하는 init프로세스란 무엇일까?
      운영체제 부팅 과정에서 가장 먼저 실행되는 프로세스이다!

      이게 무엇을 의미하느냐, 부모 프로세스가 종료되면 자식 프로세스들은 고아 프로세스(Orphan process)가 된다.

      근데, 만약 부모프로세스를 가장 먼저 실행되는 프로세스인 init프로세스로 설정을 하게 된다면, orphan이 될 일이 없기에, 안정성과 지속성을 보장받을 수 있다!

  1. 만약 부모 프로세스가 wait 또는 waitpid를 실행하고 있다면, 그것(부모 프로세스)에게 알린다

  2. SIGCHLD를 parent에게 보낸다

    • 그러나 SIGCHLD의 기본 동작은 무시된다

    여기서 SIGCHILD란, POSIX시그널의 하나로, 자식프로세스의 종료 또는 중지를 부모 프로세스에게 알리는 시그널이다! 기본적으로는 무시되게 작업되어있다. 부모 프로세스가 자식 프로세스의 상태 변화를 실시간으로 감지

exec family

exec 패밀리는 유닉스와 유닉스 기반 운영 체제에서 제공되는 함수들의 그룹이다. exec은 "execute"의 줄임말로, 새로운 프로세스를 실행하는 데 사용된다.

exec 패밀리에는 다음과 같은 함수들이 포함되어 있다:

  1. execve(): 새로운 프로그램을 실행하고 새로운 프로세스 이미지를 로드합니다. 실행 파일의 경로와 인자들을 지정할 수 있습니다.
  1. execv(): execve()와 유사하지만, 실행 파일의 경로를 상대 경로로 지정할 수 있습니다.
  1. execvp(): execve()와 유사하지만, 실행 파일의 경로를 환경 변수 PATH에서 검색하여 찾아낼 수 있습니다.
  1. execl(): 인자들을 인자 목록으로 지정하여 실행 파일을 실행합니다.
  1. execlp(): execl()과 유사하지만, 실행 파일의 경로를 환경 변수 PATH에서 검색하여 찾아낼 수 있습니다.

exec 함수들은 현재 실행 중인 프로세스의 이미지를 새로운 프로그램으로 교체하며, 새로운 프로그램은 현재 프로세스의 컨텍스트를 상속받는다. 따라서 exec 함수를 사용하여 다른 프로그램을 실행하면 현재 프로세스가 종료되고 대상 프로그램이 실행된다. exec 함수는 프로세스 간의 프로그램 교체 및 새로운 환경에서의 실행을 가능하게 한다.

총정리!

자, 지금까지 우리는 '쉘'이라는것이 어떻게 작동하는지 배웠다

그 중, 프로그램을 프로세스에서 실행시키는 방법에 대해 배웠다

전반적으로 정리를 해보자!

  • 쉘은 fork, exec, wait함수를 통해 프로그램을 동작시킨다
  • 리눅스는 프로그램을 프로세스로 로드하여 코드를 실행시킨다
    - 여기서 프로세스란 프로그램을 실행시키기 위한 메모리 공간이다
  • 각 실행중인 프로그램들은 프로세스를 가진다
    - 프로세스는 각각의 PID를 가지고 있으며, 개별적인 오너, 사이즈, 그리고 다른 구성요소들을 가진다
  • fork는 현재 프로세스를 복사하여 새로운 (또는 child)프로세스를 만들어낸다
  • 프로그램은 exec family라는 프로세스를 통해 프로그램이 로드되고 실행된다
  • 프로그램은 wait함수를 통해 child프로세스가 종료될때까지 기다릴 수 있다
  • caller는 새로운 프로그램의 main함수에 문자열을 전달 할 수 있으며, 이 프로그램은 exit를 통해 char값을 반환하게 된다
profile
보안

0개의 댓글