[시스템] 11. Multiplexed I/O, Memory Mapped I/O
1. 개요
어떤 Socket에서 read() 를 호출해서 네트워크로부터 데이터를 수신하려고 한다. 근데 아무도 데이터를 송신하지 않았다면 수신할 데이터가 없으므로 read() 시스템 콜이 리턴하지 않고 이를 호출한 프로세스를 Sleep 시킨다. 그러다가 데이터가 도착하면 read()가 리턴을 하고 프로세스가 깨어나게 된다. 이때 프로세스를 Sleep 시키지 않게 하기 위해서 IO Multiplexing을 이용한다.
IO Multiplexing: IO와 관련된 시스템 콜을 호출했을 때 바로 IO를 처리한 후에 리턴될 수 있는지를 확인한다. 즉 Block이 되지 않을 File Discriptor 들을 확인해서 선택적으로 처리할 수 있게 된다.
2. select(), pselect()
$\verb|int select(int n, *readfds, *writefds, *exceptfds, *timeout)|$
관심 있는 File Discriptors 들 중에서 IO를 할 준비가 된 File Descriptor들의 개수를 리턴하는 함수이다.
- readfds, writefds, exceptfds: 각각 읽기, 쓰기, 제외 여부를 체크할 File Discriptors 리스트
- n: File Discriptor들 중에서 가장 높은 값 + 1
- timeout: timeval 구조체를 사용하는데, 이 시간만큼 IO가 가능한 놈이 없다면 바로 리턴하도록 한다. (리눅스는 이 값을 자동으로 남은 시간만큼 수정한다.) 제한시간 안줄거면 NULL
에러 발생 시 -1을 리턴 (시그널 방해받으면 errno == EINTR), timeout 시간이 지나도 아무것도 가능한 것이 없으면 0을 리턴한다. 성공할 경우 IO를 할 준비가 된 File Descriptor들의 개수를 리턴한다.
$\verb|int pselect(int n, *readfds, *writefds, *exceptfds, *timeout, *sigmask)|$
select와 기능은 동일한데, timeout과 sigmask가 다르다.
- timeout: timespec 구조체를 사용하는데, 이 값은 pselect() 시스템 콜에 의해 수정되지 않는다. (재사용 가능)
- sigmask: 특정 시그널을 한시적으로 Block할 수 있다.
3. FD Macros
- $\verb|FD_CLR(fd, *set)|$ : Set에서 fd 제거
- $\verb|FD_ISSET(fd, *set)|$ : Set에 포함되어 있는지 확인
- $\verb|FD_SET(fd, *set)|$ : Set에 fd 추가
- $\verb|FD_ZERO(*set)|$ : Set 초기화
4. mmap
$\verb|void *mmap(* addr, len, prot, flags, fd, offset)|$
File을 메모리로 Mapping 하는 시스템 콜이다. 메모리를 이용하면 read, write 없이 포인터로 직접 I/O 작업이 가능해진다.
- File Descriptor fd로부터 offset 에서 시작하여 len bytes 만큼을 메모리에 Mapping 한다.
- addr: Mapping이 시작될 주소를 넘기는데, 일반적으로 0을 넣는다.
- prot: fd를 open할 때 권한과 같은 것으로 $\verb|PROT_READ, PROT_WRITE, PROT_EXEC|$를 조합해서 등록해야 한다.
- flags: $\verb|MAP_SHARED, MAP_PRIVATE|$ 중에서 하나만 명시되어야 한다.
- len, offset: 반드시 $\verb|page_size|$의 배수로 설정해야 한다.
- 리턴값: Mapping 된 주소값을 리턴
5. munmap
$\verb|int munmap(*addr, len)|$
addr부터 len만큼 Mapping된 메모리 공간을 해제한다. 성공 시 0, 실패 시 -1 리턴
mmap을 하면 File Descriptor를 Mapping 하면 파일의 Reference Count가 1 증가한다. 반대로 munmap을 하면 1 감소한다. Mapping을 한 후에 $\verb|close|$ 시스템 콜을 호출해도 메모리로 계속 접근이 가능하다.