SELECT(2)

名前
select, FD_CLR, FD_ISSET, FD_SET, FD_ZERO - 多重化された I/O の同期をとる

書式
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

FD_CLR(int fd, fd_set *set);
FD_ISSET(int fd, fd_set *set);
FD_SET(int fd, fd_set *set);
FD_ZERO(fd_set *set);

説明
select はいくつかのファイル・ディスクリプター(file descriptor)の状態が 変化するのを待つ。

三つの独立したディスクリプターの集合を監視する。 readfds にリストされたものは読み込みが可能かどうかを監視する。 writefds にリストされたものはすぐにそれに書き込みが可能かどうかを監視する。 exceptfds にあるものは例外の監視を行なう。終了する時に、実際にどの ディスクリプターの状態が変化したか示すために集合が変更される。

集合を操作するために四つのマクロ(macro)が提供される。 FD_ZERO は集合を消去(clear)する。 FD_SET と FD_CLR は集合にディスクリプターを加えたり取り除いたりする。 FD_ISSET は集合にディスクリプターがあるかどうか調べる; これは select が終了した後で便利である。

n は三つの集合にあるディスクリプターの中の最大値に 1 を足したもの。

timeout は select が返ってくるまでの経過時間の上限。これはゼロにすることができ、 その場合は select はすぐに返ってくる。もし timeout に NULL (時間切れ(timeout)無し) が指定されると、 select は無期限に停止(block)する。

返り値
成功した場合、 select はディスクリプター集合に含まれているディスクリターの数を返す、 いずれの興味深い事象の前に時間切れになった場合はゼロになることもある。 エラーならば -1 を返し、 errno に適切な値が設定される; 集合と timeout は未定義となる、エラーの後はそれらの内容は信頼できない。

エラー

EBADF
    集合のどれかに無効なファイルディスクリプターが与えられた。

EINTR
    禁止(block)されていないシグナル(signal)を受けた。

EINVAL
    n が負である。

ENOMEM
    select が内部テーブルにメモリーを割当てることができなかった。

注意
select を呼び出すコードには三つの集合全てに空が設定し、 n にゼロ、 timeout に NULL でない値を設定し、移植性(portable)のある方法で秒単位以下の スリープ(sleep)を実現していたものがある。

Linux では、 timeout は停止(sleep)していない時間の量を反映するように修正された。 他のほとんどのインプリメンテーションではこのようになっていない。 これは timeout を読み取る Linux のコードを他のオペレーティング・システムへ移植する 場合と ループの中で timval 構造体を初期化せずに再使用して複数回の select を行なっているコードを Linux へ移植する場合の両方で問題を起こす。 select が返ってきた後は timeout は未定義であると考えるべきである。

例
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int
main(void)
{
    fd_set rfds;
    struct timeval tv;
    int retval;
    /* Watch stdin (fd 0) to see when it has input. */
    FD_ZERO(&rfds);
    FD_SET(0, &rfds);
    /* Wait up to five seconds. */
    tv.tv_sec = 5;
    tv.tv_usec = 0;
    retval = select(1, &rfds, NULL, NULL, &tv);
    /* Don't rely on the value of tv now! */
    if (retval)
        printf("Data is available now.\n");
        /* FD_ISSET(0, &rfds) will be true. */
    else
        printf("No data within five seconds.\n");
    exit(0);
}

準拠
4.4BSD ( select 関数は 4.2BSD で最初に現われた)。 一般に BSD のソケット層をサポートした BSD 以外のシステム(System V の変種を含む)への移植、またはそれからの移植 ができる。一方で System V の変種は典型的に戻る前に timeout 変数を設定す るのに対して、BSDの変種では設定しないことに注意すること。

関連項目
accept(2), connect(2), read(2), recv(2), send(2), write(2)