[Linux] TLPI 책 정리 7 - Chapter 3 : System Programming Concepts

시온·2023년 6월 25일
0

Linux

목록 보기
7/7
post-thumbnail

System Programming Concepts

이번 챕터에서는 시스템 프로그래밍에 대한 선행지식들을 다룬다.

System Calls

시스템 콜은 어떤 프로세스가 커널에게 특정한 작업을 취하도록 요청하는 명령어이다. 이러한 시스템 콜 API를 통해, 프로세스는 커널 없이는 불가능한 파일 I/O나, pipe 생성, 타 프로세스와의 통신 등을 할 수 있다.

시스템 콜의 일반적인 특징은 다음과 같다.

  • 시스템 콜은 프로세서 상태를 사용자 모드 (user mode) 에서 커널 모드 (kernel mode) 로 변경한다. 이로 인해 CPU가 kernel 메모리 영역을 접근할 수 있게 된다.

  • 시스템 콜 명령어 모음은 정해져있다. 각 시스템 콜은 고유한 넘버링을 받는다.

시스템 콜 호출은 겉보기에는 단순한 C 함수 호출처럼 보이지만, 실상은 다양한 단계로 이루어져 있다.

  1. 응용 프로그램이 wrapper 함수를 통해 시스템 콜을 호출한다.
    wrapper 함수란?

  2. wrapper 함수는 시스템 콜에 필요한 모든 인자를 커널이 지정한 특정한 레지스터에 넣는다.

  3. 커널이 각 시스템 콜을 식별하기 위하여 wrapper 함수가 해당 시스템 콜 넘버를 특정한 CPU 레지스터에 기입한다. (%eax)

  4. wrapper 함수가 trap (소프트웨어 인터럽트) 를 실행하여 프로세스의 모드를 사용자 모드에서 커널 모드로 변경한다.

...

Library Functions

라이브러리 함수란, 단순하게 표준 C 라이브러리를 구성하는 함수들을 의미한다.

대부분의 라이브러리 함수에서는 시스템 콜을 사용하지 않지만, 몇몇 라이브러리 함수는 시스템 콜 위에 레이어링 하고 있다.

fopen() 함수는 open() 이라는 시스템 콜을 사용한다.

또한 라이브러리 함수는 시스템 콜 함수보다 조금 더 사용자 친화적인 인터페이스를 제공한다. 대표적 예시가 printf()로, 시스템 콜인 write()를 사용하지만 훨씬 다양한 기능 및 편의성을 제공한다.

사실, 42서울 과제로 printf()를 구현하는 것이 있는데, write() 함수를 이용해서 구현하는 것이 정말 어려웠다...

The Standard C Library; The GNU C Library (glibc)

UNIX 버전이 다양한 만큼, 표준 C 라이브러리 역시 다양할 수 밖에 없다. 하지만, Linux에서 가장 보편적으로 쓰이는 버전은 바로 GNU C 라이브러리 (glibc) 이다.

Handling Errors from System Calls and Library Functions

Handling system call errors

시스템 콜 함수의 man 페이지를 보게 되면 리턴 값들에 대한 내용이 등장한다. 거의 대부분의 에러는 리턴 값 -1 을 가지게 된다.

fd = open(pathname, flags, mode);	/* system call to open a file */
if (fd == -1) {
	/* Code to handle the error */
}
...
if (close(fd) == -1) {
	/* Code to handle the error */
}

만약 시스템 콜에서 에러가 나게 되면, 전역 변수 errno가 에러에 해당하는 양수값으로 바뀌게 된다. 다음은 errno를 사용하여 시스템 콜 에러를 진단하는 예시이다.

cnt = read(fd, buf, bytes);
if (cnt == -1) {
	if (errno == EINTR)
    	fprintf(stderr, "read was interrupted by a signal\n");
    else {
    	/* Some other error occured */
    }
}

일반적으로, 에러가 발생 시 errno 값에 따른 에러 메시지를 출력한다. perror()와 strerror()함수가 이를 위한 함수다. 다음은 시스템 콜 에러를 핸들링하는 예시이다.

fd = open(pathname, flags, mode);
if (fd == -1) {
	perror("open");
    exit(EXIT_FAILURE);
}

Summary

  1. 시스템 콜은 프로세스가 커널에게 서비스를 요청할 수 있게 해주는 명령어이다.
  2. 아무리 단순한 시스템 콜이라도 일반 C 함수와 비교했을 때 엄청나게 큰 오버헤드를 가지고 있다. (처리 단계가 훨씬 복잡하기 때문)
  3. 표준 C 라이브러리는 다양한 작업을 수행할 수 있는 라이브러리 함수들을 제공한다.
  4. 몇몇 라이브러리 함수들은 시스템 콜 함수들을 이용하는 식으로 구현되어 있다.
  5. 대부분의 시스템 콜 함수들과 라이브러리 함수들은 리턴 값을 가지며, 리턴 값으로 함수 호출이 성공했는지 실패했는지 판별한다. 이러한 경우 리턴 값은 항상 체크를 해야한다.
profile
끊임없이 성장중

0개의 댓글