파일 열기
|
|
- 파일을 열고 파일 디스크립터에 매핑
- flags 인자는 O_RDONLY, O_WRONLY, O_RDWR중 하나를 포함해야 함, 그외 O_APPEND, O_NONBLOCK 등이 있음 (책참조)
- mode에서는 새로운 파일의 권한(ex 0644, S_IRWXU 등이 있음, 책참조)
- O_WRONLY|O_CREAT|O_TRUNC 조합은 너무 일반적이라 creat()시스템 콜을 제공
- 에러 발생 시 -1 리턴 후 errno를 적절한 에러값으로 설정
파일 읽기
|
|
- fd가 참조하는 파일의 현재 오프셋에서 len byte바이트 만큼 buf에 읽기
- 현재 읽은 바이트수 반환, 에러시 -1 반환, 0 반환 시 EOF(읽을 데이터 없음)을 나타냄(책에 리턴의 다양한 상황에 대해 나와 있음)
- 논블럭 읽기 모드에서 읽을 데이터가 없다면 -1반환, errno를 EAGAIN으로 설정(논블럭 모드시 반드시 점검할 것)
- 최대 읽기 값은 SSIZE_MAX(LONG_MAX, 0x7ffffff)
- SIZE_MAX는 size_t의 최대값으로 부호가 없는 값, ssize_t는 부호 있는 값을 나타냄
파일 쓰기
|
|
- count 바이트 만큼 fd가 참조하는 현재 파일 시작지점이 buf인 내용 기록
- 현재 쓴 바이트수 반환, 에러시 -1 반환 후 errno를 적당한 값으로 변경
- O_APPEND 모드는 파일 오프셋이 항상 파일 끝에 위치하도록 함(멀티 프로세스 관점에서 보면 파일 오프셋을 원자적으로 갱신)
- 논블럭 쓰기 모드에서 블럭되면 -1반환, errno를 EAGAIN으로 설정
- write 명령 시스템콜은 물리적 영역에 바로 쓰는 것이 아닌 버퍼에 복사해 놓음, 이후 이 버퍼를 수집해서 정렬 후 디스크에 씀
- 동기식 입출력을 지원하기 위해 fsync()와 fdatasync(), sync() 시스템 콜 지원
- fsync()는 버퍼의 모든 변경점을 디스크에 씀(메타데이터, 즉 파일생성시간 등 포함)
- fdatasync()는 메터데이터를 제외한 데이터만 기록
- sync()는 인자/반환값이 없이 버퍼의 모든 내용을 기록하도록 요구, 범용성이 높음
- open() 호출 시 O_SYNC 플래그 사용하면 모든 파일 입출력 동기화(O_DSYNC, O_RSYNC도 있다, 역할은 찾아볼 것)
직접입출력
- open() 시 O_DIRECT 플래그를 사용하면, 캐시/버퍼링/입출력관리 값은 복잡한 계층을 우회하여 직접 입출력 관리, 효과가 미미하다.
파일 닫기
|
|
- fd에 연관된 파일과의 매핑해제, 프로세스에서 파일 떼어냄
- 파일을 닫더라도 버퍼의 내용을 디스크에 강제로 쓰지 않는다.
- 파일을 닫을 때 커널 내부에서 그 파일을 표현하는 자료구조 해제, 메모리에서 inode 복사본 제거
- close의 반환값을 검사하는 것이 좋다. EBADF(fd가 유효하지 않음) 및 EIO 가 중요
파일 탐색
|
|
- 파일의 특정위치로 이동하는 함수, origin 인자 : SEEK_CUR, SEEK_END, SEEK_SET
- 호출 성공 시 새로운 파일 오프셋을 반환하며 에러가 발생하면 -1을 반환, errno를 설정
- lseek(fd, 0, SEEK_CUR)을 이용하면 현재 오프셋을 알아낼 수 있다.
- 파일의 끝을 넘어 위치를 지정하는 것도 가능, 이의 경우 데이터를 읽으면 EOF 반환, 쓰기 요청시 새로운 공간 생성 후 0으로 채움
- 이렇게 0으로 채운 공간을 구멍이라고 하는데 이는 물리적 공간을 차지하지 않으며 이를 다루는 과정에서 물리적 입출력 작업이 필요하지 않다.
지정한 위치 읽고 쓰기
|
|
- 읽고 쓸 파일 오프셋을 지정하여 read(), write() 수행함, 그러하 하기 차이점 존재
- 호출 완료 후 파일포인터를 갱신하지 않음
- lseek사용 시 발생할 수 있는 경쟁 상태를 회피 가능(멀티 스레드에서 각 스레드가 동시에 offset을 업데이트 하려는 경우)
파일 잘라내기
|
|
- 파일을 len 크기로 잘라내는 시스템 콜
- 호출 성공 0 반환, 에러가 발생하면 -1을 반환, errno를 설정
- 파일의 크기보다 큰 값으로 잘라내기 가능, 확장된 바이트는 모두 0으로 채워 짐
다중입출력
- 여러 개의 파일 디스크립터를 동시에 블록하고 그중 하나라도 블록되지 않고 읽고 쓸 준비가 되면 알려주는 기능
- 논블록 입출력을 사용하면 프로세스가 계속 기다리면서 임의의 순서대로 입출력을 요청해야 함(비효율적임)
- 3가지 다중입출력 방식 제공 : select, poll, epoll
select()
|
|
- 동기화된 다중 입출력 메커니즘 제공, 파일 디스크립터가 입출력을 수행할 준비가 되거나 옵션으로 정해진 시간이 경과할 때 까지만 블럭
- argument
- n : 파일디스크립터 집합에서 가장 큰 파일 디스크립터 숫자
- readfds : 데이터 읽기가 가능한지 파악하기 위한 파일 디스크립터 집합
- writefds : 데이터 쓰기가 가능한지 파악하기 위한 파일 디스크립터 집합
- exceptfds : 예외 발생 또는 소켓에서 대역을 넘어서는 데이터가 존재하는지 파악하기 위한 파일 디스크립터 집합
- timeout : NULL이 아니면 timeout 시간 설정, 함수 반환시 남은 시간을 넣어서 반환 됨
- timeout을 제외한 나머지 fds집합을 NULL로 넘겨서 다양한 시스템에서 동작하는 쉬운 잠들기 구현 가능
- pselect() : 파일 디스크립터와 시그널을 기다리는 사이에 발생할 수 있는 경쟁상태 해결을 위해 sigmask인자 추가
poll()
|
|
- systemv에서 제공하는 다중입출력, poll의 단점을 보완(그러나 이식성의 이유로 select가 많이 사용)
- argument
- fds : 감시하고자 하는 단일 파일 디스크립터를 명시, events 필드는 감시할 이벤트 비트마스크, revents는 반환 이벤트
- nfds : 감시할 파일 디스크립터 갯수
- timeout : timeout 밀리 초단위, 음수 사용시 무한 대기
select VS poll
- poll이 파일 디스크립터 숫자가 큰경우 점 더 효율정
- select를 사용하면 파일 디스크립터 집합을 반환하는 시점에 재구성되므로 잇단 호출과정에서 매번 초기화 필요
- select가 상대적으로 이식성이 높다
커널 부분
가상파일 시스템
- 추상화된 파일 시스템에 대한 설명(책 참조)
페이지 캐시
- 디스크 파일 시스템에서는 캐시를 가지고 있음
페이지 쓰기 저장
- 커널은 버퍼를 통해 쓰기 작업을 지연(플러셔 스레드가 별도로 있음)