FCNTL
Section: Linux Programmer's Manual (2)
Updated: 2009-10-17
Index
JM Home Page
roff page
名前
fcntl - ファイルディスクリプタの操作を行う
書式
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
説明
fcntl()
は、オープンされたファイルディスクリプタ
fd
に関して下記の操作を行う。操作は
cmd
によって決まる:
fcntl()
はオプションとして第三引き数をとることができる。
第三引き数が必要かどうかは
cmd
により決まる。
必要な引き数の型は
cmd
名の後ろの括弧内で指定されている
(ほとんどの場合、必要な型は
long
であり、この引き数を表すのに
arg
という名前を使っている)。
引き数が必要ない場合には
void
が指定されている。
ファイルディスクリプタの複製
- F_DUPFD (long)
-
利用可能なファイルディスクリプタのうち、
arg
以上で最小のものを探し、
fd
のコピーとする。これは別の形の
dup2(2)
である。
dup2(2)
では指定されたディスクリプタが使われる点が違う。
-
成功すると、新しいディスクリプタが返される。
-
詳細は
dup(2)
を参照のこと。
- F_DUPFD_CLOEXEC (long; Linux 2.6.24 以降)
-
F_DUPFD
と同様だが、それに加えて複製されたディスクリプタに対して
close-on-exec フラグをセットする。
このフラグを指定することで、プログラムは
FD_CLOEXEC
フラグをセットするために
fcntl()
の
F_SETFD
操作を追加で行う必要がなくなる。
このフラグがなぜ有用かについては、
open(2)
の
O_CLOEXEC
の説明を参照のこと。
ファイルディスクリプタ・フラグ
以下のコマンドを使って、ファイルディスクリプタに関連するフラグ
を操作することができる。
現在のところ、定義されているフラグは一つだけである:
FD_CLOEXEC
(close-on-exec フラグ)。
FD_CLOEXEC
ビットが 0 なら、ファイルディスクリプタは
execve(2)
を行ってもオープンされたままだが、そうでない場合はクローズされる。
- F_GETFD (void)
-
ファイルディスクリプタ・フラグを読み出す。
arg
は無視される。
- F_SETFD (long)
-
ファイルディスクリプタ・フラグに
arg
で指定した値を設定する。
ファイル状態フラグ
オープンファイル記述 (open file description) には、
ファイル記述毎に設定される状態フラグがいくつかある。これらのフラグは
open(2)
によって初期化され、
fcntl(2)
により変更することもできる。これらは、
(dup(2),
fcntl(F_DUPFD),
fork(2)
などで) 複製されたファイルディスクリプタ同士は
同じオープンファイル記述を参照する。
そのため、
同じファイル状態フラグが共有される。
ファイル状態フラグとその意味は
open(2)
で説明されている。
- F_GETFL (void)
-
ファイル状態フラグを読み出す。
arg
は無視される。
- F_SETFL (long)
-
ファイル状態フラグに
arg
で指定された値を設定する。
arg
のうち、ファイルのアクセスモード
(O_RDONLY, O_WRONLY, O_RDWR)
とファイル作成フラグ (すなわち
O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC)
に関するビットは無視される。
Linux では、このコマンドで変更できるのは
O_APPEND,
O_ASYNC,
O_DIRECT,
O_NOATIME,
O_NONBLOCK
フラグだけである。
アドバイザリ・ロック
F_GETLK, F_SETLK, F_SETLKW
は、レコード・ロックの獲得/解放/テストのために使用する
(レコード・ロックはファイルセグメント・ロックや
ファイル領域ロックとも呼ばれる)。
三番目の引き数
lock
は、以下に示すフィールドを含む構造体へのポインタである
(フィールドの順序は関係なく、構造体に他のフィールドがあってもよい)。
struct flock {
...
short l_type; /* Type of lock: F_RDLCK,
F_WRLCK, F_UNLCK */
short l_whence; /* How to interpret l_start:
SEEK_SET, SEEK_CUR, SEEK_END */
off_t l_start; /* Starting offset for lock */
off_t l_len; /* Number of bytes to lock */
pid_t l_pid; /* PID of process blocking our lock
(F_GETLK only) */
...
};
この構造体の
l_whence, l_start, l_len
フィールドで、ロックを行いたいバイト範囲を指定する。
ファイルの末尾より後ろのバイトをロックすることはできるが、
ファイルの先頭より前のバイトをロックすることはできない。
l_start
はロックを行う領域の開始オフセットである。
その意味は
l_whence
により異なる:
l_whence
が
SEEK_SET
の場合はファイルの先頭からのオフセット、
l_whence
が
SEEK_CUR
の場合は現在のファイルオフセットからのオフセット、
l_whence
が
SEEK_END
の場合はファイルの末尾からのオフセットと解釈される。
後ろの2つの場合には、
ファイルの先頭より前にならない範囲で、
l_start
に負の値を指定することができる。
l_len
はロックしたいバイト数を示す。
l_len
が正の場合、ロックされるバイト範囲は
l_start
以上
l_start+l_len-1
以下となる。
l_len
に 0 を指定した場合は特別な意味を持つ:
l_whence and l_start
で指定される位置からファイルの末尾までの全てのバイトをロックする
(ファイルがどんなに大きくなったとしてもファイルの末尾までロックする)。
POSIX.1-2001 では、負の値の
l_len
をサポートする実装を認めている (必須ではない)。
l_len
が負の場合、ロックされるバイト範囲は
l_start+l_len
以上
l_start-1
以下となる。
この動作はカーネル 2.4.21 以降および 2.5.49 以降の Linux で
サポートされている。
l_type
フィールドは、ファイルに対して読み出しロック
(F_RDLCK)
と書き込みロック
(F_WRLCK)
のどちらを
設定するかを指定する。
ファイルのある領域に対して、読み出しロック (共有ロック) を保持できる
プロセス数に制限はないが、書き込みロック (排他ロック) を保持できる
のは一つのプロセスだけである。排他ロックを設定すると、(共有ロックか
排他ロックにかかわらず) 他のロックは何も設定できない。
一つのプロセスは、ファイルのある領域に対して一種類のロックしか保持できない。
新規のロックがロックが設定されている領域に対して適用されると、既存のロック
は新規のロックの種別に変換される
(新規のロックで指定されたバイト範囲が既存ロックの範囲と一致する場合以外では、
変換の過程で既存のロックの分割、縮小、結合が行われることがある)。
- F_SETLK (struct flock *)
-
(l_type
が
F_RDLCK
か
F_WRLCK
の場合は) ロックの獲得を、
(F_UNLCK
の場合は) ロックの解放を、
flock
構造体のフィールド
l_whence, l_start, l_len
で指定された範囲のバイトに対して行う。
指定されたロックが他のプロセスが設定しているロックと衝突する場合は、
-1 を返し、
errno
に
EACCES
か
EAGAIN
を設定する。
- F_SETLKW (struct flock *)
-
F_SETLK
と同様だが、こちらではそのファイルに対して衝突するロックが
適用されていた場合に、そのロックが解放されるのを待つ点が異なる。
待っている間にシグナルを受けた場合は、システムコールは中断され、
(シグナルハンドラが戻った直後に) 返り値 -1 を返す (また
errno
に
EINTR
が設定される;
signal(7)
参照)。
- F_GETLK (struct flock *)
-
このコールの呼び出し時には、
lock
にはそのファイルに適用しようとするロックに関する情報が入っている。
ロックを適用できる場合には、
fcntl()
は実際にはロックを行わず、構造体
lock
の
l_type
フィールドに
F_UNLCK
を設定し、他のフィールドは変更せずに、復帰する。
違う種別のロックが (一つもしくは複数) 適用されていて
ロックを適用できないような場合には、
fcntl()
は、原因となったロックの一つについての詳細情報を構造体
lock
のフィールド
l_type, l_whence, l_start, l_len
に格納し、また
l_pid
にロックを保持しているプロセスの PID を設定して、復帰する。
読み出しロックを適用するには、
fd
は読み出し用にオープンされていなければならない。
書き込みロックを適用するには、
fd
は書き込み用にオープンされていなければならない。
読み書き両方のロックを適用するには、読み書き両用で
ファイルをオープンしなければならない。
レコードのロックは、
F_UNLCK
により明示的に削除されるだけでなく、
プロセスが終了したときや、ロックが適用されているファイルを参照している
ファイルディスクリプタのいずれかがクローズされた場合にも解放される。
このロックの解放は自動的に行われる。
この動作はまずい: あるプロセスが
/etc/passwd
や
/etc/mtab
といったファイルにロックを適用しているときに、
あるライブラリ関数が何かの理由で同じファイルを open, read, close
すると、そのファイルへのロックが失われることになる。
レコードのロックは
fork(2)
で作成された子プロセスには継承されないが、
execve(2)
の前後では保存される。
stdio(3)
ではバッファリングが行われるので、
stdio 関連の関数ではレコードのロックの使用は回避される;
代わりに
read(2)
や
write(2)
を使用すること。
強制ロック (mandatory locking)
上述のロックにはアドバイザリ・ロック (advisory lock) と強制ロック (mandatory
lock) の二種類があるが、デフォルトではアドバイザリ・ロックとなる。
アドバイザリ・ロックに強制力はなく、協調して動作するプロセス間でのみ
有効である。
強制ロックは全てのプロセスに対して効果がある。
あるプロセスが互換性のない強制ロックが適用されたファイル領域に対して
(read(2)
や
write(2)
により) 互換性のないアクセスを実行しようとした場合、
アクセスの結果は
そのファイルのオープンファイル記述で
O_NONBLOCK
フラグが有効になっているかにより決まる。
O_NONBLOCK
フラグが有効になっていないときは、ロックが削除されるか、
ロックがアクセスと互換性のあるモードに変換されるまで、
システムコールは停止 (block) される。
O_NONBLOCK
フラグが有効になっているときは、システムコールはエラー
EAGAIN
で失敗する。
強制ロックを使用するためには、ロック対象のファイルが含まれるファイルシステム
と、ロック対象のファイル自身の両方について、強制ロックが有効になっていなけれ
ばならない。ファイルシステムについて強制ロックを有効にするには、
mount(8)
に "-o mand" オプションを渡すか、
mount(2)
に
MS_MANDLOCK
フラグを指定する。ファイルについて強制ロックを有効にするには、
そのファイルのグループ実行許可 (group execute permission) を無効とし、
かつ set-group-ID 許可ビットを有効にする
(chmod(1)
と
chmod(2)
を参照)。
Linux の強制ロックの実装は信頼性に欠けるものである。
下記の「バグ」の節を参照のこと。
シグナルの管理
F_GETOWN,
F_SETOWN,
F_GETOWN_EX,
F_SETOWN_EX,
F_GETSIG,
F_SETSIG
は、I/O が利用可能になったことを示すシグナルを管理するために使用される。
- F_GETOWN (void)
-
ファイルディスクリプタ
fd
のイベントに対するシグナル
SIGIO
および
SIGURG
を受けているプロセスのプロセスID かプロセスグループを
(関数の結果として) 返す。
プロセスID は正の値として返される。
プロセスグループID は負の値として返される (下記のバグの章を参照)。
arg
は無視される。
- F_SETOWN (long)
-
ファイルディスクリプタ
fd
のイベント発生を知らせるシグナル
SIGIO
や
SIGURG
を受けるプロセスの
プロセス ID またはプロセスグループID を
arg
で指定された ID に設定する。
プロセスID は正の値として指定し、
プロセスグループID は負の値として指定する。
ほとんどの場合、呼び出し元プロセスは所有者として自分自身を指定する
(つまり
arg
に
getpid(2)
を指定する)。
fcntl()
の
F_SETFL
コマンドを使用してファイルディスクリプタに
O_ASYNC
状態フラグを設定した場合には、そのファイルディスクリプタへの
入出力が可能になる度に
SIGIO
シグナルが送られる。
F_SETSIG
は
SIGIO
以外の別のシグナルの配送を受けられるように
するのにも使うことができる。
許可 (permission) のチェックで失敗した場合には、
シグナルは黙って捨てられる。
F_SETOWN
により指定された所有者のプロセス (またはプロセスグループ) に
シグナルを送る際には、
kill(2)
に書かれているのと同じ許可のチェックが行われる。
このとき、シグナルを送信するプロセスは
F_SETOWN
を使ったプロセスである
(但し、下記の「バグ」の章を参照のこと)。
ファイルディスクリプタがソケットを参照している場合は、
F_SETOWN
を使用して、ソケットに帯域外 (out-of-band) データが届いた時に
SIGURG
シグナルを配送する相手を選択することもできる
(SIGURG
が送られた場合には
select(2)
がソケットが「特別な状態」にあると報告することだろう)。
バージョン 2.6.11 以前の 2.6.x カーネルでは、以下に示す動作であった。
-
-
スレッドグループをサポートしているスレッドライブラリ (例えば NPTL) を
使って動作しているマルチスレッド・プロセスで
F_SETSIG
に 0 以外の値を指定した場合、
F_SETOWN
に正の値を渡すと、その意味が違ってくる:
プロセス全体を示すプロセスID ではなく、プロセス内の特定の
スレッドを示すスレッドID と解釈される。
したがって、
F_SETSIG
を使う場合には、きちんと結果を受け取るには、
F_SETOWN
に渡す値を
getpid(2)
ではなく
gettid(2)
の返り値にする必要があるだろう。
(現状の Linux スレッド実装では、メイン・スレッドのスレッドID は
そのスレッドのプロセスID と同じである。つまり、
シグナル・スレッドのプログラムではこの場合
gettid(2)
と
getpid(2)
は全く同じように使うことができる。)
ただし、注意すべき点として、この段落で述べたことは、
ソケットの帯域外データが届いたときに生成される
SIGURG
シグナルにはあてはまらない。
このシグナルは常にプロセスかプロセスグループに送られ、
送信先は
F_SETOWN
に渡された値にしたがって決められる。
-
上記の動作は、Linux 2.6.12 で図らずも削除され、
元に戻されない予定である。
Linux 2.6.32 以降で、特定のスレッド宛にシグナル
SIGIO
と
SIGURG
を送るには
F_SETOWN_EX
を使うこと。
- F_GETOWN_EX (struct f_owner_ex *) (Linux 2.6.32 以降)
-
直前の
F_SETOWN_EX
操作で定義された現在のファイルディスクリプタの所有者設定
を返す。情報は
arg
が指す構造体に格納されて返される。構造体は以下の通りである。
struct f_owner_ex {
int type;
pid_t pid;
};
type
フィールドは、
F_OWNER_TID ,
F_OWNER_PID ,
F_OWNER_PGRP
のいずれか一つの値となる。
pid
フィールドは、スレッド ID、プロセス ID、プロセスグループ ID を
表す正の整数である。詳細は
F_SETOWN_EX
を参照。
- F_SETOWN_EX (struct f_owner_ex *) (Linux 2.6.32 以降)
-
この操作は
F_SETOWN
と同様の処理を行う。
この操作を使うと、I/O が利用可能になったことを示すシグナルを、
特定のスレッド、プロセス、プロセスグループに送ることができる
ようになる。
呼び出し元は、
arg
経由でシグナルの配送先を指定する。
arg
は
f_owner_ex
構造体へのポインタである。
type
フィールドは以下のいずれかの値を取り、
この値により
pid
がどのように解釈されるかが規定される。
-
- F_OWNER_TID
-
スレッド ID が
pid
で指定された値のスレッドにそのシグナルを送る
(スレッド ID は
clone(2)
や
gettid(2)
の呼び出しで返される値である)。
- F_OWNER_PID
-
ID が
pid
で指定された値のプロセスにそのシグナルを送る。
- F_OWNER_PGRP
-
ID が
pid
で指定された値のプロセスグループにそのシグナルを送る。
(F_SETOWN
と異なり、プロセスグループ ID には正の値を指定する点に注意すること。)
- F_GETSIG (void)
-
入力や出力が可能になった場合に送るシグナルを
(関数の結果として) 返す。
値ゼロは
SIGIO
を送ることを意味する。
(SIGIO
を含む) 他の値はいずれも、
SIGIO
の代わりに送るシグナル番号を表す。
後者の場合、シグナルハンドラを
SA_SIGINFO
フラグ付きで設定すれば、ハンドラで追加の情報を得ることができる。
arg
は無視される。
- F_SETSIG (long)
-
入力や出力が可能になった場合に送るシグナルを
arg
に指定された値に設定する。
値ゼロは
SIGIO
を送ることを意味する。
(SIGIO
を含む) 他の値はいずれも、
SIGIO
の代わりに送るシグナル番号を表す。
後者の場合、シグナルハンドラを
SA_SIGINFO
フラグ付きで設定すれば、
ハンドラで追加の情報を得ることができる。
F_SETSIG
にゼロ以外の値を設定し、シグナルハンドラに
SA_SIGINFO
フラグを設定すると、
(sigaction(2)
を参照) I/O イベントに関する追加の情報が
siginfo_t
構造体でシグナルハンドラへ渡される。
si_code
フィールドが示すシグナルの原因が
SI_SIGIO
である場合、
si_fd
フィールドにはイベントに対応するファイルディスクリプタが入っている。
それ以外の場合は、どのファイルディスクリプタが利用可能かを示す情報は
ないので、どのファイルディスクリプタで I/O が可能かを判断するためには
通常の機構
(select(2),
poll(2),
O_NONBLOCK
を設定した
read(2)
など) を使用しなければならない。
リアルタイムシグナル (値が
SIGRTMIN
以上) を選択している場合は、
同じシグナル番号を持つ複数の I/O イベントがキューに入ることがある
(キューに入れるかどうかは利用可能なメモリに依存している)。
上記と同様、
SA_SIGINFO
が設定されている場合、シグナルハンドラのための追加の情報が得られる。
以下の点に注意すること。
Linux では一つのプロセスに対してキューに入れられるリアルタイム
シグナルの数に上限が設けられており
(getrlimit(2)
と
signal(7)
を参照)、この上限に達するとカーネルは
SIGIO
シグナルを配送する。この
SIGIO
シグナルは、指定されたスレッドではなくプロセス全体に送られる。
これらの機構を使用することで、ほとんどの場合で
select(2)
や
poll(2)
を使用せずに完全な非同期 I/O を実装することができる。
O_ASYNC,
F_GETOWN,
F_SETOWN
の使用は BSD と Linux に特有である。
F_GETOWN_EX,
F_SETOWN_EX,
F_GETSIG,
F_SETSIG
は Linux 固有である。POSIX には、同様のことを行うために、非同期 I/O と
aio_sigevent
構造体がある。Linux では、GNU C ライブラリ (Glibc) の一部として
これらも利用可能である。
リース (leases)
(Linix 2.4 以降で利用可能)
F_SETLEASE
は、
fd
が参照するオープンファイル記述に対して新しいリースを設定するのに使用される。
F_GETLEASE
は、
fd
が参照するオープンファイル記述に対して設定されている
現在のリースを取得するのに使用される。
ファイルのリースにより、
あるプロセス ("lease breaker") がそのファイルディスクリプタが参照
しているファイルに対して
open(2)
や
truncate(2)
を行おうとした際に、リースを保持しているプロセス ("lease holder") へ
(シグナルの配送による) 通知が行われるという機構が提供される。
- F_SETLEASE (long)
-
arg
の内容に基いてファイルのリースの設定、削除を行う。整数
arg
には以下の値が指定できる:
-
- F_RDLCK
-
読み出しリースを取得する。これにより、
そのファイルが書き込み用にオープンされたり、ファイルが切り詰められた場合に、
呼び出し元のプロセスに通知が行われるようになる。
読み出しリースを設定できるのは、読み出し専用でオープンされている
ファイルディスクリプタに対してのみである。
- F_WRLCK
-
書き込みリースを取得する。これにより、
(読み出し用か書き込み用にかかわらず) そのファイルがオープンされたり、
ファイルが切り詰められた場合に、呼び出し元のプロセスに通知が行われるようになる。
書き込みリースは、そのファイルに対するオープンされたファイルディスクリプタが
他にない場合にのみ設定できる。
- F_UNLCK
-
そのファイルからリースを削除する。
リースはオープンファイル記述に対して関連付けられる
(open(2)
参照)。
つまり、
(fork(2)
や
dup(2)
などにより作成された) ファイルディスクリプタの複製は同じリースを参照し、
複製も含めたどのファイルディスクリプタを使ってもこのリースを変更したり
解放したりできる。
また、これらのファイルディスクリプタのいずれかに対して
F_UNLCK
操作が明示的に実行された場合や、すべてのファイルディスクリプタが
閉じられた場合にも、リースは解放される。
リースの取得は通常のファイル (regular file) に対してのみ可能である。
非特権プロセスがリースを取得できるのは、UID (所有者) がプロセスの
ファイルシステム UID と一致するファイルに対してだけである。
CAP_LEASE
ケーパビリティを持つプロセスは任意のファイルに対してリースを取得できる。
- F_GETLEASE (void)
-
ファイルディスクリプタ
fd
に対して設定されているリースの種別を取得する。
F_RDLCK, F_WRLCK, F_UNLCK
のいずれかが返される。
F_RDLCK, F_WRLCK
はそれぞれ、読み出しリース、書き込みリースが設定されていることを示し、
F_UNLCK
はリースが何も設定されていないことを示す。
arg
は無視される。
あるプロセス ("lease folder") が
F_SETLEASE
で設定されたリースと矛盾するような
open(2)
や
truncate(2)
を実行した場合、
そのシステムコールはカーネルによって停止され、
カーネルは lease holder にシグナル (デフォルトでは
SIGIO)
を送って通知を行う。
lease holder はこのシグナルを受信したときにはきちんと対応すべきである。
具体的には、別のプロセスがそのファイルにアクセスするための準備として
必要な後片付け (例えば、キャッシュされたバッファのフラッシュ) を
すべて行ってから、そのファイルのリースの削除または格下げを行う。
リースを削除をするには、
arg
に
F_UNLCK
を指定して
F_SETLEASE
を実行する。
lease holder がファイルに書き込みリースを保持していて、
lease breaker が読み出し用にそのファイルをオープンしている場合、
lease holder が保持しているリースを読み出しリースに格下げすれば
十分である。これをするには、
arg
に
F_RDLCK
を指定して
F_SETLEASE
を実行する。
lease holder が
/proc/sys/fs/lease-break-time
で指定された秒数以内にリースの格下げか削除を行えなかった場合、
カーネルは強制的にその lease holder のリースを削除もしくは格下げを行う。
一度リースの削除か格下げが自発的もしくは強制的に行われると、
lease breaker がまだシステムコールを再開していない場合には、
カーネルが lease breaker のシステムコールの続行を許可する。
lease breaker が実行した
open(2)
や
truncate(2)
が停止中にシグナルハンドラにより中断された場合、
そのシステムコールは
EINTR
エラーで失敗するが、上で述べた他の処理は
そのまま行われる。
open(2)
や
truncate(2)
が停止中に lease breaker がシグナルにより kill された場合、
上で述べた他の処理はそのまま行われる。
lease breaker が
open(2)
を呼ぶ際に
O_NONBLOCK
フラグを指定した場合、そのシステムコールは
EWOULDBLOCK
エラーで直ちに失敗するが、上で述べた他の処理はそのまま行われる。
lease holder への通知に使われるデフォルトのシグナルは
SIGIO
だが、
fcntl()
の
F_SETSIG
コマンドで変更することができる。
F_SETSIG
コマンドが実行され
(SIGIO
を指定された場合も含む)、
SA_SIGINFO
フラグ付きでシグナルハンドラが設定されている場合には、
ハンドラの第二引き数として
siginfo_t
構造体が渡され、この引き数の
si_fd
フィールドには別のプロセスがアクセスしたリース設定済みファイルの
ディスクリプタが入っている
(この機能は複数のファイルに対してリースを設定する場合に有用である)。
ファイルやディレクトリの変更の通知 (dnotify)
- F_NOTIFY (long)
-
(Linux 2.4 以降)
fd
で参照されるディレクトリか、その中にあるファイルに変更があった場合に
通知を行う。どのイベントを通知するかは
arg
で指定する。
arg
はビットマスクで、以下のビットの 0個以上の論理和をとったものを指定する。
-
- DN_ACCESS
-
ファイルへのアクセスがあった (read, pread, readv)
- DN_MODIFY
-
ファイルの内容が変更された (write, pwrite, writev, truncate, ftruncate).
- DN_CREATE
-
ファイルが作成された (open, creat, mknod, mkdir, link, symlink, rename).
- DN_DELETE
-
ファイルが削除 (unlink) された (unlink, 別のディレクトリへの rename, rmdir)
- DN_RENAME
-
ディレクトリ内でのファイル名の変更があった (rename)
- DN_ATTRIB
-
ファイル属性が変更された (chown, chmod, utime[s])
-
(上記の定義を利用するには
_GNU_SOURCE
機能検査マクロを定義しなければならない。)
ディレクトリの変更通知は通常「一回限り (one-shot)」であり、
アプリケーション側でその後さらに通知を受信したい場合は
再登録しなければならない。
arg
に
DN_MULTISHOT
が含まれていた場合には、
変更通知は明示的に解除されるまで有効状態が継続する。
F_NOTIFY
要求は積算されていく。つまり、
arg
で指定されたイベントがすでにモニタされている
イベント集合に加算される形になる。
すべてのイベントの通知を無効にするには、
arg
に 0 を指定して
F_NOTIFY
を呼び出す必要がある。
通知はシグナルの配送で行われる。
デフォルトのシグナルは
SIGIO
だが、
fcntl()
の
F_SETSIG
コマンドで変更することができる。
後者の場合には、
(SA_SIGINFO
フラグ付きでシグナルハンドラが設定されている場合には)
ハンドラの第二引き数として
siginfo_t
構造体が渡され、この構造体の
si_fd
フィールドには通知の行われたファイルディスクリプタが入っている
(この機能は複数のディレクトリに対して通知を設定する場合に有用である)。
特に
DN_MULTISHOT
を使う場合は、通知にはリアルタイムシグナルを使うべきである。
それは、リアルタイムシグナルを使うことで、複数の通知をキューに入れる
ことができるからである。
注意:
新しくアプリケーションを書く際には、(カーネル 2.6.13 以降で利用可能となった)
inotify
インタフェースを使用すべきである。
inotify
はファイルシステムイベントの通知を取得するための
ずっと優れたインタフェースである。
inotify(7)
を参照。
返り値
成功した場合の返り値は操作の種類により違う:
- F_DUPFD
-
新しいディスクリプタを返す。
- F_GETFD
-
フラグの値を返す。
- F_GETFL
-
フラグの値を返す。
- F_GETLEASE
-
ファイルディスクリプタに対して保持されているリースの種別を返す。
- F_GETOWN
-
ディスクリプタの所有者を返す。
- F_GETSIG
-
読み込みや書き出しが可能になった時に送られるシグナルの値、もしくは
伝統的な
SIGIO
動作の場合にはゼロを返す。
- 他の全てのコマンドは 0 を返す。
-
エラーの時は -1 が返され、
errno
に適切な値が設定される。
エラー
- EACCES か EAGAIN
-
他のプロセスが保持しているロックによって操作が禁止されている。
- EAGAIN
-
そのファイルは他のプロセスによってメモリ・マップされているため、
操作が禁止されている。
- EBADF
-
fd
がオープンされたファイルディスクリプタでない。
あるいはコマンドが
F_SETLK
または
F_SETLKW
だったが、対象のファイルディスクリプタのオープンモードが
必要となるロックの型にマッチしていない。
- EDEADLK
-
指定された
F_SETLKW
コマンドを実行した場合にはデッドロックになることが検出された。
- EFAULT
-
lock
が利用可能なアドレス空間の外部にある。
- EINTR
-
F_SETLKW
コマンドがシグナルにより割り込まれた
(signal(7)
参照)。
F_GETLK と F_SETLK
の場合、ロックを確認したり取得したりする前にシグナルによって割り込まれた。
これはたいていリモートのファイルをロックする場合
(例えば NFS 上でロックする場合) に起こる。
しかしローカルでも起こる場合がある。
- EINVAL
-
F_DUPFDで、
arg
が負か、もしくは許される最大値よりも大きい。
F_SETSIG
の場合、
arg
が利用可能なシグナル番号ではない。
- EMFILE
-
F_DUPFDで、
プロセスがすでに最大数までファイルディスクリプタをオープンしている。
- ENOLCK
-
オープンされているロックの数が多過ぎて、ロック・テーブルがいっぱいである。
または remote locking protocol (例えば NFS 上のロック) が失敗した。
- EPERM
-
追加専用属性が設定されたファイルの
O_APPEND
フラグをクリアしようと試みた。
準拠
SVr4, 4.3BSD, POSIX.1-2001.
POSIX.1-2001 で規定されている操作は、
F_DUPFD,
F_GETFD,
F_SETFD,
F_GETFL,
F_SETFL,
F_GETLK,
F_SETLK,
F_SETLKW,
F_GETOWN,
F_SETOWN
だけである。
F_DUPFD_CLOEXEC
は POSIX.1-2008 で規定されている。
F_GETOWN_EX,
F_SETOWN_EX,
F_GETSIG,
F_SETSIG,
F_NOTIFY,
F_GETLEASE,
F_SETLEASE
は Linux 固有である (これらの定義を有効にするには
_GNU_SOURCE
マクロを定義すること)。
注意
エラーの際の返り値が
dup2(2)
と
F_DUPFD
では異なっている。
カーネル 2.0 以降では、
flock(2)
と
fcntl()
が設定するロック種別の間に相互作用はない。
システムによっては、
struct flock
に上記以外のフィールドがあるものもある (例えば
l_sysid)。
はっきりと言えることは、ロックを保持しているプロセスが別のマシンに存在
する場合には、
l_pid
だけはあまり役にたたないだろうということである。
バグ
いくつかのアーキテクチャ (特に i386) における Linux システムコールの慣習
のため以下の制限が存在する。
F_GETOWN
が返す (負の) プロセスグループID が -1 から -4095 の範囲に入った場合、
glibc はこの返り値をシステムコールでエラーが起こったと
間違って解釈してしまう。つまり、
fcntl()
の返り値は -1 となり、
errno
には (正の) プロセスグループID が設定されることになる。
Linux 固有の
F_SETOWN_EX
と
F_GETOWN_EX
ではこの問題を回避できる。
Linux 2.4 以前では、非特権プロセスが
F_SETOWN
を使って、ソケットのファイルディスクリプタの所有者に
呼び出し元以外のプロセス (やプロセスグループ) を指定すると
発生するバグがある。この場合、
呼び出し元が所有者として指定したプロセス (やプロセスグループ) に
シグナルを送る許可を持っていたとしても、
fcntl()
が -1 を返し
errno
に
EPERM
を設定することがある。
このエラーが返ったにもかかわらず、ファイルディスクリプタの所有者
は設定され、シグナルはその所有者に送られる。
これまでの Linux の全てのバージョンにおける強制ロックの実装は、
競合条件下で強制ロックが不完全になるような場合がある。
ロックと重なって実行された
write(2)
の呼び出しは強制ロックが獲得された後にもデータを変更することができる。
ロックと重なって実行された
read(2)
の呼び出しは強制ロックが獲得された後になって行われたデータの変更を
検出することができる。
同様の競合条件が強制ロックと
mmap(2)
の間にも存在する。それゆえ、強制ロックに頼るのはお薦めできない。
関連項目
dup2(2),
flock(2),
open(2),
socket(2),
lockf(3),
capabilities(7),
feature_test_macros(7)
カーネルソースの
Documentation/filesystems/
ディレクトリ内の
locks.txt,
mandatory-locking.txt,
dnotify.txt
も参照のこと。
(以前のカーネルでは、これらのファイルは
Documentation/
ディレクトリ直下にあり、
mandatory-locking.txt
は
mandatory.txt
という名前であった。)
Index
- 名前
-
- 書式
-
- 説明
-
- ファイルディスクリプタの複製
-
- ファイルディスクリプタ・フラグ
-
- ファイル状態フラグ
-
- アドバイザリ・ロック
-
- 強制ロック (mandatory locking)
-
- シグナルの管理
-
- リース (leases)
-
- ファイルやディレクトリの変更の通知 (dnotify)
-
- 返り値
-
- エラー
-
- 準拠
-
- 注意
-
- バグ
-
- 関連項目
-
This document was created by
man2html,
using the manual pages.
Time: 03:26:41 GMT, April 25, 2010