CPU가 프로그램을 실행하고 있는데 I/O 등의 장치에 의해 혹은 예외상황이 발생해 처리가 필요한 경우에 이를 알려주는 것이 인터럽트(Interrupt)다. 인터럽트는 크게 하드웨어 인터럽트와 소프트웨어 인터럽트로 나뉜다.
하드웨어 인터럽트는 CPU가 아닌 다른 하드웨어 장치가 CPU에 어떤 정보를 주거나 서비스를 요청해야하는 경우 발생시키는 인터럽트이다. 소프트웨어 인터럽트는 소프트웨어가 발생시키는 인터럽트를 가리킨다. 보통 응용프로그램을 일컫는다. 종류로는 시스템 콜(system call)과 예외 상황(exception)이 있다. 예외 상황의 예시로는 어떤 값을 0으로 나누는 것을 생각해보면 된다. 본문에서는 소프트웨어 인터럽트의 종류에 시스템 콜과 예외 상황이 있다고 이야기했지만, 책이나 사람에 따라서는 소프트웨어 인터럽트를 시스템 콜이라고 말하는 경우도 있다. 이는 문맥에 따라 파악해야 할 것이다.
이제 인터럽트 처리 과정에 대해 알아보자.
1. 어떤 기기에 의해 인터럽트 시그널을 프로세서에게 보낸다.
2. 프로세서는 인터럽트를 받기 전에 실행중인 명령을 중단시킨다.
3. 인터럽트를 검사하고 받은 인터럽트에 대해 승인 신호를 기기에 보낸다.
4. 프로세서는 인터럽트 루틴을 실행하기 전에 커널 모드에서 프로세스의 context를 커널 스택에 push한다.
5. 인터럽트 서비스 루틴을 실행한다.
6. 커널 스택에 저장해뒀던 context를 pop한다.
7. 유저 모드로 전환한다.
8. 다음 명령으로 수행한다.
2에서 인터럽트를 받기 전에 프로세서가 어떻게 인터럽트의 우선순위를 확인하고 중단시키는 지 의문이 있었다. 확인하는 것 자체가 큰 오버헤드가 될 수 있기 때문이다. 이때는 소프트웨어와 하드웨어로 구현하는 두가지 방법이 있다, 소프트웨어로 구현한다면 인터럽트가 발생할 때마다 우선 순위를 판단하는 커널 코드가 실행돼야한다. 이 커널 코드는 인터럽트가 발생할 때마다 우선 순위를 판단해야 할 것이다. 그래서 오버헤드가 될 수 있다. 그런데 이를 하드웨어로 구현하는 경우에는 오버헤드를 많이 줄일 수 있다. 이는 본문의 내용을 벗어나므로 링크로 대신하겠다.
(친구들과 이야기해보고 찾아보니 인터럽트는 무조건 비동기적으로 걸린다고 한다. 인터럽트의 우선 순위가 요구되는 경우는 인터럽트가 마스킹을 하지 않아 인터럽트 2개가 겹치는 경우다. 보통 인터럽트 핸들링을 할 때 인터럽트가 중복 호출이 되지 않도록 마스킹(블로킹)을 한다. 이를 도와주는 API로는 sigprocmask가 있다. 이에 대한 구체적인 설명은 링크로 대신하겠다.)
위의 처리 과정에서 이전에는 설명하지 않은 '유저 모드'와 '커널 모드'라는 용어가 나왔다. 운영체제의 여러 역할 중에 하나는 보안이다. 이를 위해 운영 체제는 기본적으로 '유저 모드'와 '커널 모드'를 지원한다. 이 둘의 차이는 특권 명령(Privileged Instruction)를 수행할 수 있는지로 나뉜다. CPU가 수행할 수 있는 명령에는 '일반 명령'과 '특권 명령'으로 나뉘는데 이는 입출력 장치, 하드웨어 자원에 직접적인 접근이 가능하냐 아니냐로 나뉜다. 즉, 유저 모드는 입출력 장치, 하드웨어 자원에 직접적인 접근이 불가능하고, 커널 모드는 입출력 장치, 하드웨어 자원에 직접적인 접근이 가능하다. 이때 유저 모드와 커널 모드는 모드 비트(mode bit)로 결정된다. 고전적인 운영체제에서는 모드를 두가지로 나누지만 현대에는 필요성에 따라 더 나누는 경우도 있다.
유저 모드에서는 입출력 장치, 하드웨어 자원에 직접적인 접근이 불가능하다고 하였다. 하지만 유저 모드에서 응용 프로그램을 실행하고 프로세스를 실행 시에 이를 돌리기 위한 메모리를 할당받아야 한다. 그러면 어떻게 할당 받을 수 있을까? 정답은 시스템 콜이다.
소프트웨어 인터럽트 중 하나인 시스템 콜은 운영체제의 커널이 제공하는 서비스를 응용 프로그램(사용자)이 접근하기 위한 인터페이스다. 즉, 커널 영역의 기능을 유저 모드가 사용 가능하게끔, 프로세스가 하드웨어에 직접 접근해서 필요한 기능을 사용할 수 있게 해준다. 시스템 콜의 처리 과정은 다음과 같다.
1. 시스템 콜을 호출한다.
2. IDT에서 0x80(syscall)을 호출한다.
3. 커널 모드에서 현재 프로세스의 context를 커널 스택에 push한다.
4. 시스템 콜 테이블에서 호출한 syscall에 해당하는 서비스 루틴을 수행한다.
5. 커널 스택에 저장해두었던 context를 pop한다.
6. 유저 모드로 전환한다.
7. 다음 명령을 수행한다.
이번 포스팅에서는 인터럽트와 그 종류 중 하나인 시스템 콜에 대해 알아보았다.
'컴퓨터 > 운영체제' 카테고리의 다른 글
[OS] Thread (1) (0) | 2020.04.16 |
---|---|
[OS] Inter Process Communication (IPC) (1) | 2020.04.15 |
[OS] Context Switch와 레지스터 셋의 관계 (0) | 2020.04.15 |
[OS] Operating System Structures (part2) (0) | 2020.03.25 |
[OS] Operating System Structures (part1) (0) | 2020.03.23 |