인터럽트, 시스템 콜, 유저모드, 커널모드 들의 프로그래밍과의 관계

GoldenDusk·2023년 9월 3일
0

CS지식

목록 보기
11/26
post-thumbnail

1. User mode와 Kernel mode

영상 및 사진 출처 : 🔗 https://www.youtube.com/watch?v=v30ilCpITnY&list=PLcXyemr8ZeoQOtSUjwaer0VMJSMfa-9G-&index=10

🍌 user mode

  • 우리가 개발하는 프로그램은 일반적으로 유저모드에서 실행

🍌 user mode ⇒ Kernel mode

  • 프로그램 실행 중에 인터럽트(interrupt)가 발생하거나 시스템 콜(system call)을 호출하게 되면 커널 모드로 전환

🍌 Kernel mode

  1. 방금 전까지 실행 중이던 프로그램의 현재 CPU 상태를 저장
  • 나중에 마저 실행하기 위해
  1. 커널이 인터럽트나 시스템 콜을 직접 처리한다. 즉, CPU에서 커널 코드가 실행됨
  2. 처리가 완료되면 중단됐던 프로그램의 직전의 CPU 상태를 복원

🍌 Kernel mode ⇒ user mode

  • 다시 통제권을 프로그램에게 반환

🍌 user mode

  • 프로그램이 이어서 실행된다.

🍌 커널(kernel)

  • 운영체제의 핵심
  • 시스템의 전반을 관리/감독하는 역할
  • 하드웨어와 관련된 작업을 직접 수행

2. 커널 모드의 존재 이유

시스템을 보호하기 위해

커널 모드가 없으면 우리가 만든 프로그램이 마음대로 하드웨어를 다 점유해서 사용하고 다른 프로세스 방해하고 자칫하면 전체 컴퓨터 시스템 붕괴될 수도 있다.

그러니까 시스템 전반적인 부분 즉, 하드웨어적 부분커널에서 관리하고 우리가 만든 프로그램은 커널을 통해 하드웨어 기능 사용할 수 있게 시스템이 안정적으로 돌아갈 수 있게 함

3. Interrupt

시스템에서 발생한 다양한 종류의 이벤트 혹은 그런 이벤트를 알리는 매커니즘이자 어떤 신호가 들어왔을 때 CPU를 잠깐 정지시키는 것

키보드, 마우스 등 IO 디바이스로 인한 인터럽트, 0으로 숫자를 나누는 산술 연산에서의 인터럽트, 프로세스 오류 등으로 발생하며, 발생 시 인터럽트 핸들러 함수가 모여 있는 인터럽트 벡터로 가서 인터럽트 핸들러 함수 실행

그렇다면.. 인터럽트 핸들러 함수란?

인터럽트가 발생했을 때, 이를 핸들링하기 위한 함수. 커널 내부의 IRQ를 통해 호출되며, request_irq( )를 통해 인터럽트 핸들러 함수 등록 가능

🍐 인터럽트의 종류

  1. 전원(power)에 문제가 생겼을 때
  2. I/O 작업이 완료되었을 때
  3. 시간이 다 됐을 때(timer 관련)
  4. 0으로 나눴을 때(trap)
  5. 잘못된 메모리 공간에 접근을 시도할 때(trap)

인터럽트가 발생하면 cpu에서는 즉각적으로 인터럽트 처리를 위해 커널 코드를 커널 모드에서 실행

즉, 커널인터럽트 처리를 위해 cpu에서 주도적으로 실행된다고 보면 된다.

여기서 즉각적이란 인터럽트는 명령어 실행도중 발생했을 텐데 실행중이던 명령어까지는 마무리 하고 커널모드로 전환

🥐 하드웨어 인터럽트

키보드를 연결한다거나 마우스를 연결하는 일 등의 IO 디바이스에 발생하는 인터럽트를 말한다.

🥐 소프트웨어 인터럽트

트랩이라고도 하며, 프로세스 오류 등으로 프로세스가 시스템콜을 호출할 때 발동한다.

4. 시스템 콜(System call)

🍐 시스템 콜의 개념

  • 프로그램이 OS 커널이 제공하는 서비스를 이용하고 싶을 때 시스템 콜을 통해 실행
  • 시스템 콜이 발생하면 해당 커널 코드가 커널 모드에서 실행

🍐 시스템 콜의 종류

  1. 프로세스/스레드 관련
  2. 파일 I/O 관련
  3. 소켓 관련
  4. 장치(device) 관련
  5. 프로세스 통신 관련

🍐 리눅스에서 제공하는 일부 시스템 콜

  • 리눅스는 C언어로 개발됨

5. 시스템 콜 & 인터럽트 예제 : 파일 read

전제

  • 스레드 t1, t2
  • cpu : single core cpu
  1. t1이 실행하고 있다가 read라는 시스템 콜 호출시 커널 모드로 전환

  1. 커널 모드에서는 t1의 cpu 상태 저장
  2. 파일의 위치를 찾아서 버퍼에서 읽을 수 있도록 준비 시킴
  3. read는 block 시스템 이라 파일이 읽을 상태가 될때까지 기다려야 하기 때문에 t1을 wating 상태로 변환해줘야 한다.

  1. 이렇게 되면 cpu에서 일하는 스레드가 없기 때문에 스케줄링을 통해서 계속 일하게 해줘야 한다.
  • t2가 기다리고 있었으니 running으로 바꿔준다.

  1. 이제 유저 모드로 바뀌게 되며, 주도권을 t2가 가지고 된다.
  2. 그러고 실행 되다가.. 파일을 읽을 준비가 됐다고 하면 알려줌

뭐로 파일을 읽을 준비가 됐다고 알려줄까?

그게 바로 interrupt, 파일이 준비가 됐다는 인터럽트 발생시킴

  1. 인터럽트 처리를 위해 다시 커널모드로 전환된다.
  2. 커널모드로 갔으니, t2의 cpu 상태를 저장한다.
  3. t1의 상태를 ready 상태로 변경해 줘야 한다.
  4. t2 cpu 상태 복원

  1. 커널모드 마무리 후 유저 모드로 돌아감
  2. t2가 실행하다가 이 방식이 멀티태스킹 방식이라 t2가 자기에게 주어진 타임슬라이트를 다 쓰면 timer라는 하드웨어를 통해 알려주게 됨
  3. 이 때 알려주는 방식 또한 인터럽트이다. 타이머와 관련된 인터럽트 발생

  1. 다시 커널모드로 전환되며, t2 cpu 상태 저장
  • t2 ready
  • t1 running
  • t1 cpu 상태 복원

  1. 유저모드로 전환되며, 주도권 t1에게 넘어간 후 파일을 읽어올 준비가 다 끝났으니 그 작업을 하게 됨

6. 프로그래밍 언어와 시스템 콜

하드웨어 혹은 시스템 관련 기능은 어떤 프로그램이라도 반드시 시스템 콜을 통해서만 사용 가능하다.

하지만 보통 우리는 개발 시 직접 OS 시스템 콜을 사용한 적은 없었다. 그럼에도 불구하고 우리는 지금까지 파일 I/O, 네트워크 I/O, 프로세스/스레드 작업을 해왔다.

Q. 이게 어떻게 가능했던 것일까?

A. 이것은 우리가 사용하는 프로그래밍 언어들이 시스템 콜을 포장(wrapping)하여 간접적으로 사용할 수 있도록 제공했기 때문이다.

예시 java.lang.Thread class

  • 원래대로라면 무조건 시스템 core를 필요로 하는 작업
Thread thread = new Thread();
thread.start();

thread.class의 일부 코드

  1. native가 붙으면 운영체제를 보통 뜻한다.
  2. java native interface를 통해 기반이 되는 os의 시스템의 콜을 호출하게 됨 즉, 연결이 된다는 것
  3. 리눅스 기반이라면 start0() ⇒ clone이라는 시스템 콜을 호출
  4. 프로그래밍 언어는 탄생 시 자기 철학이나 입맛에 맞는 시스템 콜을 보장해서 쓸 수 있게 제공해준다.

profile
내 지식을 기록하여, 다른 사람들과 공유하여 함께 발전하는 사람이 되고 싶다. gitbook에도 정리중 ~

0개의 댓글