EN JA
FUTEX(2)
FUTEX(2) Linux Programmer's Manual FUTEX(2)

名前

futex -高速ユーザ空間ロック

書式

 

#include <linux/futex.h>
#include <sys/time.h>
 

int futex(int * uaddr , int op , int val , const struct timespec * timeout ,
 

int * uaddr2 , int val3 );

説明

futex() システムコールは、指定したアドレスの値が変更されるのをプログラムが待つ手段や特定のアドレスに対して待機中のプロセスを wake (起床) させる手段を提供する (プロセスが異なれば同じメモリに対するアドレスも同じではないかもしれないが、カーネルは異なる位置にマップされた同じメモリを futex() で使えるよう内部でマップする)。通常は、このシステムコールは futex(7) に書かれているように、共有メモリ中のロックが競合する場合の処理を実装するのに用いられる。

futex(7) の操作がユーザ空間で競合なく完了しなかった場合、カーネルに仲裁させるためにシステムコールを呼ぶ必要がある。仲裁というのは、呼び出しプロセスを sleep (起床待ち) させたり、反対に待ちプロセスを wake させたりすることを意味する。

この関数を呼び出すプロセスは futex(7) に記述されているセマンティクスに忠実であることが要求される。このセマンティクスには移植不可能なアセンブリ命令を書くことが含まれる。このことは言い換えると futex のユーザのほとんどは実際はライブラリの作者であり、一般アプリケーションの開発者ではないということである。

uaddr 引き数は、カウンタを格納する、アラインメントの揃った int 型変数を指している必要がある。実行する操作は op 引き数を介して、値 val とともに渡される。

現在のところ 5 つの操作が定義されている:

FUTEX_WAIT
この操作は futex アドレス uaddr に指定された値 val がまだ格納されているかどうかを不可分操作で検証し、 sleep 状態でこの futex アドレスに対して FUTEX_WAKE が実行されるのを待つ。 timeout 引き数が NULL でない場合、その内容は待ち時間の最大値を表す。NULL の場合は無限大を表す。引き数 uaddr2val3 は無視される。
 
futex(7) に照らし合わせると、この呼び出しはカウントのデクリメントで負の値 (競合を表す) になった場合に実行され、別のプロセスがその futex を解放し FUTEX_WAKE の操作を実行するまで sleep する。
FUTEX_WAKE
この操作では指定した futex アドレスに対して待ち状態の (すなわち FUTEX_WAIT 中の) 最大 val 個のプロセスを wake させる。引き数 timeout, uaddr2, val3 は無視される。
 
futex(4) に照らし合わせると、この操作はカウントのインクリメントで待ちプロセスがあると判明し、 futex 値が 1 に設定された (利用可能であることを表す) 場合に実行される。
FUTEX_FD (Linux 2.6.25 以前)
非同期の wake に対応するため、この操作はファイルディスクリプタを futex に関連づける。別のプロセスが FUTEX_WAKE を実行すると、プロセスは val で渡されたシグナル番号のシグナルを受信する。呼び出しプロセスは使用後、返されたファイルディスクリプタをクローズしなければならない。引き数 timeout, uaddr2, val3 は無視される。
 
競合状態を防止するため、呼び出しプロセスは FUTEX_FD が返ったあと futex が up されたかどうかを確認しなければならない。
 
FUTEX_FD はもともと競合が起きやすかったため、 Linux 2.6.26 以降で削除されている。
FUTEX_REQUEUE (Linux 2.5.70 以降)
この操作は、 FUTEX_WAKE が使われていて、かつ wake されている全てのプロセスが他の futex を取得する必要がある場合に、「獣の群れの暴走 (thundering herd)」効果を避けるために導入された。この呼び出しは val 個のプロセスを wake し、アドレス uaddr2 で futex を待っている他の全てのプロセスを再度キューにいれる。引き数 timeoutval3 は無視される。
FUTEX_CMP_REQUEUE (Linux 2.6.7 以降)
故意に FUTEX_REQUEUE を使う場合に競合が起こるため、 FUTEX_CMP_REQUEUE が導入された。これは FUTEX_REQUEUE と似ているが、場所 uaddr に値 val3 がまだ保持されているかを最初にチェックする。保持されていない場合、操作はエラー EAGAIN で失敗する。引き数 timeout は無視される。

返り値

In the event of an error, all operations return -1, and set errno to indicate the error. The return value on success depends on the operation, as described in the following list:
FUTEX_WAIT
Returns 0 if the process was woken by a FUTEX_WAKE call. See ERRORS for the various possible error returns.
FUTEX_WAKE
wake したプロセスの数を返す。
FUTEX_FD
futex に関連づけられた新たなファイルディスクリプタを返す。
FUTEX_REQUEUE
wake したプロセスの数を返す。
FUTEX_CMP_REQUEUE
wake したプロセスの数を返す。

エラー

EACCES
futex メモリに読み込みアクセス権がなかった。
EAGAIN
FUTEX_CMP_REQUEUE detected that the value pointed to by uaddr is not equal to the expected value val3. (This probably indicates a race; use the safe FUTEX_WAKE now.)
EFAULT
ユーザ空間から timeout の情報を取得する際にエラーが発生した。
EINTR
A FUTEX_WAIT operation was interrupted by a signal (see signal(7)) or a spurious wakeup.
EINVAL
Invalid argument.
ENFILE
オープンされているファイルの総数がシステムの制限に達した。
ENOSYS
op に無効な操作が指定された。
ETIMEDOUT
Timeout during the FUTEX_WAIT operation.
EWOULDBLOCK
op was FUTEX_WAIT and the value pointed to by uaddr was not equal to the expected value val at the time of the call.

バージョン

最初の futex 対応は Linux 2.5.7 で組み込まれたが、上記のセマンティクスとは異なる。 4 つの引き数のここに書かれているセマンティクスを持つシステムコールは、Linux 2.5.40 で導入された。 Linux 2.5.70 では 1 つの引き数が追加された。 Linux 2.6.7 では 6 番目の引き数が追加された。これは汚く、s390 アーキテクチャ上の特別のものである。

準拠

このシステムコールは Linux 固有である。

注意

繰り返すが、裸の futex はエンドユーザが容易に使うことのできる概念として意図されたものではない (glibc にはこのシステムコールに対するラッパー関数はない)。実装者は、アセンブリ言語に慣れており、以下に挙げる futex ユーザ空間ライブラリのソースを読み終えていることが要求される。

関連項目

futex(7)

Fuss, Futexes and Furwocks: Fast Userlevel Locking in Linux (proceedings of the Ottawa Linux Symposium 2002), online at

 

http://kernel.org/doc/ols/2002/ols2002-pages-479-495.pdf

futex の使用例ライブラリ, futex-*.tar.bz2

 

ftp://ftp.nl.kernel.org/pub/linux/kernel/people/rusty/

この文書について

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