poll, ppoll -
ファイルディスクリプタにおけるイベントを待つ
#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
#define _GNU_SOURCE /* feature_test_macros(7) 参照 */
#include <poll.h>
int ppoll(struct pollfd *fds, nfds_t nfds,
const struct timespec *timeout_ts, const sigset_t *sigmask);
poll() は
select(2)
と同様の仕事を行う、つまり、ファイルディスクリプタ集合のいずれか一つが
I/O
を実行可能な状態になるのを待つ。
監視するファイルディスクリプタ集合は、
fds
引き数で指定する。
fds
は、以下の型の構造体の配列である。
struct pollfd {
int fd; /* file descriptor */
short events; /* requested events */
short revents; /* returned events */
};
nfds には、
fds
配列の要素数を指定する。
fd
フィールドには、オープンされたファイルのファイルディスクリプタが入る。
このフィールドが負の場合、対応する
events
フィールドは無視され、
revents には 0
が返される。(この機能により、一つの
poll() の呼び出しで
簡単にあるファイルディスクリプタを無視することができる。
単に
fd
フィールドの符号を反転するだけでよい。)
構造体の
events
要素は入力パラメータで、
ファイルディスクリプタ
fd に関して、
アプリケーションが興味を持っているイベントのビットマスクを指定する。
このフィールドに 0
が指定された場合は、
fd
の全てのイベントが無視され、
revents には 0
が返される。
revents
要素は出力パラメータで、実際に起こったイベントがカーネルにより設定される。
revents
で返されるビット列には、
events
で指定したもののどれか、もしくは
POLLERR,
POLLHUP,
POLLNVAL
のうちの一つが含まれる
(
POLLERR,
POLLHUP,
POLLNVAL の
3つのビットは
events
に指定しても意味がなく、対応した状態が真の場合に
revents に設定される)。
どのファイルディスクリプタにも要求したイベントが発生しておらず、
エラーも起こらない場合、
poll()
はイベントのうちいずれか一つが発生するまで停止
(block) する。
timeout 引き数は、
poll()
が停止する最小時間をミリ秒で指定する
(この停止時間はシステムクロックの粒度に切り上げられ、カーネルの
スケジューリング遅延により少しだけ長くなる可能性がある)。
timeout
に負の値を指定した場合、タイムアウト時間が無限大を意味する。
timeout を 0
に指定した場合、I/O
可能なファイルディスクリプタが
ない場合であっても、
poll() はすぐに返る。
events に指定したり、
revents
で返されるビットは
<poll.h>
で定義されている:
- POLLIN
- 読み出し可能なデータがある。
- POLLPRI
- 読み出し可能な緊急データ
(urgent data) がある
(例えば、TCP
ソケットの帯域外
(out-of-band data)
データを受信した場合や、
パケットモードの擬似端末のマスタがスレーブ側の変化を見つけたとき)。
- POLLOUT
- 書き込みが停止
(block)
しない状態である。
- POLLRDHUP (Linux 2.6.17 以降)
- ストリームソケットの他端が、コネクションを
close したか、
コネクションの書き込み側を
shutdown した。
この定義を有効にするには、
(「どの」ヘッダファイルをインクルードするよりも前に)
_GNU_SOURCE
機能検査マクロを定義しなければならない。
- POLLERR
- エラー状態
(出力の場合のみ)。
- POLLHUP
- ハングアップした
(出力の場合のみ)。
- POLLNVAL
- 不正な要求: fd
がオープンされていない
(出力の場合のみ)。
_XOPEN_SOURCE
を定義してコンパイルした場合には、以下の定義も行われる。
ただし、上記のリストにあるビット以上の情報が得られる訳ではない。
- POLLRDNORM
- POLLIN と同じ。
- POLLRDBAND
- 優先帯域データ
(priority band data)
が読み出し可能である
(普通は Linux
では使用されない)。
- POLLWRNORM
- POLLOUT と同じ。
- POLLWRBAND
- 優先帯域データ
(priority data)
が書き込み可能である。
Linux では
POLLMSG
も定義されているが、使用されていない。
ppoll()¶
poll() と
ppoll() の関係は
select(2) と
pselect(2)
の関係と同じようなものである:
pselect(2) と同様に、
ppoll()
を使うと、アプリケーションはファイルディスクリプタの状態変化
もしくはシグナルの捕捉を安全に待つことができる。
timeout
引き数の精度の違いを除くと、以下の
ppoll() の呼び出しは、
ready = ppoll(&fds, nfds, timeout_ts, &sigmask);
次の呼び出しを
atomic
に実行するのと等価である。
sigset_t origmask;
int timeout;
timeout = (timeout_ts == NULL) ? -1 :
(timeout_ts.tv_sec * 1000 + timeout_ts.tv_nsec / 1000000);
sigprocmask(SIG_SETMASK, &sigmask, &origmask);
ready = poll(&fds, nfds, timeout);
sigprocmask(SIG_SETMASK, &origmask, NULL);
なぜ
ppoll()
が必要なのかについての説明は
pselect(2)
の説明を参照のこと。
sigmask 引き数に NULL
が指定された場合、シグナルマスクの操作は行われない
(したがって、
ppoll() の
poll() との違いは
timeout
引き数の精度だけとなる)。
timeout 引き数は
ppoll()
が停止する時間の上限を指定するものである。
この引き数には以下の型の構造体へのポインタを指定する。
struct timespec {
long tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
timeout_ts に NULL
が指定された場合、
ppoll
は無限に停止することがあり得る。
返り値¶
成功した場合は正の数を返す。この数は
0 以外の
revents
要素を持つ構造体の数である
(別の言い方をすると、これらのディスクリプタ
にはイベントかエラー報告がある)。
値 0
は、タイムアウトとなり、どのファイルディスクリプタでもイベントが
発生しなかったことを示す。エラーの場合は
-1 が返され、
errno
が適切に設定される。
エラー¶
- EFAULT
- 引き数として指定した配列が、呼び出したプロセスのアドレス空間に
含まれていない。
- EINTR
- 要求されたイベントのどれかが起こる前にシグナルが発生した。
signal(7) 参照。
- EINVAL
- nfds の値が RLIMIT_NOFILE
を超えた。
- ENOMEM
- ファイルディスクリプタ・テーブルを確保するためのメモリがない。
バージョン¶
poll() システムコールは
Linux 2.1.23 で導入された。
このシステムコールが存在しない古いカーネルでは、
glibc (や古い Linux libc) は
select(2)
を使用して
poll()
ラッパー関数のエミュレーションを行う。
ppoll() システムコールは
カーネル 2.6.16 で Linux
に追加された。
ppoll()
ライブラリコールは glibc
2.4 に追加された。
poll() は POSIX.1-2001
に準拠している。
ppoll() は Linux 固有である。
いくつかの実装では、値
-1
を持った非標準の定数
INFTIM
が定義されており、
poll() の
timeout
の指定に使用できる。
この定数は glibc
では定義されていない。
Linux での注意¶
Linux の
ppoll()
システムコールは
timeout_ts
引き数を変更する。
しかし、glibc
のラッパー関数は、システムコールに渡す
timeout 引き数
としてローカル変数を使うことでこの動作を隠蔽している。
このため、glibc の
ppoll()
関数では
timeout_ts
引き数は変更されない。
select(2)
の「バグ」の節に書かれている、誤った準備完了通知
(spurious readiness notifications)
についての議論を参照のこと。
関連項目¶
select(2),
select_tut(2),
time(7)
この文書について¶
この man ページは Linux
man-pages
プロジェクトのリリース
3.41 の一部
である。プロジェクトの説明とバグ報告に関する情報は
http://www.kernel.org/doc/man-pages/
に書かれている。