-
Notifications
You must be signed in to change notification settings - Fork 7
close(2)
close - 파일 디스크립터 닫기
#include <unistd.h>
int close(int fd);
close()
는 파일 디스크립터를 닫아서 더 이상 어떤 파일도 가리키지 않으며 재사용할 수 있게 만든다. 연계된 파일에 레코드 락(fcntl(2) 참고)이 잡힌 게 있고 그 프로세스 소유이면 (그 락을 얻는 데 어떤 파일 디스크립터를 썼는지 상관없이) 그 락을 제거한다.
fd
가 하위 열린 파일 기술 항목(open(2) 참고)을 가리키는 마지막 파일 디스크립터이면 그 열린 파일 기술 항목 관련 자원들이 해제된다. 또 그 파일 디스크립터가 unlink(2)로 제거된 파일에 대한 마지막 참조이면 파일이 삭제된다.
성공 시 close()
가 0을 반환한다. 오류 시 -1을 반환하며 errno
를 적절히 설정한다.
EBADF
-
fd
가 유효한 열린 파일 디스크립터가 아니다. EINTR
-
close()
호출이 시그널에 의해 중단되었다. signal(7) 참고. EIO
- I/O 오류가 발생했다.
-
ENOSPC
,EDQUOT
- NFS에서는 이 오류들이 가용 저장 공간을 초과하는 첫 번째 쓰기에서 정상적으로 보고되지 않고 이후의
write(2)
, fsync(2),close()
에서 보고된다.
오류 시 close()
를 재시도하지 말아야 하는 이유에 대한 NOTES의 설명을 보라.
POSIX.1-2001, POSIX.1-2008, SVr4, 4.3BSD.
닫기에 성공했다는 게 데이터가 성공적으로 디스크에 저장됐다는 걸 보장하지는 않는다. 커널에서 버퍼 캐시를 써서 쓰기를 연기하기 때문이다. 일반적으로 파일 시스템에서는 파일이 닫힐 때 버퍼를 플러시 하지 않는다. 기반 디스크에 데이터가 물리적으로 저장되게 해야 한다면 fsync(2)를 써라. (그 다음부터는 디스크 하드웨어에게 달렸다.)
'exec에서 닫기' 파일 디스크립터 플래그를 쓰면 execve(2) 성공 시 파일 디스크립터가 자동으로 닫히도록 할 수 있다. 자세한 내용은 fcntl(2) 참고.
그 파일 디스크립터를 같은 프로세스의 다른 스레드에서 시스템 호출로 사용 중일 수도 있을 동안에 닫는 건 그리 현명한 일이 아니다. 파일 디스크립터가 재사용될 수도 있기 때문에 의도치 않은 부작용을 유발하는 잡아내기 힘든 경쟁 조건이 있을 수 있다.
세심한 프로그래머라면 close()
의 반환 값을 확인할 것이다. 앞선 write(2)
동작에서의 오류가 열린 파일 기술 항목을 해제하는 마지막 close()
에서만 보고되는 일도 충분히 가능하기 때문이다. 파일을 닫을 때 반환 값 검사를 하지 않는 게 조용한 데이터 유실로 이어질 수도 있다. 특히 NFS와 디스크 쿼터에서 이런 경우를 볼 수 있다.
단, 실패 반환 값은 진단 용도(즉 미처리 I/O가 아직 있거나 실패한 I/O가 있었을 수도 있음을 응용에게 알려주기)나 보완 용도(가령 파일에 한 번 더 쓰거나 백업 만들기)로만 쓰는 게 좋다.
실패 반환 후에 close()
를 재시도하는 건 바람직하지 못한 처리 방식이다. 다른 스레드에서 재사용된 파일 디스크립터를 닫히게 할 수도 있기 때문이다. 리눅스 커널에서는 닫기 동작 초반에서 항상 파일 디스크립터를 해제하여 재사용 될 수 있게 만들기 때문에 그런 일이 생길 수 있다. 파일 시스템이나 장치로 데이터를 플러시 하는 것처럼 오류를 반환할 수 있는 단계들은 닫기 동작 후반에서 이뤄진다.
여러 다른 구현들에서도 마찬가지로 이후 close()
반환에서 오류를 보고하더라도 (파일 디스크립터가 유효하지 않다는 뜻인 EBADF
경우를 제외하고) 파일 디스크립터를 항상 닫는다. POSIX.1에서는 현재 이 점에 대해 아무 언급이 없지만 표준 다음 주 릴리스 때 이 동작을 강제화할 계획이 있다.
I/O 오류에 대해 알고 싶은 세심한 프로그래머라면 close()
전에 fsync(2) 호출을 할 수 있다.
EINTR
오류는 다소 특별한 경우다. EINTR
오류와 관련해 POSIX-1.2013에서는 다음과 같이 말한다.
잡게 돼 있는 시그널에 의해
close()
가 중단되는 경우errno
를EINTR
로 설정해서 -1을 반환해야 하며fildes
의 상태는 명세되어 있지 않다.
이는 리눅스와 기타 여러 구현에서 이뤄지는, close()
에서 보고하는 다른 오류들과 마찬가지로 파일 디스크립터가 닫힌다고 보장되는 동작 방식을 허용한다. 하지만 이는 다른 가능성 또한 허용한다. 즉 구현에서 EINTR
오류를 반환하면서 파일 디스크립터를 계속 열어 둘 수도 있다. (문서에 따르면 HP-UX의 close()
에서 이렇게 한다.) 그러면 호출자는 파일 디스크립터 누출을 막기 위해 한 번 더 close()
를 써서 파일 디스크립터를 닫아야 한다. 이러한 구현 동작 방식의 차이는 이식 가능한 응용에 어려운 장애물이 된다. 많은 구현에서는 EINTR
오류 후에 close()
를 다시 호출해선 안 되지만 적어도 한 구현에서는 close()
를 다시 호출해야 하는 것이다. POSIX.1 표준 다음 주 릴리스에서 이 난제를 다루려는 계획이 있다.
fcntl(2), fsync(2), open(2), shutdown(2), unlink(2), fclose(3)
2017-09-15