Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- userprog
- 백준
- 핀토스
- 큐
- TiL
- 리액트
- 모션비트
- 4기
- 나만무
- 스택
- 사이드프로젝트
- HTML
- Java
- 소켓
- 티스토리챌린지
- Vue.js
- 크래프톤정글
- 자바
- 크래프톤 정글
- CSS
- 코드트리
- 자바스크립트
- JavaScript
- defee
- corou
- 시스템콜
- 알고리즘
- 오블완
- pintos
- Flutter
Archives
- Today
- Total
미새문지
크래프톤 정글 week05, day32 - User mode & Kernel mode, 시스템 콜(System Call) 본문
크래프톤 정글/TIL
크래프톤 정글 week05, day32 - User mode & Kernel mode, 시스템 콜(System Call)
문미새 2024. 2. 21. 00:35728x90
실행 흐름
- 우리가 개발하는 프로그램은 일반적으로 유저 모드에서 실행된다.
- 프로그램 실행 중에 인터럽트(interrupt)가 발생하거나 시스템 콜(system call)을 호출하게 되면 커널 모드로 전환된다.
- 전환된 커널 모드에선 프로그램의 현재 cpu상태를 저장하고, 인터럽트나 시스템 콜을 직접 처리하게 된다. 그리고 처리가 완료되면 중단됐던 프로그램의 cpu 상태를 복원하고 다시 유저 모드로 전환되며 프로그램이 이어서 실행된다.
커널(kernel)
- 운영체제의 핵심이며, 이를 규정짓는 매우 중요한 소프트웨어. 시스템의 전반을 관리/감독하는 역할이다.
- 하드웨어의 자원을 자원이 필요한 프로세스에 나눠주고, 프로세스 제어, 메모리 제어, 시스템 콜 등을 수행하는 부분으로 운영체제의 가장 아래 계층에서 돌아간다.
- 커널 모드가 있는 이유는 시스템을 보호하기 위해 잇으며, 만약 커널 모드가 없으면 우리가 만든 프로그램이 하드웨어를 점유하게 되고 프로세스가 조작되어 위험하다.
인터럽트(Interrupt)
- 시스템에서 발생한 다양한 종류의 이벤트 혹은 그런 이벤트를 알리는 메커니즘
- 인터럽트 종류
- 전원(power)에 문제가 생겼을 때
- I/O 작업이 완료 됐을 때
- 시간이 다 됐을 때(timer 관련)
- 0으로 나눴을 때 *
- 잘못된 메모리 공간에 접근을 시도할 때 *
- * 종류는 보통 trap이라고 불리기도 한다.
- 인터럽트가 발생하면 cpu에서는 즉각적으로 인터럽트 처리를 위해 커널 코드를 커널 모드에서 실행한다.
시스템 콜(System call)
- 프로그램이 OS 커널이 제공하는 서비스를 이용하고 싶을 때 시스템 콜을 통해 실행한다.
- 운영체제의 기능을 사용하는 모든 프로그램은 시스템 호출을 통해 해당 기능을 호출해야 한다. 이를 통해 운영체제는 프로그램의 요청을 처리하고, 시스템의 자원을 효율적으로 관리할 수 있다.
- 시스템 콜의 종류
- 자원 관리 : 메모리, 프로세스, 파일, 네트워크 등의 자원 관리
- 프로세스 관리 : 프로세스의 생성, 종료, 실행 등을 관리
- 입출력 관리 : 키보드, 마우스, 모니터 등의 입출력 장치를 관리
- 시스템 호출 처리 : 응용 프로그램이 요청한 시스템 호출을 처리
- 하드웨어 제어 : CPU, 메모리, 디스크 등의 하드웨어를 제어
- 시스템 콜이 발생하면 해당 커널 코드가 커널 모드에서 실행
- 시스템 콜 & 인터럽트 예제 : 파일 read
- t1 : 스레드1, t2 : 스레드2, 싱글코어 cpu
- t1이 cpu에서 실행 중이고 t2가 대기 상태로 있을 때
- t1이 user mode에서 file을 시스템 콜의 read를 호출 했을 시 커널 모드로 전환
- 커널 모드에서 t1 cpu 상태를 저장된다.(파일을 읽을 준비) → t1은 waiting 상태로 전환
- cpu에서는 동작하는 게 없기 때문에 바로 다음 작업인 t2를 실행 준비를 하고 유저 모드로 전환
- 유저 모드에서 t2가 실행하다가 ssd에서 t1이 요청한 파일을 읽을 준비가 되었다고 인터럽트를 발생시킨다. 그럼 발생한 인터럽트를 처리하기 위해 다시 커널 모드로 전환
- 커널 모드에서 t2 cpu 상태를 저장하고, t1의 상태를 ready 상태로 바꾼다.
- t2의 cpu 상태를 복원하고 다시 통제권을 유저 모드로 넘겨준다.
- 아까 인터럽트 때문에 중단됐던 부분에서 다시 시작한다. 지금 방식이 멀티 태스킹 방식이기 때문에 timer라는 하드웨어를 통해 알려주는데 그 때 인터럽트가 발생해 커널 모드로 전환
- t2의 cpu 상태를 저장하고 ready상태가 된다. 그리고 t1이 running 상태가 되며 복원된다. 그리고 유저 모드로 통제권을 넘겨준다.
- t1이 실행되고 파일을 읽을 준비가 되었기 때문에 데이터를 읽어오는 작업을 한다.
- t1이 cpu에서 실행 중이고 t2가 대기 상태로 있을 때
- t1 : 스레드1, t2 : 스레드2, 싱글코어 cpu
- 함수 종류
- 프로세스 관리 : 프로세스 생성, 종료, 실행 등을 관리하는 함수
- 메모리 관리 : 메모리 할당, 해제, 복사 등을 관리하는 함수
- 파일 시스템 관리 : 파일 생성, 삭제, 읽기, 쓰기 등을 관리하는 함수
- 네트워크 관리 : 네트워크 연결 설정, 데이터 전송 등을 관리하는 함수
- 입출력 관리 : 키보드, 마우스, 모니터 등의 입출력 장치를 관리하는 함수
- 시스템 호출의 예시
- 프로세스 생성 : fork() 시스템 호출을 사용하여 새로운 프로세스를 생성할 수 있다.
#include <stdio.h>
#include <unistd.h>
int main() {
pid_t pid = fork(); // fork() 시스템콜을 호출하여 자식 프로세스를 생성하고, 생성된 자식 프로세스의 pid 값을 pid 변수에 저장
if (pid == 0) { // 자식 프로세스인 경우에만 실행되는 조건문
printf("Child process\n"); // 자식 프로세스가 실행될 때 "Child process"를 출력
} else if (pid > 0) { // 부모 프로세스인 경우에만 실행되는 조건문
printf("Parent process\n"); // 부모 프로세스가 실행될 때 "Parent process"를 출력
} else { // fork() 시스템콜이 실패한 경우에 실행되는 조건문
printf("Fork failed\n"); // fork() 시스템콜이 실패한 경우에 "Fork failed"를 출력
}
return 0; // 프로그램 종료
}
- 파일 읽기 : open() 시스템 호출을 사용하여 파일을 열고, read() 시스템 호출을 사용해 파일의 내용을 읽을 수 있다.
#include <stdio.h>
#include <fcntl.h> // 파일 제어를 위한 헤더 파일
#include <unistd.h>
int main() {
int fd = open("test.txt", O_RDONLY); // "test.txt" 파일을 읽기 전용으로 열고, 파일 디스크립터를 fd 변수에 저장
if (fd == -1) { // 파일 열기가 실패한 경우에 실행되는 조건문
printf("파일 열기 실패\n"); // 파일 열기가 실패한 경우에 "파일 열기 실패"를 출력
return -1; // 프로그램 종료
}
char buf[100]; // 파일의 내용을 저장할 버퍼
ssize_t nread = read(fd, buf, sizeof(buf)); // fd로 지정된 파일 디스크립터에서 buf 크기만큼의 데이터를 읽어와 nread 변수에 저장
if (nread == -1) { // 파일 읽기가 실패한 경우에 실행되는 조건문
printf("파일 읽기 실패\n"); // 파일 읽기가 실패한 경우에 "파일 읽기 실패"를 출력
close(fd); // 사용이 끝난 파일 디스크립터를 닫음
return -1; // 프로그램 종료
}
printf("파일 내용: %s\n", buf); // 파일의 내용을 출력
close(fd); // 사용이 끝난 파일 디스크립터를 닫음
return 0; // 프로그램 종료
}
- 네트워크 연결 설정 : socket() 시스템 호출을 사용하여 네트워크 연결을 설정하고, connect() 시스템 호출을 사용하여 서버에 연결할 수 있다.
- 시스템 호출은 운영체제의 기능을 사용하기 위해 필수적인 요소이며, 프로그램의 성능과 안정성에 큰 영향을 미친다.
- 네트워크 연결 함수
- socket() : 시스템 호출을 사용하여 소켓을 생성한다.
- bind() : 시스템 호출을 사용하여 소켓을 바인드 한다.
- listen() : 시스템 호출을 사용하여 클라이언트의 연결 요청을 대기한다.
- accept() : 시스템 호출을 사용하여 클라이언트의 연결을 수락한다.
- write() : 시스템 호출을 사용하여 클라이언트에게 메세지를 전송한다.
- read() : 시스템 호출을 통해 클라이언트로부터 메세지를 수신한다.
- 시스템 콜 함수
- brk(), sbrk() : malloc 함수로 메모리 할당을 요청할 때 사용하는 시스템 콜
- brk, sbrk는 힙의 크기를 변경하는데, 힙은 데이터 영역 직후에 시작해 위쪽으로 메모리 주소가 커지는 영역이다.
- 즉, 현재 프로세스의 program break(힙의 꼭대기를 가리키는 변수)의 위치를 변경하는 함수이다.
- heap 영역의 요청이 없을 때 까지는 Data Segment = Program Break이다.
- brk와 sbrk의 차이
- brk()
- 해당 값이 합리적이고 시스템에 메모리가 충분할 때 program break를 brk의 인자인 addr에서 지정한 값으로 설정한다. 그리고 프로세스는 최대 데이터 크기를 초과하지 않는다.
- 성공 시 0, 실패 시 -1을 반환한다.
- sbrk
- program break를 increment bytes만큼 증가시킨다. increment 인자를 0으로 설정해 sbrk()를 호출하는 건 현재의 program break의 위치를 찾을 때 쓰인다.
- 성공 시 이전 program break 주소를 반환하며 실패 시 void* 포인터 형으로 -1을 반환한다.
- program break가 증가한 경우, 이 반환 값은 새로 할당된 메모리의 시작 부분에 대한 포인터이다.
- brk()
- brk와 sbrk의 차이
- brk, sbrk는 힙의 크기를 변경하는데, 힙은 데이터 영역 직후에 시작해 위쪽으로 메모리 주소가 커지는 영역이다.
- brk(), sbrk() : malloc 함수로 메모리 할당을 요청할 때 사용하는 시스템 콜
#include <stdio.h>
int main()
{
printf("brk(0) : %d \n", brk(0));
printf("sbrk(0) : %d \n", sbrk(0));
return 0;
}
// 결과
// brk(0) : 0
// sbrk(0) : 0x8efe000
보통 개발할 때 직접 OS 시스템 콜을 사용한 적이 없었는데 파일 I/O, 네트워크 I/O, 프로세스/스레드 관련 작업을 할 수 있던 건 사용하고 있는 프로그래밍 언어들이 시스템 콜을 포장(wrapping)하여 간접적으로 사용할 수 있도록 제공했기 때문이다.
학습 시간 : 14 ~ 24시
728x90
'크래프톤 정글 > TIL' 카테고리의 다른 글
크래프톤 정글 week05, day34 - 저장 장치 기술 (1) | 2024.02.21 |
---|---|
크래프톤 정글 week05, day33 - 포인터 문제 -1 (2) | 2024.02.21 |
크래프톤 정글 week05, day31 - rb트리 구현 코드 (1) | 2024.02.21 |
크래프톤 정글 week04, day30 - rb트리 구현 중 (1) | 2024.02.21 |
크래프톤 정글 week04, day29 - 프로세스, 쓰레드 (1) | 2024.02.20 |