공부 기록/운영체제

컴퓨터 시스템과 운영체제 (3)

도도히히 2025. 11. 9. 20:16

3. 커널과 시스템 호출

응용프로그램의 자원 접근 문제

오늘날 운영체제: 다중 프로그래밍 운영체제

  • 다수의 응용프로그램이 한 컴퓨터에서 동시에 실행

문제

  • 응용프로그램이 직접 컴퓨터 자원에 접근하면 충돌과 훼손 발생
    • 다른 응용프로그램이 적재된 메모리 훼손 가능
    • 다른 응용프로그램이 만든 파일 삭제 및 훼손 가능
    • 응용프로그램이 커널이 적재된 영역 훼손 가능

해결 방안

  • 응용프로그램의 자원 접근 불허
    • 자원에 대한 모든 접근 권한을 커널에만 부여

구체적인 해결 방법

  • 메모리 공간User spaceKernel space로 분리
    • 응용프로그램은 User space에 적재, 커널은 Kernel space에 적재
  • CPU의 실행 모드User modeKernel mode로 분리
    • 응용프로그램은 User mode에서만 실행, 커널은 Kernel mode에서만 실행
    • User space에서 Kernel space의 코드를 직접 접근하지 못하게 하기 위해
    • User mode에서 커널 코드를 접근하면 응용프로그램 강제 종료(하드웨어에 대한 접근 차단 및 커널 보호)
  • 응용프로그램이 커널 기능을 이용하고자 할 때, 시스템 호출을 이용해서만 커널 코드 이용

 

User space와 Kernel space

 

운영체제는 컴퓨터 메모리를 두 공간으로 분리

  • User space: 응용프로그램들이 나누어 사용하는 공간
    • 응용프로그램들이 적재
  • Kernel space: 커널만 사용할 수 있는 공간
    • 디바이스 드라이버 포함

분리 이유

  • 커널 코드와 데이터를 악의적인 응용프로그램이나 코딩 실수로부터 지키기 위함

CPU는 User mode와 Kernel mode 중 한 모드로 실행

  • CPU에 의해 구현되고 운영체제가 활용하는 기능
  • 모드 레지스터 (CPU 내부에서 모드 상태를 나타냄)
  • 운영체제는 CPU 모드 레지스터를 이용해 커널 영역 지킴
  • User mode
    • CPU의 모드 비트: 1
    • User space에 있는 코드나 데이터에 액세스
    • Kernel space의 접근 불허 (응용프로그램으로부터 커널 영역 보호)
    • Privileged instruction 실행 불허 (입출력 장치, 타이머, 인터럽트 처리, 시스템 중단 등 특별한 목적으로 설계된 CPU 기계 명령)
  • Kernel mode
    • CPU의 모드 비트: 0
    • 모든 메모리 공간에 접근할 수 있고 하드웨어 접근 및 제어 가능
    • Privileged Instruction 사용 가능

 

User mode → Kernel mode

 

2가지 경우

  • 시스템 호출
  • 인터럽트 발생

시스템 호출

  • 특별한 CPU 기계 명령에 의해 진행
  • 기계 명령이 CPU의 모드 비트를 Kernel mode로 전환

인터럽트

  • CPU가 인터럽트를 수신하면 Kernel mode로 자동 전환(인터럽트 서비스 루틴이 Kernel space에 있음)
  • 인터럽트 서비스 루틴 실행
  • 루틴이 끝나면 CPU는 User mode로 전환

 

Privileged instruction

 

Kernel mode에서 실행할 특별한 목적으로 설계된 CPU 명령

종류

  • I/O 명령
    • 하드웨어 제어 및 장치로부터의 입출력
  • Halt 명령
    • CPU의 작동을 중지시키는 명령 (현재 처리할 작업이 없을 때)
    • CPU를 유휴 상태로 만들기 (전력 소모 줄이기)
  • 인터럽트 플래그를 켜고 끄는 명령
    • CPU 내에 있는 인터럽트 플래그 비트를 제어하여 인터럽트를 허용하거나 무시하도록 지시
    • 인텔) cli(clear interrupt flag)/sti(set interrupt flag) 명령
      • cli: 인터럽트 비활성화
      • sti: 인터럽트 활성화
  • 타이머 설정 명령
    • CPU 타이머 설정
    • 일정한 간격으로 인터럽트 발생 → 운영체제가 프로세스 스케줄링 등을 제어할 수 있도록 함
  • 컨텍스트 스위칭 명령
    • CPU가 하나의 프로세스에서 다른 프로세스로 작업을 전환할 때 사용
    • 여러 프로세스가 CPU 공유하면서 사용
  • 메모리 지우기 명령
    • 메모리 초기화
    • 사용하지 않는 메모리 영역 줄이기
  • 장치 상태 테이블 수정 등의 명령
    • 시스템의 다양한 하드웨어 장치 상태를 기록하고 관리하는 테이블 수정

 

커널은 프로세스인가?

  • 커널: 부팅 시에 Kernel space에 적재된 함수들과 데이터 집합
    • 컴파일된 바이너리 형태
    • 하드디스크 특정 영역에 저장
    • 부팅 시 Kernel space의 메모리에 적재
  • 커널 코드는 함수들의 집합
    • Kernel mode에서 실행되는 함수들과 데이터들의 집합
  • 커널은 프로세스가 아님
    • 독립적으로 실행 X
      • 응용프로그램이 시스템 호출을 통해 커널에 기능을 요청할 때 실행
      • 인터럽트가 발생하여 인터럽트 서비스 루틴이 실행될 때 실행

cf. 커널은 스택, 힙을 가지는 주체가 아님 (프로세스나 스레드는 스택, 힙을 가지고 있음)

커널 모드에서 작업을 처리할 때만 각 프로세스의 커널 공간의 커널 스택을 사용함

 

함수 호출 vs 시스템 호출 비용

  • 함수 호출: 라이브러리 활용
    • User space에 적재된 함수가 다른 함수나 라이브러리 함수 호출
    • CPU 실행 모드: User mode
    • 실행 과정
      • User space의 스택에 리턴 주소와 매개변수 전달
      • 호출된 함수의 지역변수 생성
      • 끝나면 함수를 호출한 곳으로 복귀
  • 시스템 호출: 커널 기능 활용
    • 시스템 호출 라이브러리에 작성된 시스템 호출 함수를 통해 간접적으로 커널 기능 요청
    • CPU 실행 모드: User mode → Kernel mode로 전환
    • 실행 과정
      • 시스템 호출을 일으키는 특별한 기계 명령 (CPU마다 다름) 실행
      • 커널 함수마다 매겨진 고유 번호 전달(시스템 호출 번호)
      • User mode → Kernel mode
      • 커널의 시스템 호출 핸들러 실행 (커널 함수의 고유 번호를 분석해 해당 커널 함수 호출)
      • 리턴할 때 User mode로 전환 (사용자 프로그램으로 복귀)

 

printf()가 직접 디스플레이에 출력할까?

printf() 함수는 표준 라이브러리 함수

  • 디스플레이에 접근하는 것은 커널만 가능
  • printf() 함수는 디스플레이에 직접 출력 불가능
  • 표준 라이브러리 함수는 특정 CPU/OS에 종속적이지 X
  • printf()는 C 표준 라이브러리의 버퍼에 출력
  • write() 호출: 버퍼가 차거나 (full buffering), 개행문자를 만나면 실행 (line buffering)
    • full buffering: 데이터가 가득 찼을 때 한꺼번에 출력
    • line buffering: 실시간으로 데이터 출력할 때 유용, 비교적 더 많은 시스템 호출 발생
  • write() 함수는 “시스템 호출 CPU 명령” 실행
  • 커널에 작성된 함수가 디스플레이에 해당 내용 출력

printf()가 시스템 호출을 직접 일으키지 X, write() 함수를 호출하여 시스템 호출 발생하도록 함

but, 매번 write 함수를 호출하지 X → 데이터를 더 효율적으로 처리하기 위해 출력 버퍼를 활용함

출력 버퍼: 출력할 데이터를 임시로 모아두는 공간(유저 공간에 있음) → 시스템 호출 최소화

 

Full & line buffering 실험

기본적으로 라인 버퍼링이 적용됨

 

출력 결과는?

#include <stdio.h>
#include <unistd.h>

int main() {
	printf("123");
	write(1, "45", 2);
	printf("67\\n");
	write(1, "8", 1);
	printf("9");
	write(1, "10", 1);
	printf("\\n");
	
	return 0;
}

 

결과:

4512367

819

 

write(1, “45”, 2);

  • 2: 2바이트를 쓴다는 의미, 45를 씀

write(1, “10”, 1);

  • 1: 1바이트를 쓴다는 의미, 10 중에서 앞의 1만 씀

 

fread() vs read()의 호출 비용 비교

fread()

size_t fread(void *buffer, size_t size, size_t count, FILE *stream);
  • 파일 포인터가 가리키는 파일로부터 size 단위의 데이터를 count 개수만큼 읽어서 buffer 라는 공간에 읽어들이라는 프로토타입
  • 반환값: 성공적으로 읽어들인 원소의 개수

read()

size_t read(int fd, void *buf, size_t nbytes);
  • 파일 디스크립터(fd)로부터 n바이트를 읽어서(nbytes, buf보다 크면 안됨) buf가 가리키는 공간에 저장하라는 프로토타입
  • 반환값: 성공적으로 읽어들인 데이터 크기 (항상 리턴값이 n바이트인 것은 아님)

 

fread() vs. read()

시스템 호출은 함수 호출에 비해 많은 시간 비용 (시스템 호출을 많이 할수록 실행 속도 저하)

ex) 파일에서 1000바이트를 읽는 2가지 유형의 코드의 실행 비교 결과? (아래 ex에 있음)

 

표준 라이브러리 함수 fread(buf, size, count, fp)의 동작 과정

fread() 처음 호출: 라이브러리 내 버퍼(입력버퍼)가 비어 있음

→ read() 호출하여 라이브러리 내 버퍼 채움 (시스템 호출)

n = read(fd, buf, size); → 보통 I/O block size : 4KB

응용프로그램이 요청한 size만큼 응용프로그램의 buf로 복사

버퍼가 비거나 부족하면 다시 read() 호출

 

ex)

char buf[100];

for (i=1; i≤10; i++)

fread(buf, 1, 100, fp);

  • 1번째 반복에서는 read()를 호출해 시스템 호출을 1번 실행함(sys_read()가 실행됨, 하드디스크로부터 데이터를 읽어들여와 표준 라이브러리 내에 있는 입력 버퍼에 데이터 채워넣음)
  • 2번째 ~ 10번째 반복에서는 입력 버퍼에 저장된 데이터를 가지고 fread()로 읽어오기 때문에 시스템 호출을 하지 않아도 됨

 

시스템 호출 함수 read(fd, buf, size)의 동작 과정

시스템 호출을 이용하여 커널 코드 실행

커널 코드에서 디스크 읽기

라이브러리를 거치지 않고 바로 buf로 읽어들임

(입력 버퍼X)

ex)

char buf[100];

for (i=1; i≤10; i++)

read(fd, buf, 100);

  • 입력 버퍼가 없어 반복마다 시스템 호출을 해야 하므로 성능이 저하됨

 

시스템 호출에 따른 비용 정리

시스템 호출에 따른 비용은 매우 큼

시스템 호출은 필연적이지만, 시스템 호출 횟수를 줄여야 응용프로그램의 실행 시간이 짧아지고 더 많은 프로그램을 실행시킬 수 있는 시간을 확보하여 시스템의 처리율이 향상

 


4. 운영체제와 인터럽트

Interrupt(인터럽트)

입출력 장치나 저장 장치들이 비동기적 사건을 CPU에게 알리는 행위

  • 비동기적: 예정되지 않거나 발생시간을 예측할 수 없는 이벤트
  • ex) 키보드 입력, 네트워크로부터 데이터 도착 등

 

하드웨어 인터럽트

  • 장치들이 어떤 상황 발생을 CPU에게 알리는 하드웨어 신호
  • CPU는 인터럽트를 수신하면 인터럽트 서비스 루틴 실행

ex) 하드디스크에서 데이터를 읽는 동안 CPU는 다른 작업을 수행하고 있다가 하드디스크가 작업을 완료했을 때 인터럽트를 통해 CPU에게 알림

 

소프트웨어 인터럽트

  • CPU 명령으로 발생시키는 인터럽트 (소프트웨어적으로 CPU 신호를 보내 특정 작업 요청)
  • 시스템 호출을 일으키는 int 0x80 명령 등

 

컴퓨터에서 인터럽트 활용

  • 마우스 조작 (마우스 움직이거나 클릭)
  • 키보드 입력
  • 네트워크로부터 데이터 도착
  • 하드디스크의 쓰기 종료
  • 시스템 클럭으로부터 일정한 시간 간격으로 알림
  • 컴퓨터의 리셋 버튼 누르기
  • USB 메모리의 부착 혹은 해제

 

인터럽트 서비스 루틴

: 하드웨어 인터럽트가 발생했을 때 CPU가 그에 대응하는 코드를 실행할 수 있도록 하는 중요한 매커니즘

  • 인터럽트 핸들러 라고도 불림
  • 디바이스 드라이버커널 코드에 포함
    • 커널의 일부로 작동
    • 각 하드웨어 장치에 대한 하드웨어 드라이버에 의해서 정의
  • 임베디드 컴퓨터의 경우 ROM에 위치
    • 시스템이 부팅 시부터 인터럽트를 처리할 수 있도록 하기 위함
    • 임베디드 시스템에서 하드웨어와 소프트웨어가 밀접하게 결합 → 인터럽트 서비스 중요
  • 각 드라이버가 커널과 연결됨, 드라이버를 통해 장치와 소통

 

다중프로그래밍 리뷰

  • 여러 프로세스 동시에 실행
  • 한 프로세스가 입출력 시행하면 다른 프로세스로 교체
  • 인터럽트: 입출력이 완료될 때 장치로부터 입출력 완료 통보를 받는 방법
    • 인터럽트가 없다면 CPU는 입출력 완료를 계속 검사하는 **폴링(polling)**을 실행해야 하므로 매우 비효율적
    • 인터럽트가 없다면, 다중프로그래밍 운영체제의 구현은 사실상 거의 불가능

 

인터럽트의 효과

  • 입출력 장치와 CPU가 동시에 각자의 작업 실행
    • 입출력 장치는 지시받은 입출력 진행하고 CPU는 다른 프로그램 실행
  • 컴퓨터 시스템이 효율적으로 작동
    • CPU 활용률 높아지고 시스템 처리율 향상

'공부 기록 > 운영체제' 카테고리의 다른 글

컴퓨터 시스템과 운영체제 (2)  (0) 2025.11.09
컴퓨터 시스템과 운영체제  (0) 2025.11.09