인터럽트와 시스템 콜
운영체제는 interrupt driven이고, 운영체제에서 사용하는 interrupt를 system call이라고 한다. 따라서 운영체제의 동작 방식을 이해하기 위해선 interrupt와 system call에 대해 필히 이해하고 있어야 한다. 이 글에서는 인터럽트에 대해 먼저 알아보고, system call에 대해 기술하도록 하겠다.
인터럽트 (Interrupt)
🔷인터럽트란?
CPU가 프로그램을 실행하고 있을 때, 입출력 하드웨어 등의 장치나 예외상황이 발생하여 처리가 필요할 경우에 마이크로프로세서에게 알려 처리할 수 있도록 하는 것을 말한다.
🔷 인터럽트를 왜 쓰는지..
밑에 출처에 남긴 블로그에서 운영체제가 인터럽트를 사용하는 이유에 대한 엄청난 비유를 찾았다.
CPU를 고급 인력, 운영체제를 고급 인력의 뽕을 뽑으려는 악덕 사장님으로 비유한다.
결론부터 말하면 인터럽트를 사용하는 이유는 CPU의 명령 수행 속도보다 입출력의 속도가 훨씬 느리기 때문이다.
고급 인력인 CPU가 일을 하지 않고 계속해서 입출력을 하는 시간을 소비하게 된다면 운영체제는 CPU를 어떻게 더 굴릴 수 있을 지 생각할 것이다.
이때 나온 것이 인터럽트로, CPU가 입출력 연산을 기다리는 동안 CPU에게 인터럽트를 걸어 다른 할 일을 하도록 하는 것이다.
🔷 인터럽트(Interrupt)의 종류
인터럽트는 크게 H/W적으로 발생했는 지, S/W적으로 발생했는 지에 따라 두 가지로 분류된다.
🔹H/W적으로 발생하는 인터럽트 - interrupt
인터럽트는 대부분 H/W(마우스, 키보드, 프린터, ...) 로부터 발생한다.
ex) 위 그림처럼 클락을 이용해서 시간에 맞게 CPU에게 인터럽트를 걸어준다.
🔹 S/W적으로 발생하는 인터럽트 - trap, exception
S/W적으로 발생한 인터럽트는 trap이나 exception이라고 부른다.
ex) 0으로 나눌 때
- b=0; c = a/b;
ex) 운영체제를 이용하기 위한 요청
- system call
🔷인터럽트의 동작 과정
1. 인터럽트를 당한 명령어의 주소를 저장 (다시 돌아왔을 때 여기부터 실행해야 하므로)
2. 다른 인터럽트가 들어오지 않도록 막음
3. ISR( Interrupt Service Routine) 또는 Interrupt handler를 실행
- IST의 시작주소를 Interrupt vector에서 찾아서 load 함으로써 실행
- ISR의 끝에 IRET 명령어에 의해 인터럽트가 해제
4. 1번에서 저장했던 복귀 주소가 다시 PC로 load 되어 인터럽트 당한 명령어를 재개한다.
밑은 학부생 때 필기했던 그림이라 알아보기 힘들지만 설명을 붙이자면...
Main Memory에 현재 실행되고 있는 Progam이 적재 되어있다.
program은 우리 눈에는 위에처럼 코드의 형태로 보이지만, 이것이 실행될 때는 Compile 되어 기계어의 형태로 실행이 된다.
main 함수에서 200번 주소에서부터 program이 실행이 되다가 210 주소의 명령어를 실행하게 되면, foo()라는 함수를 호출하기 위해 interrupt가 발생한다.
1. 인터럽트를 당한 명령어의 주소를 저장
따라서 이제 위에 적어놓은 과정 중 1번인, 복귀 주소인 211을 레지스터에 저장한다.
2. 다른 인터럽트가 들어오지 않도록 막음
3. ISR( Interrupt Service Routine) 또는 Interrupt handler를 실행
이제 다음 실행할 명령어로는 foo()의 시작 주소인 240이 PC에 load된다.
240~260까지 실행이 되면
4. 1번에서 저장했던 복귀 주소가 다시 PC로 load 되어 인터럽트 당한 명령어를 재개한다.
1번에서 저장해놓은 복귀 주소 211이 다시 PC에 load된다.
211부터 명령어가 다시 실행된다.
🔹3번 ISR 또는 Interrupt handler를 실행 에서 IST의 시작주소를 Interrupt vector에서 찾는 과정
🔷 CPU 명령어 - 유저 모드 명령어 + 커널 모드 명령어
운영체제는 듀얼 모드 명령어로 유저모드, 커널모드로 구분해서 OS가 자신을 보호한다.
관리자는 마스터 키를 가질 수 있고, 일반 사용자는 방 키만 가질 수 있는 것으로 비유할 수 있다.
🔹Mode bit
CPU에서 사용할 수 있는 명령어가 많은데, 그 중 OS만 실행 가능한 명령어들이 있다
이때, mode bit를 둬서 (0, 1) 구분한다
0 : 커널모드
1 : 유저모드
🔹🔹 Timer (Privileged instructions)
어떤 응용 프로그램이 영원히 끝나지 않는다면 CPU는 아무것도 할 수 없을 것이다. 이걸 위해 '클락'을 사용해서 OS가 CPU를 제어하도록 한다.
이때 당연히 마음대로 timer를 바꾸면 안되고, OS만이 할 수 있어야 한다.
이렇게 Mode bit를 통해 Privileged Instruction을 통해서 User Mode -> Kernel Mode로 가게 해주는 것이 System call이다.
System Call
프로그램이 실행되는 중에 디스크 입출력 명령을 읽은 경우를 예시를 들어보면, 이것은 os의 권한이므로 이 app은 맘대로 해당 명령을 실행할 수 없다.
따라서 os에게 system call을 통해 대신해서 이 privileged 명령어를 수행해달라고 요청한다. 그렇게 system call을 통해서 user mode -> kernal mode로 넘어가게 되고 디스크 입출력을 수행할 수 있게 된다.
System call은 커널 영역의 기능을 사용자 모드가 사용 가능할 수 있도록 os에게 요청하는 작업이다.
system call 이라는 인터럽트를 CPU가 감지하게 되면, 수행 중이었던 APP을 멈추고 cpu의 제어권은 운영체제에게 넘어가서 kernal mode로 넘어가게 된다.
이 때, 하드웨어적으로는 듀얼 모드에서 모드를 구분해주는 Mode bit가 1에서 0으로 바뀌면서 Privileged 명령어를 수행할 수 있게 되는 것이다.
🔹system call 의 구현
system call을 하는 APP은 system call이 어떻게 구현되었는 지 알 필요가 없고, 그저 system call만 호출하면 된다. 내부적으로 어떻게 실행/구현되는 지는 알 필요도 없고, 개발자에게 숨겨져 있다.
예를 들어 음성 인식기 package를 샀을 때, 그냥 사용하면 되지 내부에서 어떻게 동작하는 지 몰라도 되는 것과 비슷하다.
밑에는 file을 open하는 system call의 예시이다. APP은 매개변수가 무엇이고 형태가 무엇인지만 알아서 잘 호출할 수 있으면 된다.
int open(const char *pathname, int flags);
🔹C언어의 printf()의 System call 예시
사실 출력장치에 프린트하려면 printf()를 호출할게 아니라 write()이라는 system call을 호출해야 한다. 하지만 system call은 호출하기 까다롭다.
따라서 쓰기 좋도록 만들어놓은게 printf()이고, Standard C Library에 정의해둔 것이다.
직접 system call을 해도 되지만, 더 쓰기 편한 코드로 작성가능하다.
Standard C Library는 OS가 아니니까 User 모드에서 실행된다.
우리는 printf()를 부르고, printf()가 Library에서 찾아지고, 얘가 write()이라는 system call을 하는 것!
printf() -> Library에서 찾기 -> write()
🔷결론
system call이란 운영체제의 기능을 우리가 만드는 프로그램에서 이용할 수 있게끔 하는 인터페이스 (프로그램 인터페이스)
출처
https://velog.io/@adam2/%EC%9D%B8%ED%84%B0%EB%9F%BD%ED%8A%B8
'‡Computer Science ‡ > º 운영체제' 카테고리의 다른 글
[운영체제] 동기화(Process Synchronization) (0) | 2024.07.08 |
---|---|
[운영체제] 가상 메모리와 페이징 교체 알고리즘 (1) | 2024.07.05 |
[운영체제] PCB와 Context Switching (0) | 2024.06.27 |