여러가지 인터럽트 타입(키보드 인터럽트, …등)들이 들어오면,PIC는그걸 다 합쳐주는 역할을 한다.
인터럽트 신호들을 잘 조율하여 CPU에게 전달해준다. (PIC의 칩이 CPU의 핀 중 하나로써 구성됨)
◆interrupt가 왜 필요한가?
인터럽트를 사용하면 감시에 신경을 쓰지 않고 인터럽트 요청이 왔을 경우만 따로 수행해주면 되므로, 프로세스 수행 효율이 올라감! (인터럽트를 사용하지 않으면 CPU는 스스로 이벤트 발생여부를 일정시간마다 확인해야 함(Polling) → 프로세스 수행 효율이 떨어짐.)
◆ Dual-Mode : User mode, Kernel mode
운영체제는 사용자 프로그램이 마음대로 시스템에 접근하지 못하도록 모드(Mode)를 나눈다. 이 모드는 CPU를 점유하고 있는 주체가 누구냐에 따라 구분한다.
사용자 프로그램의 잘못된 수행으로 다른 프로그램이나 OS에 피해가 가면 안되므로 보호장치가 필요하기 때문이다.
모드는유저 모드(User Mode)와커널 모드(Kernel Mode)로 나뉘고, 이를 통해 운영체제 자신과 다른 시스템 요소들을 보호한다. (하드웨어에 의해 Mode bit가 제공된다.Mode bit가 1이면 유저 모드, 0이면 커널 모드)
유저 모드
사용자 프로그램이 CPU 점유
프로그램의 자원에 함부로 침범하지 못하는 모드
코드의 작성, 프로세스 실행 등의 간단한 행동을 할 수 있다.
커널 모드
OS가 CPU 점유
드라이버, 메모리, CPU 등 모든 자원에 접근, 명령할 수 있음
유저모드와는 다르게 컴퓨터 내부의 모든 행동이 가능
사용자는 일반적으로 유저 모드를 사용함.
만약 커널 모드에 접근하고 싶은 경우, 사용자 프로세스가 운영체제에게 소프트웨어 인터럽트인시스템 콜을 호출하여 커널의 기능을 사용할 수 있음
※ 시스템 콜 : 유저 모드에서 커널 모드의 기능을 호출하고자 할 때 사용하는 인터페이스 역할을 한다.
◆ System Call (시스템 콜)
사용자나 프로그램이 직접적으로 컴퓨터 자원에 접근하는 것을 막고 커널을 보호하기 위해 만든 인터페이스. 사용자는 시스템 콜을 통해 OS가 제공하는 operation들을 이용할 수 있다.
시스템 콜은 사용자나 프로그램이 직접적으로 컴퓨터 자원에 대한 접근하는 것을 막고 커널을 보호하기 위해 만든 인터페이스이다. 사용자가 OS의 operation들(예시: write(), read() 등)을 이용하고 싶으면, 직접 이용할 수는 없고 반드시 시스템 콜을 통해 커널 모드로 변경하여 실행한 후 결과값을 돌려받을 수 있다.
■ System Call 작동 과정
유저 프로세스가 실행하고 있다가 시스템 콜을 호출하게 되면,프로세스 제어 권한이 커널로 넘어감(유저 모드 →커널 모드로 변경됨).커널은 해당 시스템 콜에 맞는 함수를 찾아서 핸들링하고, 결과값을 유저에게 돌려줌.
시스템 콜에도 기능에 따른 다양한 시스템 콜 타입이 존재함. (Process control, File management, Device management 등)
각 시스템 콜에는 번호가 할당되고, 시스템 콜 인터페이스는시스템 콜 번호와 시스템 콜 핸들러 함수 주소로 구성되는 시스템 콜 테이블을 유지한다.
운영체제는 자신의 커널 영역에서 해당 인덱스가 가리키는 주소에 저장되어 있는 루틴을 수행한다.
작업이 완료되면 커널 모드에서 유저 모드로 다시 넘어온다.
※ 시스템 콜 작동 과정 : 시스템 콜 발생 → 시스템 콜 테이블에서 타입에 맞는 함수 찾아서 핸들링 → 결과값 전달
ex)
예를들어 유저 모드에서 “파일을 열어줘" 시스템 콜인 open()을 하면, 유저 모드 → 커널 모드로 변경됨.
이때 파일을 여는 건 커널 모드에서 하고, 유저 모드로 결과값을 전달함.
→ 따라서 호출자인 유저 모드에서는 시스템 콜의 내부 구현 방식을 알 수 없음. (Abstraction)
※ 보통 직접 시스템 콜을 호출하기보다는, 상위 API(Application Programming Interface)를 통해 커널의 기능을 사용한다.
ex)
라이브러리 콜인 printf()를 통해 시스템 콜 write()를 invoke함.
※ 참고) 시스템 콜 파라미터들은 어떻게 전달하냐?
- 레지스터: 가장 간단한 방법은 파라미터를 CPU 내부의 레지스터에 저장해놓고, 이를 OS가 읽어와서 사용할 수 있다.
단, 레지스터는 개수가 한정적이어서 파라미터를 많이 넣지는 못하므로, 파라미터가 너무 많은 경우 파라미터 길이 제한이 거의 없는 다음 방식들(Block, Stack)을 사용한다.
- Block: 파라미터를 메인 메모리의 블록이나 테이블에다 저장해놓고, 이 메모리 시작 주소를 줘서 OS가 파라미터를 읽어오도록 한다.
- Stack: 파라미터가 프로그램에 의해 stack에 Push되고, 필요할 때마다 OS가 Pop해서 사용하는 방식.
◆ OS 구조
OS 구조에도 여러 종류가 존재한다.
Simple Structure – MS-DOS
Monolithic Structure – UNIX -OS의 기능들이 하나의 커널로 엮어있는 구조. -user↔kernel은 system call interface를 통해 소통 -커널에서 소통이 쉬워서 성능이 좋으나, 일부가 잘못되면 다른 것들에게도 영향을 줌(서로 의존성이 높음 → 유지보수 힘듦)
Layered – an abstraction -시스템들의 레이어가 나누어져 있는 구조. 각 층의 독립성을 높였다. -레이어별로 따로 구성할 수 있으므로, 디자인 하기 쉬우며 디버깅하기도 쉬움. -그러나 레이어들을 거쳐서 접근해야 하기 때문에 비교적 성능이 떨어짐
Microkernel – Mach -정말 필수적으로 필요한 기능만 커널에 넣고, 나머지 많은 부분을 user space에서 수행하도록 함. -Monolithic의 단점을 보완하고자 한 것