Skip to content

8. Exceptional Control Flow


프로세서의 컨트롤 플로 (Control Flow)는 PC의 값이 끊임없이 증가하며 해당 주소의 명령어를 읽는 과정을 의미. 모든 프로그램의 PC가 계속 1씩 증가하는 것은 아니잖아. 대표적으로 분기, 반복과 같은 jump가 있겠다. 이 경우 PC는 서로 인접하지 않은 두 주소 사이를 넘나드는 것이 가능하다.

하지만 분기나 반복의 경우, 프로그램 내부의 상태에 따라서만 PC를 옮기는 것이라는 점. ECF(Exceptional Control Flow)는 시스템의 상태변화에 따라서 PC를 옮기는 작업을 일컫는다. 대표적으로

  • 패킷이 들어와 메모리 어딘가에 저장해야 하는 경우
  • 디스크에 있는 파일을 불러오는 중이라서 메모리에 다 올릴때까지 대기할 수 없는 경우
  • 하드웨어 타이머가 일정 인터벌을 넘겨버린 경우
  • 자식 프로세스가 종료되기까지 기다려야 하는 경우

ECF는 여러종류가 있다. 하드웨어 단에서 발생한 이벤트를 처리하는 예외처리기 (exception handlers), OS 단에서 한 프로세스에서 다른 프로세스로 문맥전환(Context Switching), 유저 프로세스가 다른 프로세스에게 보내는 시그널이 있다. 이런 개별적인 프로그램들은 일반적인 실행흐름으로부터 벗어나 side stepping을 할 수도 있고, 또는 nonlocal jump 수행할 수도 있다.

ECF를 배워야 하는 이유는 다음과 같다.

  • 중요한 시스템 컨셉 (IO, 프로세스, 가상메모리)를 이해하는데 사실상 필수로 알아야 하기 때문.
  • 커널 코드에게 요청을 보내는 데 ECF를 사용하기 때문. (trap and syscall)
  • 흥미로운 프로그램을 만드는 데 필요하기 때문. 셸을 만들어 셸 안에서 여러 다른 프로그램들을 실행시키고 그 결과를 받아봐야 하는 경우, 나만의 웹 서버를 만들고 싶은 경우
  • concurrency 개념을 익히는 데에 아주 중요하기 때문.
  • C++나 JAVA에서 제공하는 Software Exceptions를 이해하는 데 도움을 주기 때문. SW exception은 OS exception과 어떤 차이가 있는지, 유저 코드 안에서 nonlocal jump를 하기 위해 어떤 메커니즘이 들어가는지 알게된다.

예외는 하드웨어와 OS, 프로세스 간의 교차점을 알게 해준다. 시스템 콜로 하여금 OS와 유저 프로세스가 어떻게 상호작용 하는지에 대해 알아보고, 프로세스와 프로세스 간에 어떻게 상호작용 하는지에 대해 알아본다.

DUMP#

  • ⭐️ 8.1 Exceptions
  • 8.2. Processes
    • Process는 혼자서 시스템 전체를 점유하고 있다는 착각을 하게 만든다. 그 아래에는 논리흐름에 따라 멀티태스킹(혹은 time slicing)을 사용한다.
    • 유저모드와 커널모드: 커널모드비트가 켜져있으면 물리메모리를 참조할 수 있게 되는 등 권한이 강화된다. 하지만 유저 프로세스는 커널모드로 강제로 전환할 수 없기 때문에 오직 syscall 인터페이스만을 통해 시스템 자원에 간접적으로 접근할 수 있다.
    • Context Switches: 프로세스 상태(code, data, stack, registers, pc, env, fd)를 Context라고 부른다. 컨텍스트 정보가 있으면 얼마든지 중단시켰던 프로세스를 다시 preempt(선점)할 수 있다. 스케줄러는 이렇게 선점할 프로세스를 결정하게 되고, 다음 단계에 의해서 컨텍스트를 변환하게 된다.
      1. 기존 프로세스의 컨텍스트를 저장한다.
      2. 선점할 프로세스의 컨텍스트를 불러온다.
      3. 실행흐름을 다시 옮긴다.
      4. context switch의 결과로 직전에 실행중이던 실행흐름이
        1. 재개될 수도 있고
        2. ready list에 들어갈 수도 있고
        3. 종료될 수도 있다.
    • trap에 의해 syscall이 호출될 수도 있지만 interrupt에 의해서도 context switch될 수도 있다.
      • trap: 커널에게 read 요청을 보내면 디스크가 완료 시그널을 보낼때까지 현 프로세스를 sleep시키고 context switch
      • interrupt: IO device(timer, disk controller)가 보내는 신호에 따라 context switch
        • 시스템 콜은 내부 인터럽트, 소프트웨어 인터럽트에 해당.
  • 8.3. System Call Error Handling
    • strerror(errno) 전역변수 errno를 해석해주는 함수 strerror를 잘 활용하자.
  • 8.4. Process Control
    • getpid 나의 pid, getppid 부모 프로세스의 pid
    • 프로세스의 상태는 세가지이다. {Running, Stopped, Terminated}
    • fork를 통해 부모와 거의 동일한 컨텍스트를 가진 자식 프로세스를 생성할 수 있다. 자식 프로세스가 새로운 프로그램을 실행하도록 만들고 싶다면 execve를 사용하면 된다.
    • 자식 프로세스가 terminated 되더라도 부모 프로세스가 명시적으로 wait 하지 않은 채로 terminated 되면 자식 프로세스는 좀비 프로세스가 된다.
    • sleep은 유명하지. 몇초동안 프로세스를 중단한다.
  • ⭐️ 8.5. Signals
  • 8.6. Nonlocal Jumps
    • setjmp, longjmp를 통한 예외적인 실행흐름을 유저 프로세스 단에서 만들어낼 수 있다.
    • setjmp는 이 함수를 호출하는 프로세스의 환경을 env 버퍼에 담아 저장하는 역할을 한다. switch문을 활용해 longjmp 호출 시 넣었던 인자 retval을 구분할 수 있다.
    • longjmpenv 버퍼로부터 다시 setjmp를 호출했던 시점으로 돌아간다. 대표적으로 깊게 호출된 재귀함수 안에서 특정한 상황에서 빠르게 기존 위치로 돌아와야 할 때 사용할 수 있다.
  • 8.7. Tools for Manipulating Processes
  • 8.8. Summary

MISC#

8.2.3. Private Address Space 에서 참조한 Process address space 도식표
Pasted image 20230908204804.png