본문 바로가기
컴퓨터 공학/시스템 프로그래밍

예외적인 제어흐름 (1부)

by 조엘 2020. 8. 30.

안녕하세요 파피몬입니다! 오늘은 예외적인 제어흐름에 대해 공부해봤습니다!

Computer Systems A Programmer's Perspective (3rd Edition)의 내용을 공부한 것을 토대로한 포스팅입니다. 
오개념이 있다면 알려주세요! 
1부, 2부로 나눠져있습니다 :)

 

<개요>

프로세서에 전원을 처음 공급하고 전원을 끌 때까지, 프로세서는 프로그램의 인스트럭션을 수행하게 된다. 

 

하지만 현대 컴퓨터 시스템들은 프로그램의 실행과 반드시 관련이 있지 않은 시스템의 변화에도 반응할 수 있어야 한다! ex) HW타이머, 패킷의 네트워크 어댑터 도착, 디스크로부터 페이지 요청, 부모 프로세스가 자식 프로세스 기다리기 등등... 

 

이를 예외적인 제어 흐름(Exceptional Control Flow)이라고 부른다. 하나씩 살펴보도록 하자. 

 

<예외상황>

예외상황: 하드웨어와 운영체제에 의해서 구현된 ECF의 한 가지 형태로, 프로세서 상태의 변화(이벤트)에 대한 대응이다.

 

시스템 내에서 예외 상황별로 예외번호를 부여하게 된다. 운영 체제는 예외 테이블이라는 점프 테이블을 할당한다. 런타임시 이벤트의 발생이 감지되면, 그에 해당하는 예외번호 k를 결정하게 된다. 예외 테이블의 엔트리 k를 통해 간접 프로시저 콜을 하는 방식으로 예외상황을 발생시킨다!

 

예외 처리 핸들러가 처리를 끝마치면 세가지 중 한가지 일이 발생한다. 

 

1. 제어를 Icurr로 돌려준다

2. 제어를 Inext로 돌려준다

3. 프로그램을 종료시킨다. 

 

 

 

<예외의 종류>

1. Interrupt

  프로세서 외부에 있는 I/O device로 부터의 시그널을 받으면, 프로세서의 인터럽트 pin이 high로 설정되고, 이를 적절한 인터럽트 핸들러로 처리하게 된다!

 

2. Trap

  의도적 예외상황으로, 어떠한 인스트럭션을 실행한 결과로 발생하게 된다! 의도적 예외상황 중 가장 중요한 사용은 system call이며, 이는 유저 프로그램에서 커널에 접근하기 위해 사용된다. 

  +) 커널은 커널 서비스(파일 읽기, 새 프로세스 만들기, 새 프로그램 로드, 현재 프로세스 종료 등...)의 제한된 접근을 하기 위해 특별한 인스트럭션을 제공한다. 이를 수행하면 커널 서비스를 사용할 수 있게 된다. 

 

3. Fault

  정정할 수 있을 가능성이 있는 에러 조건으로 부터 발생한다. 해당 폴트가 정정 가능하다고 판단 시, 현재 instruction을 재실행하고, 정정 불가능하다고 판단 시 abort하게 된다. ex) Page Fault

 

4. Abort

  복구할 수 없는 치명적인 에러에서 발생한다. 핸들러는 제어를 응용 프로그램을 종료하는 중단 루틴으로 넘겨준다. 

 

<프로세스>

우리가 컴퓨터에서 프로그램을 실행하면, 아주 끊김없이 쾌적하게 동시에 여러 프로그램을 사용할 수 있다. 지금처럼 블로그에 포스팅 하면서, 음악을 틀면서, 유튜브 동영상까지 스트리밍 할 수 있는 방법은 무엇일까?

 

프로세스: 실행 프로그램의 인스턴스

시스템 내의 각 프로그램은 어떤 프로세스의 context에서 돌아가게 된다. (여기서 context란 프로그램이 정확하게 돌아가기 위해 필요한 상태 구성, ex)메모리에 저장된 코드/데이터, 스택, 레지스터 내용 등...) 

 

이 프로세스라는 개념을 통해 프로그램의 코드와 데이터가 시스템 메모리 상의 유일한 객체인 것 처럼 보이게 한다. 

 

<논리적인 제어흐름 & 문맥 전환>

 

사실 여러 프로세스를 실행시키게 되면, 동시에 많은 프로세스가 실행되는 것이 아니라, 짧게 잠깐씩 프로세스를 수행하고 넘어가면서 동시에 진행되는 것 처럼 착각(?)을 불러 일으키는 것이다. 

 

여기 해당하는 프로세스가 수행 중인 인스트럭션의 주소를 담은 PC 값들의 배열을 논리적인 제어흐름 이라고 부른다.

 

운영체제 커널은 문맥 전환(context switching)이라고 알려진 예외적인 제어흐름의 상위 수준 형태를 사용해 멀티태스킹을 구현하고 있다. 커널은 프로세스가 실행되는 동안 어떤 시점에 현재 프로세스를 일시 중지하고, 이전에 일시 중지되었던 프로세스를 다시 시작하는 것을 결정할 수 있다. (이를 스케줄링 이라고 한다)

 

2가지 문맥 전환의 예시를 소개하자면

  1. 커널이 유저를 대신하여 system call을 수행하고 있을 때 일어날 수 있다. ex) read로 디스크 접근

  2. 인터럽트의 발생 ex) 타이머 인터럽트

 

<유저 모드와 커널 모드>

프로세스에서는 모드 비트를 제공한다. 

모드 비트가 on이면, 커널 모드를 뜻한다. 커널 모드에서는 모든 프로세스의 instruction과 memory에 접근이 가능하다

모드 비트가 off이면, 유저 모드를 뜻한다. 유저 모드에서는 커널 모드에서 제공되는 특수 instruction을 수행할 수 없고, 커널 모드에 진입하기 위해서는 앞서 다룬 예외 발생을 통해 진입해야 한다. 

 

<프로세스를 제어하는 system call>

프로세스를 제어하기 위해 많은 system call이 제공된다. 대표적인 함수는 다음과 같다. 

 

pid_t getpid(void); //호출하는 함수의 PID 리턴

pid_t getppid(void); //자신의 부모 PID 리턴

pid_t fork(void); //코드, 데이터, 힙, 공유 라이브러리, 유저 스택, 파일 I/O를 복사하고 PID만 다른 자식 프로세스 생성

pid_t waitpid(pid_t pid, int *statusp, int options); //자신의 자식들이 동료되거나 정지되기 기다리기

unsigned int sleep(unsigned int secs); //secs초 만큼 프로세스 정지시킨다

int execve(const char *filename, const char *argv[], const char *envp[]); //현재 프로그램의 컨텍스트 내에서 새로운 프로그램을 로드하고 실행한다. 

 

2부에서 계속...

반응형

'컴퓨터 공학 > 시스템 프로그래밍' 카테고리의 다른 글

링커 (2부)  (0) 2020.08.29
링커 (1부)  (0) 2020.08.29
쉘(Shell)에 관하여  (0) 2020.05.10

댓글