#include <poll.h> int poll(struct pollfd *fds, nfds_t nfds, int timeout); #define _GNU_SOURCE /* feature_test_macros(7) 参照 */ #include <signal.h> #include <poll.h> int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *tmo_p, const sigset_t *sigmask);
監視するファイルディスクリプター集合は、 fds 引数で指定する。 fds は、以下の型の構造体の配列である。
struct pollfd {
int fd; /* file descriptor */
short events; /* requested events */
short revents; /* returned events */
};
nfds には、 fds 配列の要素数を指定する。
fd フィールドには、オープンされたファイルのファイルディスクリプターが入る。 このフィールドが負の場合、対応する events フィールドは無視され、 revents には 0 が返される。(この機能により、一つの poll() の呼び出しで簡単にあるファイルディスクリプターを無視することができる。 単に fd フィールドの符号を反転するだけでよい。 ただし、この方法はファイルディスクリプター 0 を無視するのには使用できない点に注意すること。)
構造体の events 要素は入力パラメーターで、 ファイルディスクリプター fd に関して、 アプリケーションが興味を持っているイベントのビットマスクを指定する。 このフィールドには 0 を指定することもでき、 その場合 revents で返されるイベントは POLLHUP, POLLERR, POLLNVAL だけである (下記参照)。
revents 要素は出力パラメーターで、実際に起こったイベントがカーネルにより設定される。 revents で返されるビット列には、 events で指定したもののどれか、もしくは POLLERR, POLLHUP, POLLNVAL のうちの一つが含まれる (POLLERR, POLLHUP, POLLNVAL の 3つのビットは events に指定しても意味がなく、対応した状態が真の場合に revents に設定される)。
どのファイルディスクリプターにも要求したイベントが発生しておらず、 エラーも起こらない場合、 poll() はイベントのうちいずれか一つが発生するまで停止 (block) する。
timeout 引数は、 ファイルディスクリプターが利用可能になるまで poll() が停止する時間をミリ秒で指定する。 poll() の呼び出しは以下のいずれかになるまで停止する。
timeout 時間はシステムクロックの粒度に切り上げられ、 カーネルのスケジューリング遅延により少しだけ長くなる可能性がある点に注意すること。 timeout に負の値を指定した場合、タイムアウト時間が無限大を意味する。 timeout を 0 に指定した場合、I/O 可能なファイルディスクリプターがない場合であっても、 poll() はすぐに返る。
events に指定したり、 revents で返されるビットは <poll.h> で定義されている:
_XOPEN_SOURCE を定義してコンパイルした場合には、以下の定義も行われる。 ただし、上記のリストにあるビット以上の情報が得られる訳ではない。
Linux では POLLMSG も定義されているが、使用されていない。
timeout 引数の精度の違いを除くと、以下の ppoll() の呼び出しは、
ready = ppoll(&fds, nfds, tmo_p, &sigmask);
次の呼び出しを atomic に実行するのとほぼ等価である。
sigset_t origmask; int timeout;
timeout = (tmo_p == NULL) ? -1 :
(tmo_p->tv_sec * 1000 + tmo_p->tv_nsec / 1000000);
pthread_sigmask(SIG_SETMASK, &sigmask, &origmask);
ready = poll(&fds, nfds, timeout);
pthread_sigmask(SIG_SETMASK, &origmask, NULL);
The above code segment is described as nearly equivalent because whereas a negative timeout value for poll() is interpreted as an infinite timeout, a negative value expressed in *tmo_p results in an error from ppoll().
なぜ ppoll() が必要なのかについての説明は pselect(2) の説明を参照のこと。
sigmask 引数に NULL が指定された場合、シグナルマスクの操作は行われない (したがって、 ppoll() の poll() との違いは timeout 引数の精度だけとなる)。
tmo_p 引数は ppoll() が停止する時間の上限を指定するものである。 この引数には以下の型の構造体へのポインターを指定する。
struct timespec {
long tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
tmo_p に NULL が指定された場合、 ppoll は無限に停止することがあり得る。
On error, -1 is returned, and errno is set to indicate the cause of the error.
ppoll() システムコールは カーネル 2.6.16 で Linux に追加された。 ppoll() ライブラリコールは glibc 2.4 に追加された。
On some other UNIX systems, poll() can fail with the error EAGAIN if the system fails to allocate kernel-internal resources, rather than ENOMEM as Linux does. POSIX permits this behavior. Portable programs may wish to check for EAGAIN and loop, just as with EINTR.
いくつかの実装では、値 -1 を持った非標準の定数 INFTIM が定義されており、 poll() の timeout の指定に使用できる。 この定数は glibc では定義されていない。
poll() で監視中のファイルディスクリプターが別のスレッドによってクローズされた場合に何が起こるかの議論については、 select(2) を参照してほしい。
The raw ppoll() system call has a fifth argument, size_t sigsetsize, which specifies the size in bytes of the sigmask argument. The glibc ppoll() wrapper function specifies this argument as a fixed value (equal to sizeof(kernel_sigset_t)). See sigprocmask(2) for a discussion on the differences between the kernel and the libc notion of the sigset.
Suppose we run the program in one terminal, asking it to open a FIFO:
$ mkfifo myfifo $ ./poll_input myfifo
In a second terminal window, we then open the FIFO for writing, write some data to it, and close the FIFO:
$ echo aaaaabbbbbccccc > myfifo
In the terminal where we are running the program, we would then see:
Opened "myfifo" on fd 3
About to poll()
Ready: 1
fd=3; events: POLLIN POLLHUP
read 10 bytes: aaaaabbbbb
About to poll()
Ready: 1
fd=3; events: POLLIN POLLHUP
read 6 bytes: ccccc
About to poll()
Ready: 1
fd=3; events: POLLHUP
closing fd 3
All file descriptors closed; bye
In the above output, we see that poll() returned three times:
Licensed under GNU General Public License v2 or later.
*/
#include <poll.h>
#include <fcntl.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
} while (0)
int
main(int argc, char *argv[])
{
int nfds, num_open_fds;
struct pollfd *pfds;
if (argc < 2) {
fprintf(stderr, "Usage: %s file...\n", argv[0]);
exit(EXIT_FAILURE);
}
num_open_fds = nfds = argc - 1;
pfds = calloc(nfds, sizeof(struct pollfd));
if (pfds == NULL)
errExit("malloc");
/* Open each file on command line, and add it 'pfds' array */
for (int j = 0; j < nfds; j++) {
pfds[j].fd = open(argv[j + 1], O_RDONLY);
if (pfds[j].fd == -1)
errExit("open");
printf("Opened \"%s\" on fd %d\n", argv[j + 1], pfds[j].fd);
pfds[j].events = POLLIN;
}
/* Keep calling poll() as long as at least one file descriptor is
open */
while (num_open_fds > 0) {
int ready;
printf("About to poll()\n");
ready = poll(pfds, nfds, -1);
if (ready == -1)
errExit("poll");
printf("Ready: %d\n", ready);
/* Deal with array returned by poll() */
for (int j = 0; j < nfds; j++) {
char buf[10];
if (pfds[j].revents != 0) {
printf(" fd=%d; events: %s%s%s\n", pfds[j].fd,
(pfds[j].revents & POLLIN) ? "POLLIN " : "",
(pfds[j].revents & POLLHUP) ? "POLLHUP " : "",
(pfds[j].revents & POLLERR) ? "POLLERR " : "");
if (pfds[j].revents & POLLIN) {
ssize_t s = read(pfds[j].fd, buf, sizeof(buf));
if (s == -1)
errExit("read");
printf(" read %zd bytes: %.*s\n",
s, (int) s, buf);
} else { /* POLLERR | POLLHUP */
printf(" closing fd %d\n", pfds[j].fd);
if (close(pfds[j].fd) == -1)
errExit("close");
num_open_fds--;
}
}
}
}
printf("All file descriptors closed; bye\n");
exit(EXIT_SUCCESS);
}