関数仕様
書式
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
/* POSIX.1.2001 に従う場合 */ #include <sys/select.h> /* 以前の規格に従う場合 */ #include <sys/time.h> #include <sys/types.h> #include <unistd.h> int select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); void FD_ZERO (fd_set *fds); void FD_SET (int fd, fd_set *fds); void FD_CLR (int fd, fd_set *fds); int FD_ISSET (int fd, fd_set *fds); |
引数
| nfds | 3つの集合(readfds,writefds,exceptfds)に含まれるファイル記述子の最大値に 1 を足したもの |
| readfds | 読み出しが可能かどうかを監視するファイルディスクリプタの集合へのポインタ or NULL |
| writefds | 書込みが可能かどうかを監視するファイルディスクリプタの集合へのポインタ or NULL |
| exceptfds | 例外が発生したかどうかを監視するファイルディスクリプタの集合へのポインタ or NULL |
| timeout | タイムアウトになる時間を指定する timeval 構造体へのポインタ (NULL の場合は無期限) |
| fds | ファイルディスクリプタの集合へのポインタ |
| fd | ファイルディスクリプタ |
戻り値
| 正の値 | 変化があったファイルディスクリプタの総数(readfds,writefds,exceptfds) |
| 0 | タイムアウト |
| -1 | エラーが発生(errno にエラー番号がセットされています) |
代表的なエラー(errno)
- EBADF
何れかの集合(fds)に無効なファイルディスクリプタが設定されている
例えば、既にクローズされているディスクリプタ、など - EINTR
引数の timeout が示す時間経過前、または記述子に変化が発生する前に
シグナルに割り込まれた - EINVAL
引数の nfds が負の値、またはリソース上限 RLIMIT_NOFILE より大きい - ENOMEM
カーネルの内部テーブルにメモリを割り当てることができなかった
機能
- 複数のファイルディスクリプタを同時に監視します
read や accept などのシステムコールを呼び出すと、データが到着したり接続要求が発生するまでシステムコールから戻ってきません。変化を同時に待ち受ける仕組みが select システムコールです - 引数 timeout にタイムアウトを設定できます
timeout が示す時間内にファイルディスクリプタに変化が無かった場合、時間切れとして select からリターンします
集合を扱うためのマクロ
- FD_ZERO
集合(fds)を初期化する(セットされている全てのファイルディスクリプタを集合から削除) - FD_SET
集合(fds)に、ファイルディスクリプタ(fd)をセットする - FD_CLR
集合(fds)にセットされているファイルディスクリプタ(fd)を、集合から削除する - FD_ISSET
集合(fds)にファイルディスクリプタがセットされているかを調べる
※このマクロは select() が終了した後に使うと便利
注意すること
注意ポイント
select() から復帰した後の timeout の値は信用してはいけない
Linux では、select がタイムアウト以外で戻った際、timeout に残りの時間を反映するようになっています。
しかし、他のほとんどの OS では、このようになっていません (POSIX.1-2001は両方の動作を認めています)。
そのため、timeout を参照している Linux のコードを他の OS へ移植する場合に問題が起きます。
select() から復帰した後、timeout は未定義であると考えておく方が無難でしょう。
サンプルプログラム
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
#include <sys/time.h> #include <sys/types.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #define MYSQL_SOCKET "/tmp/mysql.sock" #define CLAMD_SOCKET "/tmp/clamd.sock" #define max(a,b) ((a >= b) ? a : b) int main(void) { int mysql_fd = -1; int clamd_fd = -1; int maxfd = -1; fd_set fds; struct timeval tv; int ret; mysql_fd = open(MYSQL_SOCKET, O_RDONLY); if (mysql_fd < 0) { goto error; } clamd_fd = open(CLAMD_SOCKET, O_RDONLY); if (clamd_fd < 0) { goto error; } while (1) { FD_ZERO(&fds); FD_SET(mysql_fd, &fds); maxfd = max(maxfd, mysql_fd); FD_SET(clamd_fd, &fds); maxfd = max(maxfd, clamd_fd); tv.tv_sec = 5; tv.tv_usec = 0; ret = select(maxfd + 1, &fds, NULL, NULL, &tv); if (ret < 0) { /* error */ if (errno == EINTR) { continue; } else { goto error; } } else if (ret == 0) { /* timeout */ continue; } else { if (FD_ISSET(mysql_fd, &fds)) { /* 処理を書く */ } if (FD_ISSET(clamd_fd, &fds)) { /* 処理を書く */ } } } close(mysql_fd); close(clamd_fd); _exit(0); error: if (mysql_fd >= 0) close(mysql_fd); if (clamd_fd >= 0) close(clamd_fd); _exit(-1); } |