Krafton Jungle/2. Keywords

[WEEK07] System Call

munsik22 2025. 4. 28. 17:18

System Call

[출처] Operating System Concepts 10th - SILBERSCHARTZ

 

시스템 콜은 응용프로그램이 OS에게 서비스를 요청하는 인터페이스이다. 일반적인 응용프로그램은 HW에 직접 접근할 수 없기 때문에, 파일 입출력, 프로세스 생성, 네트워크 통신, 메모리 제어 등의 작업이 필요할 때 OS 커널에 도움을 요청한다. 이 때 사용하는 것이 시스템 콜이다.

시스템 콜은 사용자가 OS에게 직접 무언가를 부탁하는 legal한 path다.

System Call의 주요 특징

  • 커널 모드 진입 : 시스템 콜을 호출하면 CPU 모드는 유저 모드(User Mode)에서 커널 모드(Kernel Mode)로 전환된다.
  • 보안 및 안정성 보장 : 사용자 프로그램이 직접 하드웨어를 다루지 못하도록 차단하고, 시스템 콜을 통해서만 제어할 수 있게 한다.
  • 오버헤드 : 모드 전환이 일어나기 때문에 함수 호출에 비해 비용이 크다. (context switching 발생)

System Call의 동작 흐름

  1. 사용자 프로그램이 시스템 콜 라이브러리 함수를 호출한다(open(), read() 등).
  2. 라이브러리 함수는 CPU에 System Call 번호를 세팅하고, 특별한 명령어(예: syscall, int 0x80)로 커널에 진입한다.
  3. 커널이 해당 요청을 처리하고 결과를 반환한다.
  4. 유저 모드로 복귀하고, 결과를 사용자 프로그램에 전달한다.

System Call의 예시

분류 시스템 콜
파일 조작 open(), read(), write(), close()
프로세스 관리 fork(), exec(), exit(), wait()
메모리 관리 mmap(), brk()
통신 socket(), bind(), accept(), connect()
기타 getpid(), kill()
  • C 예시 코드 : 여기서 open, write, close는 모두 직접 시스템 콜을 호출하는 C 라이브러리 함수다.
#include <unistd.h>    // write(), close()
#include <fcntl.h>     // open()
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>

int main() {
    int fd;
    const char *text = "Hello, World!\n";

    // 파일 열기 (O_WRONLY: 쓰기 모드, O_CREAT: 파일 없으면 생성, O_TRUNC: 기존 내용 삭제)
    fd = open("example.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (fd == -1) {
        perror("open");
        return 1;
    }

    // 파일에 쓰기
    if (write(fd, text, 20) == -1) {
        perror("write");
        close(fd);
        return 1;
    }

    // 파일 닫기
    if (close(fd) == -1) {
        perror("close");
        return 1;
    }

    return 0;
}
  • 다른 예제 : System call을 사용해 프로세스 생성과 프로그램 실행
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>

int main() {
    pid_t pid = fork();

    if (pid < 0) { // fork 실패
        perror("fork");
        return 1;
    } else if (pid == 0) { // 자식 프로세스
        printf("Child: Executing 'ls -l'\n");
        char *args[] = {"ls", "-l", NULL};
        execvp(args[0], args);

        // execvp 실패 시
        perror("execvp");
        return 1;
    } else { // 부모 프로세스
        printf("Parent: Waiting for child to finish\n");
        wait(NULL);  // 자식 프로세스 종료 기다림
        printf("Parent: Child finished\n");
    }

    return 0;
}