시스템 콜과 문맥 교환
유저 프로그램은 어떻게 커널에 작업을 요청할까?
본 블로그 작성 글들은, 강의를 목표로 하고 제작되었습니다. 또한 작성된 글의 정보도 틀렸을 수 있으니, 주의해주세요.
유저 모드 프로그램은 디스크나 네트워크 장치를 직접 제어할 수 없다. 대신 운영체제에 작업을 요청하는데, 이 공식적인 요청 방법을 System Call(시스템 콜)이라고 부른다.
일반 함수 호출과 무엇이 다른가?
일반 함수 호출은 같은 권한 영역 안에서 실행 위치만 바꾼다. 시스템 콜은 유저 모드에서 커널 모드로 CPU 권한이 바뀌고, 커널이 요청을 처리한 뒤 다시 유저 모드로 돌아온다.
일반 함수 호출
유저 코드 → 유저 함수 → 유저 코드
시스템 콜
유저 코드 → 커널 진입 → 권한과 인자 검사 → 커널 작업 → 유저 코드
파일 열기, 메모리 매핑, 소켓 통신, 프로세스 생성 같은 기능은 결국 시스템 콜을 사용한다. 프로그래머는 보통 운영체제 API나 표준 라이브러리를 호출하고, 그 아래 계층에서 알맞은 시스템 콜이 실행된다.
Context Switch와는 다르다
시스템 콜을 호출했다고 반드시 다른 프로세스로 바뀌는 것은 아니다. 같은 스레드가 커널 모드로 들어가 요청을 처리하고 바로 돌아올 수도 있다.
Context Switch(문맥 교환)는 현재 실행 상태를 저장하고 다른 스레드나 프로세스의 상태를 복원해서 실행 대상을 바꾸는 작업이다.
시스템 콜: 같은 실행 주체가 커널에 일을 요청함
문맥 교환: CPU가 실행할 주체 자체를 바꿈
다만 파일이나 네트워크 데이터를 기다려야 하는 시스템 콜은 현재 스레드를 대기 상태로 만들 수 있다. 그동안 운영체제는 CPU를 놀리지 않기 위해 다른 스레드를 실행하며, 이때 문맥 교환이 발생할 수 있다.
시스템 콜은 공짜가 아니다
권한 전환과 인자 검사에는 비용이 든다. 작은 데이터를 한 바이트씩 수천 번 쓰는 것보다 버퍼에 모아 한 번에 쓰는 편이 유리한 이유 중 하나다.
std::string buffer;
for (const auto& line : lines)
{
buffer += line;
buffer += '\n';
}
file.write(buffer.data(), buffer.size());
하지만 시스템 콜을 무조건 피해야 한다는 뜻은 아니다. 운영체제가 자원을 안전하게 관리하려면 반드시 필요한 경계이며, 성능 문제가 확인되었을 때 호출 횟수와 대기 방식을 살펴보는 것이 좋다.