Manpages

名 前

select, pselect, FD_CLR, FD_ISSET, FD_SET, FD_ZERO − 同 期 I/O の 多 重 化

書 式

/* 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_CLR(int fd, fd_set *set);
int FD_ISSET(int
fd, fd_set *set);
void FD_SET(int
fd, fd_set *set);
void FD_ZERO(fd_set *
set);

#include <sys/select.h>

int pselect(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *
exceptfds, const struct timespec *timeout,
const sigset_t *
sigmask);

glibc 向 け の 機 能 検 査 マ ク ロ の 要 件 (feature_test_macros(7) 参 照 ):

pselect(): _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600

説 明

select() や pselect() を 使 う と 、 プ ロ グ ラ ム で 複 数 の フ ァ イ ル デ ィ ス ク リ プ タ ー を 監 視 し 、 一 つ 以 上 の フ ァ イ ル デ ィ ス ク リ プ タ ー が あ る 種 の I/O 操 作 の 「 ready (準 備 が で き た )」 状 態 (例 え ば 、 読 み 込 み 可 能 に な っ た 状 態 ) に な る ま で 待 つ こ と が で き る 。 フ ァ イ ル デ ィ ス ク リ プ タ ー が ready (準 備 が で き た ) と は 、 (read(2) な ど の ) 対 応 す る I/O 操 作 が 停 止 (block) な し に 実 行 し た り 、 十 分 小 さ な write(2) を 実 行 し た り で き る 状 態 に あ る こ と を 意 味 す る 。

select() と pselect() の 動 作 は 同 じ で あ る が 、 以 下 の 3 点 が 異 な る :

(i)

select() で は 、 タ イ ム ア ウ ト 時 間 の 指 定 に 構 造 体 struct timeval (秒 ・ マ イ ク ロ 秒 単 位 ) を 用 い る 。 一 方 、 pselect() 関 数 で は 、 構 造 体 struct timespec (秒 ・ ナ ノ 秒 単 位 ) を 用 い る 。

(ii)

select() は 残 り 時 間 を 示 す timeout 引 き 数 を 更 新 す る こ と が あ る 。 pselect() は こ の 引 き 数 を 変 更 し な い 。

(iii)

select() は sigmask 引 き 数 を 持 た な い 。 そ の 動 作 は sigmask に NULL を 指 定 し た 場 合 の pselect() と 同 じ で あ る 。

3 つ の 独 立 し た フ ァ イ ル デ ィ ス ク リ プ タ ー 集 合 の 監 視 を 行 う 。 readfds に 入 れ ら れ た デ ィ ス ク リ プ タ ー に つ い て は 、 読 み 込 み が 可 能 か ど う か を 監 視 す る (よ り 正 確 に い う と 、 停 止 (block) な し で 読 む こ と が で き る か を 調 べ る 。 フ ァ イ ル の 終 端 (end−of−file) の 場 合 も 、 フ ァ イ ル デ ィ ス ク リ プ タ ー は 読 み 込 み 可 能 と し て 扱 わ れ る )。 writefds に 入 れ ら れ た デ ィ ス ク リ プ タ ー に つ い て は 、 書 き 込 み 用 に 利 用 可 能 な 領 域 が あ る か を 監 視 す る (た だ し 、 大 き な 書 き 込 み の 場 合 に は 停 止 す る 可 能 性 は あ る )。 exceptfds に あ る も の に つ い て は 、 例 外 の 監 視 を 行 な う 。 シ ス テ ム コ ー ル 終 了 時 に 、 ど の フ ァ イ ル デ ィ ス ク リ プ タ ー の 状 態 が 実 際 に 変 化 し た か 示 す た め に 、 集 合 の 内 容 が 変 更 さ れ る 。 あ る 種 別 の イ ベ ン ト を 監 視 し た い フ ァ イ ル デ ィ ス ク リ プ タ ー が 一 つ も な い 場 合 に は 、 対 応 す る フ ァ イ ル デ ィ ス ク リ プ タ ー 集 合 に NULL を 指 定 す る こ と が で き る 。 集 合 を 操 作 す る た め に 4 つ の マ ク ロ が 提 供 さ れ て い る 。 FD_ZERO() は 集 合 を 消 去 す る 。 FD_SET() と FD_CLR() は そ れ ぞ れ 指 定 し た フ ァ イ ル デ ィ ス ク リ プ タ ー の 集 合 へ の 追 加 、 削 除 を 行 う 。 FD_ISSET() は 集 合 に フ ァ イ ル デ ィ ス ク リ プ タ ー が あ る か ど う か 調 べ る ; こ の マ ク ロ は select() が 終 了 し た 後 に 使 う と 便 利 で あ る 。

nfds は 3 つ の 集 合 に 含 ま れ る フ ァ イ ル デ ィ ス ク リ プ タ ー の 最 大 値 に 1 を 足 し た も の で あ る 。

timeout 引 き 数 は 、 select() が フ ァ イ ル デ ィ ス ク リ プ タ ー が ready に な る の を 待 っ て 停 止 す る 時 間 を 指 定 す る 。 呼 び 出 し は 以 下 の い ず れ か に な る ま で 停 止 す る 。

* フ ァ イ ル デ ィ ス ク リ プ タ ー が 利 用 可 能 に な る 。

* シ ス テ ム コ ー ル が シ グ ナ ル ハ ン ド ラ ー に よ り 割 り 込 ま れ た 。

* タ イ ム ア ウ ト 時 間 が 満 了 し た 。 こ の

timeout 時 間 は シ ス テ ム ク ロ ッ ク の 粒 度 に 切 り 上 げ ら れ 、 カ ー ネ ル の ス ケ ジ ュ ー リ ン グ 遅 延 に よ り 少 し だ け 長 く な る 可 能 性 が あ る 点 に 注 意 す る こ と 。 timeval 構 造 体 の 両 方 の フ ィ ー ル ド が 0 の 場 合 、 select() は す ぐ に 復 帰 す る (こ の 機 能 は ポ ー リ ン グ (polling) を 行 う の に 便 利 で あ る )。 timeout に NULL (タ イ ム ア ウ ト な し ) が 指 定 さ れ る と 、 select() は 無 期 限 に 停 止 (block) す る 。

sigmask は 、 シ グ ナ ル マ ス ク (sigprocmask(2) を 参 照 ) へ の ポ イ ン タ ー で あ る 。 sigmask が NULL で な い 場 合 、 pselect() は sigmask が 指 し て い る シ グ ナ ル マ ス ク で 現 在 の シ グ ナ ル マ ス ク を 置 き 換 え て か ら 、 "select" 関 数 を 実 行 し 、 終 了 後 に シ グ ナ ル マ ス ク を 元 の シ グ ナ ル マ ス ク に 戻 す 。

timeout 引 き 数 の 精 度 の 違 い を 除 く と 、 以 下 の pselect() の 呼 び 出 し は 、

ready = pselect(nfds, &readfds, &writefds, &exceptfds,
timeout, &sigmask); 次 の コ ー ル を atomic に 実 行 す る の と 等 価 で あ る 。

sigset_t origmask;

pthread_sigmask(SIG_SETMASK, &sigmask, &origmask);
ready = select(nfds, &readfds, &writefds, &exceptfds, timeout);
pthread_sigmask(SIG_SETMASK, &origmask, NULL);

pselect() が 必 要 に な る 理 由 は 、 シ グ ナ ル や フ ァ イ ル デ ィ ス ク リ プ タ ー の 状 態 変 化 を 待 ち た い と き に は 、 競 合 状 態 を 避 け る た め に atomic な テ ス ト が 必 要 に な る か ら で あ る 。 (シ グ ナ ル ハ ン ド ラ ー が 大 域 フ ラ グ を 設 定 し て 戻 る 場 合 を 考 え て み よ う 。 こ の 大 域 フ ラ グ の テ ス ト に 続 け て select() を 呼 び 出 す と 、 シ グ ナ ル が テ ス ト の 直 後 か つ 呼 び 出 し の 直 前 に 届 い た 時 に は select() は 永 久 に ハ ン グ し て し ま う か も し れ な い 。 一 方 、 pselect() を 使 う と 、 ま ず シ グ ナ ル を 禁 止 (block) し て 、 入 っ て く る シ グ ナ ル を 操 作 し 、 望 み の sigmaskpselect() を 呼 び 出 す こ と で 、 前 記 の 競 合 を 避 け る こ と が で き る 。 ) タ イ ム ア ウ ト こ れ ら の 関 数 で 使 用 さ れ る 時 間 関 連 の 構 造 体 は 、 <sys/time.h>

struct timeval {
long tv_sec; /* 秒 */
long tv_usec; /* マ イ ク ロ 秒 */ }; や

struct timespec {
long tv_sec; /* 秒 */
long tv_nsec; /* ナ ノ 秒 */ }; の よ う に 定 義 さ れ て い る 。 (POSIX.1−2001 で の 定 義 に つ い て は 下 記 の 「 注 意 」 を 参 照 ) 秒 単 位 以 下 の 精 度 で ス リ ー プ を 実 現 す る 移 植 性 の 高 い 方 法 と し て 、 3 つ の 集 合 全 て を 空 、 nfds を 0 、 timeout を NULL で な い 値 に 設 定 し て select() を 呼 び 出 す と い う 方 法 を 使 っ て い る コ ー ド も あ る 。

Linux で は 、 select() は timeout を 変 更 し 、 残 り の 停 止 時 間 を 反 映 す る よ う に な っ て い る が 、 他 の ほ と ん ど の 実 装 で は こ の よ う に な っ て い な い (POSIX.1−2001 は ど ち ら の 動 作 も 認 め て い る )。 こ の た め 、 timeout を 参 照 し て い る Linux の コ ー ド を 他 の オ ペ レ ー テ ィ ン グ シ ス テ ム へ 移 植 す る 場 合 、 問 題 が 起 こ る 。 ま た 、 ル ー プ の 中 で timeval 構 造 体 を 初 期 化 せ ず に そ の ま ま 再 利 用 し て select() を 複 数 回 行 な っ て い る コ ー ド を Linux へ 移 植 す る 場 合 に も 、 問 題 が 起 こ る 。 select() か ら 復 帰 し た 後 は timeout は 未 定 義 で あ る と 考 え る べ き で あ る 。

返 り 値

成 功 し た 場 合 、 select() と pselect() は 更 新 さ れ た 3 つ の デ ィ ス ク リ プ タ ー 集 合 に 含 ま れ て い る フ ァ イ ル デ ィ ス ク リ プ タ ー の 数 (つ ま り 、 readfds, writefds, exceptfds 中 の 1 に な っ て い る ビ ッ ト の 総 数 ) を 返 す 。 何 も 起 こ ら ず に 時 間 切 れ に な っ た 場 合 、 デ ィ ス ク リ プ タ ー の 数 は 0 に な る こ と も あ る 。 エ ラ ー な ら ば −1 を 返 し 、 errno に エ ラ ー を 示 す 値 が 設 定 さ れ る ; フ ァ イ ル デ ィ ス ク リ プ タ ー 集 合 は 変 更 さ れ ず 、 timeout は 不 定 と な る 。

エ ラ ー

EBADF い ず れ か の 集 合 に 無 効 な フ ァ イ ル デ ィ ス ク リ プ タ ー が 指 定 さ れ た

(お そ

ら く は 、 す で に ク ロ ー ズ さ れ た フ ァ イ ル デ ィ ス ク リ プ タ ー か 、 エ ラ ー が 発 生 し た フ ァ イ ル デ ィ ス ク リ プ タ ー が 指 定 さ れ た )。

EINTR シ グ ナ ル を 受 信 し た 。

EINVAL

nfds が 負 、 ま た は リ ソ ー ス 上 限 RLIMIT_NOFILE (getrlimit(2) 参 照 ) よ り 大 き い 。

EINVAL

timeout に 入 っ て い る 値 が 不 正 で あ る 。

ENOMEM

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

バ ー ジ ョ ン

pselect() は カ ー ネ ル 2.6.16 で Linux に 追 加 さ れ た 。 そ れ 以 前 は 、 pselect() は glibc で エ ミ ュ レ ー ト さ れ て い た (「 バ グ 」 の 章 を 参 照 )。

準 拠

select() は POSIX.1−2001 と 4.4BSD (select() は 4.2BSD で 最 初 に 登 場 し た ) に 準 拠 す る 。 BSD ソ ケ ッ ト 層 の ク ロ ー ン を サ ポ ー ト し て い る 非 BSD シ ス テ ム (System V 系 も 含 む ) と の 間 で だ い た い 移 植 性 が あ る 。 し か し System V 系 で は た い が い timeout 変 数 を exit の 前 に セ ッ ト す る が 、 BSD 系 で は そ う で な い の で 注 意 す る こ と 。

pselect() は POSIX.1g と POSIX.1−2001 で 定 義 さ れ て い る 。

注 意

fd_set は 固 定 サ イ ズ の バ ッ フ ァ ー で あ る 。 負 や FD_SETSIZE 以 上 の 値 を 持 つ fd に 対 し て FD_CLR() や FD_SET() を 実 行 し た 場 合 、 ど の よ う な 動 作 を す る か は 定 義 さ れ て い な い 。 ま た 、 POSIX で は fd は 有 効 な フ ァ イ ル デ ィ ス ク リ プ タ ー で な け れ ば な ら な い と 規 定 さ れ て い る 。 型 宣 言 に 関 し て は 、 昔 な が ら の 状 況 で は timeval 構 造 体 の 2 つ の フ ィ ー ル ド は (上 記 の よ う に ) 両 方 と も long 型 で あ り 、 構 造 体 は <sys/time.h> で 定 義 さ れ て い る 。 POSIX.1−2001 の 下 で は 、 以 下 の よ う に な っ て い る 。

struct timeval {

time_t tv_sec; /* 秒 */

suseconds_t tv_usec; /* マ イ ク ロ 秒 */ }; こ の 構 造 体 は <sys/select.h> で 定 義 さ れ て お り 、 デ ー タ 型 time_tsuseconds_t<sys/types.h> で 定 義 さ れ て い る 。 プ ロ ト タ イ プ に 関 し て は 、 昔 な が ら の 状 況 で select() を 使 い た い 場 合 は 、 <time.h> を イ ン ク ル ー ド す れ ば よ い 。 POSIX.1−2001 の 環 境 で select() と pselect() を 使 い た い 場 合 は 、 <sys/select.h> を イ ン ク ル ー ド す れ ば よ い 。

glibc 2.0 で は <sys/select.h> が 提 供 す る pselect() の プ ロ ト タ イ プ が 間 違 っ て い る 。 glibc 2.1 か ら 2.2.1 で は _GNU_SOURCE が 定 義 さ れ て い る 場 合 に 、 pselect() が 提 供 さ れ る 。 glibc 2.2.2 以 降 で は 、 pselect() を 使 用 す る に は 、 「 書 式 」 に 記 載 さ れ た 要 件 を 満 た す 必 要 が あ る 。 マ ル チ ス レ ッ ド ア プ リ ケ ー シ ョ ン
select
() で 監 視 中 の フ ァ イ ル デ ィ ス ク リ プ タ ー が 別 の ス レ ッ ド で ク ロ ー ズ さ れ た 場 合 、 ど の よ う な 結 果 に な る か は 規 定 さ れ て い な い 。 い く つ か の UNIX シ ス テ ム で は 、 select() は 停 止 (block) せ ず 、 す ぐ 返 り 、 フ ァ イ ル デ ィ ス ク リ プ タ ー が ready だ と 報 告 さ れ る (select() が 返 っ て か ら I/O 操 作 が 実 行 さ れ る ま で の 間 に 、 別 の フ ァ イ ル デ ィ ス ク リ プ タ ー が 再 度 オ ー プ ン さ れ な い 限 り 、 そ れ 以 降 の I/O 操 作 は お そ ら く 失 敗 す る だ ろ う )。 Linux (や 他 の い く つ か の シ ス テ ム ) で は 、 別 の ス レ ッ ド で フ ァ イ ル デ ィ ス ク リ プ タ ー が ク ロ ー ズ さ れ て も select() に は 影 響 を 与 え な い 。 ま と め る と 、 こ の よ う な 場 合 に 特 定 の 動 作 に 依 存 し て い る ア プ リ ケ ー シ ョ ン は 「 バ グ っ て い る 」 と 考 え な け れ ば な ら な い 。

C ラ イ ブ ラ リ と カ ー ネ ル ABI の 違 い こ の ペ ー ジ で 説 明 し て い る pselect() の イ ン タ ー フ ェ ー ス は 、 glibc に 実 装 さ れ て い る も の で あ る 。 内 部 で 呼 び 出 さ れ る Linux の シ ス テ ム コ ー ル は pselect6() と い う 名 前 で あ る 。 こ の シ ス テ ム コ ー ル は glibc の ラ ッ パ ー 関 数 と は 少 し 違 っ た 動 作 を す る 。

Linux の pselect6() シ ス テ ム コ ー ル は timeout 引 き 数 を 変 更 す る 。 し か し 、 glibc の ラ ッ パ ー 関 数 は 、 シ ス テ ム コ ー ル に 渡 す timeout 引 き 数 と し て ロ ー カ ル 変 数 を 使 う こ と で こ の 動 作 を 隠 蔽 し て い る 。 こ の た め 、 glibc の pselect() 関 数 は timeout 引 き 数 を 変 更 し な い 。 こ れ が POSIX.1−2001 が 要 求 し て い る 動 作 で あ る 。

pselect6() シ ス テ ム コ ー ル の 最 後 の 引 き 数 は sigset_t * 型 の ポ イ ン タ ー で は な く 、 以 下 に 示 す 構 造 体 で あ る 。

struct {
const sigset_t *ss; /* シ グ ナ ル 集 合 へ の ポ イ ン タ ー */
size_t ss_len; /* ’ss’ が 指 す オ ブ ジ ェ ク ト の サ イ ズ
(バ イ ト 数 ) */ }; こ の よ う に す る こ と で 、 ほ と ん ど の ア ー キ テ ク チ ャ ー が サ ポ ー ト し て い る シ ス テ ム コ ー ル の 引 き 数 が 最 大 で 6 個 と い う 事 実 を 満 た し つ つ 、 pselect6() シ ス テ ム コ ー ル が シ グ ナ ル 集 合 へ の ポ イ ン タ ー と シ グ ナ ル 集 合 の サ イ ズ の 両 方 を 取 得 す る こ と が で き る の で あ る 。

バ グ

glibc 2.0 で は 、 sigmask 引 き 数 を 取 ら な い バ ー ジ ョ ン の pselect() が 提 供 さ れ て い た 。 バ ー ジ ョ ン 2.1 以 降 の glibc で は 、 pselect() は sigprocmask(2)select() を 使 っ て エ ミ ュ レ ー ト さ れ て い た 。 こ の 実 装 に は き わ ど い 競 合 条 件 に お い て 脆 弱 性 が 残 っ て い た 。 こ の 競 合 条 件 に お け る 問 題 を 防 止 す る た め に pselect() は 設 計 さ れ た の で あ る 。 最 近 の バ ー ジ ョ ン の glibc で は 、 カ ー ネ ル が サ ポ ー ト し て い る 場 合 に は 、 (競 合 が 起 こ ら な い ) pselect() シ ス テ ム コ ー ル が 使 用 さ れ る 。

pselect() が な い シ ス テ ム に お い て 、 シ グ ナ ル の 捕 捉 を 信 頼 性 が あ り (移 植 性 も 高 い ) 方 法 で 行 う に は 、 自 己 パ イ プ (self−pipe) と い う 技 を 使 う と よ い 。 こ の 方 法 で は 、 シ グ ナ ル ハ ン ド ラ ー は パ イ プ へ 1 バ イ ト の デ ー タ を 書 き 込 み 、 同 じ パ イ プ の も う 一 端 を メ イ ン プ ロ グ ラ ム の select() で 監 視 す る (一 杯 に な っ た パ イ プ へ の 書 き 込 み や 空 の パ イ プ か ら 読 み 出 し を 行 っ た 際 に 起 こ る で あ ろ う 停 止 (blocking) を 避 け る た め に は 、 パ イ プ へ の 読 み 書 き の 際 に は 非 停 止 (nonblocking) I/O を 使 用 す る と よ い )。

Linux で は 、 select() が ソ ケ ッ ト フ ァ イ ル デ ィ ス ク リ プ タ ー で "読 み 込 み の 準 備 が で き た " と 報 告 し た 場 合 で も 、 こ の 後 で read を 行 う と 停 止 (block) す る こ と が あ る 。 こ の よ う な 状 況 は 、 例 え ば 、 デ ー タ が 到 着 し た が 、 検 査 で チ ェ ッ ク サ ム 異 常 が 見 つ か り 廃 棄 さ れ た 時 な ど に 起 こ り え る 。 他 に も フ ァ イ ル デ ィ ス ク リ プ タ ー が 準 備 で き た と 間 違 っ て 報 告 さ れ る 状 況 が 起 こ る か も し れ な い 。 し た が っ て 、 停 止 す べ き で は な い ソ ケ ッ ト に 対 し て は O_NONBLOCK を 使 う と よ り 安 全 で あ ろ う 。

Linux で は 、 select() が シ グ ナ ル ハ ン ド ラ ー に よ り 割 り 込 ま れ た 場 合 (つ ま り EINTR エ ラ ー が 返 る 場 合 )、 timeout も 変 更 す る 。 こ れ は POSIX.1−2001 で は 認 め ら れ て い な い 挙 動 で あ る 。 Linux の pselect() シ ス テ ム コ ー ル も 同 じ 挙 動 を す る が 、 glibc の ラ ッ パ ー 関 数 が こ の 挙 動 を 隠 蔽 し て い る 。 具 体 的 に は 、 glibc の ラ ッ パ ー 関 数 の 内 部 で 、 timeout を ロ ー カ ル 変 数 に コ ピ ー し 、 こ の ロ ー カ ル 変 数 を シ ス テ ム コ ー ル に 渡 し て い る 。

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

int
main(void)
{
fd_set rfds;
struct timeval tv;
int retval;

/* stdin (fd 0) を 監 視 し 、 入 力 が あ っ た 場 合 に 表 示 す る 。 */
FD_ZERO(&rfds);
FD_SET(0, &rfds);

/* 5 秒 間 監 視 す る 。 */
tv.tv_sec = 5;
tv.tv_usec = 0;

retval = select(1, &rfds, NULL, NULL, &tv);
/* こ の 時 点 で の tv の 値 を 信 頼 し て は な ら な い 。 */

if (retval == −1)

perror("select()");

else if (retval)
printf("今 、 デ ー タ が 取 得 で き ま し た 。 \n");
/* FD_ISSET(0, &rfds) が true に な る 。 */
else
printf("5 秒 以 内 に デ ー タ が 入 力 さ れ ま せ ん で し た 。 \n");

exit(EXIT_SUCCESS); }

関 連 項 目

accept(2), connect(2), poll(2), read(2), recv(2), restart_syscall(2), send(2), sigprocmask(2), write(2), epoll(7), time(7) 考 察 と 使 用 例 の 書 か れ た チ ュ ー ト リ ア ル と し て 、 select_tut(2) が あ る 。

こ の 文 書 に つ い て

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