27. 다중 입출력 - poll()
poll()
시스템콜은 유닉스 운영체제의 최초 상용화 버전 중 하나인 'Unix System V
'에서 제공하는 다중 입출력 방식이었습니다. 리눅스에서 제공하고 있던 select()
시스템콜보다 더 좋았던 까닭에 리눅스에서도 poll()
시스템콜을 도입하였습니다. select() 시스템콜의 단점을 보완한 poll() 시스템콜이지만, 기존에 select()로 다중 입출력을 구현했던 개발자의 습관과 타 시스템으로의 이식성을 이유로 덜 사용된다고 합니다.
#include <poll.h>
int poll(struct pollfd* fds, nfds_t nfds, int timeout);
struct pollfd {
int fd; // 파일 디스크립터
short events; // 감시할 이벤트
short revents; // 발생한 이벤트
}
struct pollfd\* fds
: 감시하고자 하는 파일 디스크립터와 이벤트를 설정한 후 넘겨줍니다.
nfds_t nfds
: 그럼 첫 번째 매개변수로 설정한 구조체 1개만 넘겨줄 수 있느냐? 그렇지 않습니다. poll() 시스템콜은 단일 pollfd 구조체 배열을 nfds 개수만큼 사용합니다. 즉 몇 개의 구조체 배열을 넘겼는지 알려줍니다.
int timeout
: 해당 시간만큼 poll() 시스템콜은 작동합니다.
select()
시스템콜은 '읽기', '쓰기', '예외' 3가지를 독립적으로 설정한 후, 매개변수로 넘겨줘야했습니다. 그에 반면, poll() 시스템콜은 구조체 배열을 사용함으로써 설계상으로도 탐색 시간상으로도 훨씬 더 좋아졌다는걸 알 수 있습니다. pollfd 구조체 멤버를 보면 감시할 이벤트를 설정할 수 있는 events 필드가 있습니다. 이 필드를 설정한 후 poll() 시스템콜을 작동시키면 등록한 이벤트 중 발생한 이벤트가 revents 필드에 설정됩니다. revents 필드는 등록한 이벤트 중 발생된 이벤트 정보를 커널이 설정해주므로 사용자는 해당 필드를 통해 확인할 수 있습니다. 그럼 events 필드에 등록할 수 있는 이벤트는 어떤 것들이 있을지 살펴보겠습니다.
- POLLIN - 읽을 데이터가 존재한다. 즉, 읽기가 블록(blokc)되지 않는다.
- POLLRDNORM - 일반 데이터를 읽을 수 있다.
- POLLRDBAND - 우선권이 있는 데이터를 읽을 수 있다.
- POLLPRI - 시급히 읽을 데이터가 존재한다.
- POLLOUT - 쓰기가 블록(block)되지 않는다.
- POLLWRNORM - 일반 데이터 쓰기가 블록(block)되지 않는다.
- POLLWRBAND - 우선권이 있는 데이터 쓰기가 블록(block)되지 않는다.
- POLLMSG - SIGPOLL 메시지가 사용 가능하다.
그리고 revents 필드에는 다음 이벤트가 설정될 수 있습니다.
- POLLER - 주어진 파일 디스크립터에 에러가 있다.
- POLLHUP - 주어진 파일 디스크립터에서 이벤트가 지체되고 있다.
- POLLNVAL - 주어진 파일 디스크립터가 유효하지 않다.
#include <stdio.h>
#include <unistd.h>
#include <poll.h>
#define TIMEOUT 5
int main() {
struct pollfd fds[2];
int ret;
// 표준 입력에 대한 이벤트를 감시하기 위한 준비를 합니다.
fds[0].fd = STDIN_FILENO;
fds[0].events = POLLIN;
// 표준 출력에 쓰기가 가능한지 감시하기 위한 준비를 합니다.
fds[1].fd = STDOUT_FILENO;
fds[1].events = POLLOUT;
// 위에서 pollfd 구조체 설정을 모두 마쳤으니 poll() 시스템콜을 작동시킵니다.
ret = poll(fds, 2, TIMEOUT * 1000);
if (ret == -1) {
perror("poll");
return 1;
}
if (!ret) {
printf("%d seconds elapsed.\n", TIMEOUT);
return 0;
}
if (fds[0].revents & POLLIN) printf("stdin is readable\n");
if (fds[1].revents & POLLOUT) printf("stdout is writeable\n");
return 0;
}
'임베디드 > [ Linux Kernel ]' 카테고리의 다른 글
[ Linux Kernel ] 29. 버퍼 입출력 - 표준 입출력 라이브러리 (0) | 2020.11.12 |
---|---|
[ Linux Kernel ] 28. 가상 파일 시스템 (0) | 2020.11.12 |
[ Linux Kernel ] 26. 다중 입출력 - select() (0) | 2020.11.10 |
[ Linux Kernel ] 25. 파일 입출력 - open(), read(), write() (1) | 2020.11.10 |
[ Linux Kernel ] 24. 커널 프로그래밍에서 쉘 명령을 실행하는 방법 (0) | 2020.11.09 |