[운영체제(Operating System)] 1-1 syscall(시스템콜)

·6일 전
0

OS 운영체제

목록 보기
1/1
  • 시스템 콜 syscall : fork(), wait(), exec(), …

    유저 프로그램이 운영체제(커널) 기능을 요청할 때 사용하는 인터페이스
    운영체제의 모든 핵심 기능을 쓰는 공식적인 입구
    프로세스 생성도, 메모리 할당도, 입출력도
    다 시스템 콜 없으면 불가능

    • 프로세스 제어
      • fork(), exec(), exit(), wait() → 프로세스 생성, 실행, 종료, 대기 등
    • 파일 시스템 접근
      • open(), read(), write(), close() → 파일 열고 읽고 쓰고 닫기
    • 디바이스 접근 (입출력)
      • ioctl(), read(), write() → 키보드, 마우스, 디스크 등
    • 메모리 제어
      • mmap(), brk(), sbrk() → 힙 메모리 확장, 가상 주소 공간 매핑
    • 통신
      • pipe(), socket(), send(), recv()
        → 프로세스 간 메시지 주고받기

    Trap → 시스템 콜 발생 시 유저모드에서 커널 모드로 들어가는 점프 명령
    단순 함수 호출이 아닌, CPU 상태 자체가 바뀜

    시스템 콜 호출 흐름

    1. 유저 프로그램이 시스템 콜 함수 호출 (시스템 콜이 유저 모드 → 커널 모드로 trap 발생시킨다)

    2. CPU가 trap 명령 실행 → 커널 모드로 진입

    3. 운영체제가 작업 수행

    4. 작업 완료되면 → return-from-trap으로 유저 모드 복귀

      시스템 콜이 있을 때 context switch가 발생할 수 있다(특히 wait())

      유저 프로그램이 시스템 콜을 호출하면, 그 안의

      trap 명령어가 실행돼서

      CPU가 커널 모드로 진입

      → 커널은 그 요청을 처리하고

      return-from-trap 으로 다시 유저 모드로 복귀한다.

fork()

시스템 콜 중 1

유저 모드에서 호출되면( 즉 프로그램 코드를 실행해서 프로세스가 만들어졌고 실행 중에 fork()함수를 만나 호출)

내부적으로는 trap 명령(점프 명령)으로 cpu가 커널 모드로 들어가고

커널 모드 내에서 fork()작업 수행 = 똑같은 자식 프로세스 복제하여 생성함.
(자식 프로세스 전용 pcb 생성, 부모 주소 공간을 복사해서 자식에게 할당, 파일 디스크립터 테이블 복사함)
자식 프로세스를 ready 상태로 등록하고

스케줄러가 누구 먼저 실행할지 고르고
return form trap으로 복귀

  • 헷갈렸던 점: int rc = fork();를 자식 프로세스가 다시 실행하니까 조건문 가기 전에 무한히 프로세스 생성되지는 않는지? ← 아님. 해당 라인은 실행 안되는 것임

fork()는 실행한 시점의 코드만 복사해서 새 프로세스를 만드는 거지, 그 프로그램 처음부터 다시 실행시키는 게 아냐.
그러니까 자식2는 자식1이 rc = fork()를 호출한 결과로 태어난 애고,
그 시점에 코드상 위치는 if문 안쪽의 fork 줄 다음 줄이야.
→ 이미 조건문을 지나간 시점에서 태어났기 때문에
다시 그 조건을 만나지도 않고, 다시 fork()도 호출 안 해.

wait()

자식 프로세스가 종료될 때까지 부모가 기다리도록 만드는 시스템 콜

부모가 wait() 시스템 콜을 호출해

trap 발생

→ 커널 진입

  • 자식 프로세스(예: PID 29267)가 아직 종료되지 않았다면
    → 부모 프로세스(예: PID 29266)는 Blocked 상태가 됨

→ 스케줄러는 자식을 선택해서 실행시킴

- 자식이 `exit()` 호출해서 종료되면
→ 커널은 부모를 `Ready` 상태로 깨움
    
    → 다시 부모가 스케줄링되어 `Running`이 됨
    
    (커널이 자식을 Running으로 선택해서 실행 전환(context switch))
    
    → `wait()` 콜은 자식의 종료 상태를 받고 종료됨
    

fork() wait() 관계 - 프로세서 실행 순서 보장 - 스케줄러의 비결정성, 좀비 프로세스 방지

만일 fork()만 사용되었다 하면 자식프로세스가 생성 되는데,
이때, 항상 자식 프로세스가 종료된 후→ 부모 프로세스 마치기가 보장되지 않음.
비결정성. 랜덤으로 됨

순서는 cpu 스케줄러가 결정하는 것임. (그때의 상황에 따라)

따라서 부모 프로세스에서 fork() 실행 기점으로 자식 프로세스 먼저 다 끝내고 부모로 돌아오고 싶다.
-> wait()를 실행시켜야함

또한 fork() 만 호출 했을 경우, 자식이 먼저하든 부모가 먼저 실행되든, 자식 프로세스는 종료 후에 Exit()호출해서 커널 진입 후 자원 정리를 해야하는데 자식의 Pcb는 완전히 제거되지 않음. 부모가 wait()을 호출해서 자식의 종료상태를 수거해야만 함. 수거 안됐다? 그러면 이 상태는 좀비 프로세스가 됨.

자식 프로세스 생성 전 후로 wait()을 사용하면 그제야 PCB를 제거함.
wait()에게 자식의 종료 상태를 넘겨주기 전에는 terminated상태 pid도 그대로 있음 자원 낭비 중

fork()로 자식 생성 후 wait() 또는 waitpid()를 호출하지 않으면 자식이 종료될 때 좀비 프로세스가 발생한다.
부모가 종료되면 자식은 init(또는 systemd)에 의해 입양되며, 이 경우 좀비가 자동으로 정리된다.

exec()

현재 프로세스의 address space를 지우고 새로운 실행 파일의 내용으로 완전히 덮어씌움

즉, 프로세스는 그대로인데(PID도) 그 안의 내용이 싹 바뀜

fork()는 나랑 똑같은 거 만들기 (address space 똑같이 복사됨) → 두 프로세스 생김
exec() 나를 다른 애로 바꾸기 (완전 새로 로드됨) → 한 개로 이어지되 이전 것은 소멸

0개의 댓글