ppoll(2) ファイルディスクリプタにおけるイベントを待つ

Other Alias

poll

書式

#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 を指定することもでき、 その場合 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> で定義されている:

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 では定義されていない。

poll() で監視中のファイルディスクリプタが別のスレッドによってクローズされた場合に何が起こるかの議論については、 select(2) を参照してほしい。

Linux での注意

Linux の ppoll() システムコールは timeout_ts 引き数を変更する。 しかし、glibc のラッパー関数は、システムコールに渡す timeout 引き数 としてローカル変数を使うことでこの動作を隠蔽している。 このため、glibc の ppoll() 関数では timeout_ts 引き数は変更されない。

バグ

select(2) の「バグ」の節に書かれている、誤った準備完了通知 (spurious readiness notifications) についての議論を参照のこと。

この文書について

この man ページは Linux man-pages プロジェクトのリリース 3.65 の一部 である。プロジェクトの説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。