Study · 운영체제 · 파일 디스크립터 · 프로세스

열린 파일은 프로세스마다 번호표로 들고 있다

장면

프로세스가 파일을 열면 돌려받는 것은 무엇일까? 그 번호는 어디에 적혀 있을까?

$ ls -l /proc/self/fd
lrwx------ 1 tghan tghan 64 Sep 21 14:10 0 -> /dev/pts/0
lrwx------ 1 tghan tghan 64 Sep 21 14:10 1 -> /dev/pts/0
lrwx------ 1 tghan tghan 64 Sep 21 14:10 2 -> /dev/pts/0
# 맨 끝의 0 · 1 · 2 가 번호다 — 이미 세 개가 차 있어서 새로 여는 파일은 3 부터다. 앞의 권한 · 날짜는 넘겨도 된다

아래 재생기의 ▶를 누르면 한 스텝씩 진행된다. 금색 테두리가 지금 이야기하는 곳이고, 캡션이 무슨 일이 일어났는지 말해 준다. 굵게 밑줄 친 말은 누르면 뜻이 나온다. 빨간 딱지는 그때 벌어지는 일의 이름이고, 캡션 바로 위 회색 글자는 지금 스텝이 속한 묶음의 이름이다.

카드 아래 회색 줄은 그 일이 실제로 적혀 있는 소스의 파일 이름 : 줄 번호와 함수 이름이다. 글 안에 (:669)처럼 줄 번호만 적힌 것은 바로 앞에 적은 파일의 그 줄이라는 뜻이다. 캡션 한가운데 박힌 긴 영어 이름과 괄호 속 파일 · 줄 번호도 같다 — 건너뛰고 한글만 읽어도 뜻이 통하게 써 두었다.

장면 · 열린 파일은 프로세스마다 번호표로 들고 있다 0 / 10

▶ 를 누르면 open("/etc/hosts") 한 번이 3 이라는 번호를 돌려주기까지를 따라간다. 돌려받는 것은 파일이 아니라 번호 하나다. 그 번호는 프로세스마다 따로 있는 번호표의 몇 번째 칸인지를 뜻한다. 왜 하필 3 이 나오는지도 그 표를 보면 풀린다.

키보드 · ← → 한 스텝 · Space 재생/멈춤 · Home 처음

열린 것은 프로세스마다 따로 있는 번호표에 걸린다. 0·1·2 가 이미 차 있어서 새로 여는 것이 3 부터이고, 이 표에는 파일만 걸리는 것이 아니다.

어떻게 확인했나

소스 어디를 보고 적었는지와 무엇을 돌려서 쟀는지를 남긴 자리다. 처음 읽을 때는 건너뛰어도 된다.

  • fd 표는 task_struct 의 files 필드다(include/linux/sched.h:1207). 그 struct files_struct(include/linux/fdtable.h:38) 안에 fdtable(:26) 이 있고, 칸 배열 fd 와 쓰임 표시 open_fds 비트맵이 거기 들어 있다. 처음 크기는 NR_OPEN_DEFAULT(:24) = BITS_PER_LONG 칸뿐이고, 넘으면 expand_files(fs/file.c:288) 가 넓힌다.
  • 번호는 「비어 있는 가장 작은 칸」이다. alloc_fd(fs/file.c:569) 가 start = 0 에서 find_next_fd(fs/file.c:544) 로 open_fds 의 첫 0 비트를 찾는다. 0 · 1 · 2 가 이미 켜져 있으니 새로 여는 것은 3 부터다 — 커널이 3 을 특별히 정해 둔 것이 아니다.
  • 여는 차례는 「번호 먼저, 파일 나중」이다. do_sys_openat2(fs/open.c:1408) 의 FD_ADD 매크로가 get_unused_fd_flags(fs/file.c:619) 로 칸을 예약하고(include/linux/file.h:195), 파일이 다 만들어진 뒤에야 fd_install(fs/file.c:679) 로 그 칸에 건다.
  • 소켓도 같은 표에 걸린다. sock_map_fd(net/socket.c:578) 가 쓰는 것이 똑같은 get_unused_fd_flags + fd_install 쌍이다. 15번 항목과 이어지는 자리다.
  • 번호가 가리키는 것은 struct file(include/linux/fs.h:1255) 이고, 읽던 위치 f_pos(:1277) 는 파일이 아니라 여기에 붙어 있다. fork 하면 표가 dup_fd(fs/file.c:383) 로 복제되고, exec 하면 do_close_on_exec(fs/file.c:890) 가 O_CLOEXEC 로 표시된 칸만 닫는다.
  • python 으로 파일을 하나 여니 fd 번호가 3 이었다. /proc/self/fd 에 0 · 1 · 2 가 이미 차 있어서 남는 가장 작은 번호가 3 이라 그렇다. 한 프로세스가 열 수 있는 수의 상한은 /proc/self/limits 의 Max open files 이고, 이 컨테이너는 1,048,576 이었다.
‹ 이전 다음 항목 ›