EN JA
KQUEUE(2)
KQUEUE(2) FreeBSD System Calls Manual KQUEUE(2)

名称

kqueue, keventカーネルイベント通知メカニズム

ライブラリ

Standard C Library (libc, -lc)

書式

#include < sys/types.h>
#include < sys/event.h>
#include < sys/time.h>

int
kqueue( void);

int
kevent( int kq, const struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout);

EV_SET( &kev, ident, filter, flags, fflags, data, udata);

解説

kqueue() システムコールは、イベントが起こるか、または条件が保持されるとき、フィルタと名前が付けられたカーネルコードの小さな部分の結果に基づいて、ユーザに通知する一般的方法を提供しています。 kevent は、(ident, filter) のペアによって識別されます。単に kqueue ごとに 1 つのユニークな kevent があります。

フィルタは、既存の条件が存在していることを検知するために kevent の初期登録に実行され、また、イベントが評価のためのフィルタに渡されるときはいつでも実行されます。条件が報告されるべきであることをフィルタが決定するなら、 kevent は、検索するユーザのために kqueue に置かれます。

また、フィルタは、ユーザが kqueue から kevent を検索することを試みるときも実行されます。イベントをトリガした条件がもはや保持されないことをフィルタが示すなら、 kevent は、kqueue から削除され、返されません。

フィルタをトリガする複数のイベントは、複数の kevent が kqueue に置かれているような結果となりません。代わりに、フィルタは、単一の struct kevent にイベントを集めます。ファイル記述子で close() を呼び出すことは、記述子を参照しているあらゆる kevent を削除します。

kqueue() システムコールは、新しいカーネルイベントのキューを作成し、記述子を返します。キューは、 fork(2) で作成された子どもによって継承されません。しかしながら、 rfork(2)RFFDG フラグなしで呼び出されるなら、記述子テーブルは、2 つのプロセス間で kqueue の共有を許可するように共有されます。

kevent() システムコールは、キューでイベントを登録し、ユーザにあらゆる保留中 (pending) のイベントを返すために使用されます。 changelist 引数は、 < sys/event.h> で定義されているように、 kevent 構造体の配列へのポインタです。 changelist に含まれているすべての変更は、あらゆる保留中のイベントがキューから読み込まれる前に、適用されます。 nchanges 引数は、 changelist のサイズを与えます。 eventlist 引数は、kevent 構造体の配列へのポインタです。 nevents 引数は、 eventlist のサイズを決定します。 nevents が 0 であるとき、 kevent() は、 select(2) と違って、たとえ指定された timeout があっても、直ちに返ります。 timeout が NULL ポインタでないなら、struct timespec として解釈される、イベントを待つ最大のインターバルを指定します。 timeout が NULL ポインタであるなら、 kevent() は、永久に待ちます。ポーリングを引き起こすために、 timeout 引数は、0 の値の timespec 構造体を指し、NULL であってはなりません。同じ配列は、 changelisteventlist のために使用されます。

EV_SET() マクロは、kevent 構造体を容易に初期化するために提供されています。

kevent 構造体は、次のように定義されています:

struct kevent { 
 uintptr_t ident; /* このイベントのための識別子 */ 
 short   filter; /* イベントのためのフィルタ */ 
 u_short   flags; /* kqueue のためのアクションフラグ */ 
 u_int   fflags; /* フィルタのフラグ値 */ 
 intptr_t  data;  /* フィルタのデータ値 */ 
 void   *udata; /* 不透明なユーザデータ識別子 */ 
};

struct kevent のフィールドは、次の通りです:

ident
このイベントを識別するために使用される値。正確な解釈は、アタッチされたフィルタによって決定されますが、多くの場合、ファイル記述子です。
filter
このイベントを処理するために使用されるカーネルフィルタを特定します。あらかじめ定義されたシステムフィルタは、下記に説明されます。
flags
イベントで実行するアクション。
fflags
フィルタに特有のフラグ。
data
フィルタに特有のデータ値。
udata
変更されずにカーネル通して渡される不透明なユーザ定義の値。

flags フィールドは、次の値を含むことができます:

EV_ADD
kqueue にイベントを追加します。既存のイベントに再び追加することは、オリジナルのイベントのパラメータを修正し、複製されたエントリとはなりません。イベントを追加することは、EV_DISABLE フラグによって上書きされなければ、自動的にそれを有効にします。
EV_ENABLE
イベントがトリガされるなら、 kevent() に、イベントを返すことを許可します。
EV_DISABLE
イベントを無効にするので、 kevent() は、イベントを返しません。フィルタ自体は、無効にされません。
EV_DISPATCH
イベントの配信の直後にイベントの発信元を無効にします。上記の EV_DISABLE を参照してください。
EV_DELETE
kqueue からイベントを削除します。ファイル記述子にアタッチされているイベントは、記述子の最後のクローズで自動的に削除されます。
EV_RECEIPT
このフラグは、あらゆる保留中のイベントを排出 (drain) せずに kqueue への大量の変更を行うために役に立ちます。入力として渡されるとき、常に強制的に EV_ERROR が返されます。フィルタが追加に成功するとき、 data フィールドは、0 となります。
EV_ONESHOT
イベントは、トリガされているフィルタの最初の発生だけを返します。ユーザが kqueue からイベントを検索した後、それは、削除されます。
EV_CLEAR
イベントがユーザによって検索された後、その状態は、リセットされます。これは、現在の状態の代わりに状態遷移を報告するフィルタのために役に立ちます。いくつかのフィルタが、内部でこのフラグを自動的に設定するかもしれないことに注意してください。
EV_EOF
フィルタは、フィルタに特有の EOF 状態を示すために、このフラグを設定します。
EV_ERROR
下記の 「戻り値」 を参照してください。

あらかじめ定義されたシステムフィルタは、以下にリストされます。引数は、kevent 構造体の fflagsdata フィールドを通してフィルタをやりとりして渡されます。

EVFILT_READ
識別子として記述子を取り、読み込むことができるデータがあるときはいつでも返ります。フィルタの振る舞いは、記述子タイプによって少し異なります。
ソケット
listen() (接続を受け付け) するために以前に渡されたソケットは、保留中の着信接続があるとき、返ります。 data は、listen するバックログ (backlog) のサイズを含んでいます。

他のソケットの記述子は、ソケットバッファの SO_RCVLOWAT 値に従って、読み込まれるデータがあるとき、返ります。これは、フィルタが fflags の NOTE_LOWAT フラグを設定することによって、そして data に新しい最低点 (low water mark) を指定することによって追加される時点で、フィルタごとの最低点で上書きされます。返り時に、 data は、読み込むことができるプロトコルデータのバイト数を含んでいます。

ソケットの読み込み方向がシャットダウンしたなら、フィルタは、 flags の EV_EOF も設定し、(もしあれば) fflags のソケットエラーを返します。ソケットバッファに保留中のデータがまだある間に、 (接続がなくなったことを示す) EOF を返すことができます。

vnode
ファイルポインタがファイルの終りでないとき、返ります。 data は、現在位置からファイルの終りまでのオフセットを含んでいて、負であるもしれません。
FIFO, PIPE
読み込むデータがあるとき、返ります。 data は、利用可能なバイトの数を含んでいます。

最後の書き込み処理が切断するとき、フィルタは、 flags に EV_EOF を設定します。フィルタが、データを返す前に利用可能になるのを待って再開する時点で、これは、EV_CLEAR で渡されることによってクリアされます。

BPF デバイス
BPF バッファが満杯であるとき、BPF のタイムアウトが満了するか、または BPF に有効にされた“immediate mode” (イミーディエイトモード) があり、読み込むデータがあるとき、返ります。 data は、利用可能なバイトの数を含んでいます。
EVFILT_WRITE
識別子として記述子を取り、記述子に書き込むことが可能なときはいつでも返ります。ソケット、パイプと FIFO について、 data は、書き込みバッファの残りの空間の合計を含んでいます。フィルタは、読み込み側が切断するとき、EV_EOF を設定し、 FIFO の場合に、これは、EV_CLEAR の使用によってクリアされます。このフィルタは、vnode または BPF デバイスをサポートしていないことに注意してください。

ソケットについて、最低点 (low water mark) とソケットエラーの扱いは、 EVFILT_READ の場合と同じです。

EVFILT_AIO
AIO 要求の sigevent 部分は、イベントがアタッチされるべきである kqueue の記述子を含んでいる sigev_notify_kqueue、 EV_ONESHOT、EV_CLEAR または EV_DISPATCH であるべきである kevent フラグを含んでいる sigev_notify_kevent_flags、 udata 値を含んでいる sigev_value と SIGEV_KEVENT に設定される sigev_notify で書き込まれます。 aio_*() システムコールが行われるとき、イベントは、指定された kqueue に登録され、 ident 引数は、 aio_*() システムコールによって返された struct aiocb に設定されます。フィルタは、aio_error と同じ条件で返ります。
EVFILT_VNODE
識別子としてのファイル記述子と fflags を監視するイベントを取り、1 つ以上の要求されたイベントが記述子で生じるとき、返ります。監視するイベントは、次の通りです:
NOTE_DELETE
unlink() システムコールは、記述子によって参照されるファイルで呼び出されます。
NOTE_WRITE
記述子によって参照されるファイルで生じた書き込み。
NOTE_EXTEND
記述子によって参照されるファイルが拡張されました。
NOTE_ATTRIB
記述子によって参照されるファイルには、変更された属性があります。
NOTE_LINK
変更されたファイルのリンクカウント。
NOTE_RENAME
記述子によって参照されるファイルの名前が変更された。
NOTE_REVOKE
ファイルへのアクセスが、 revoke(2) によって無効にされるか、または基本的なファイルシステムがアンマウントされました。

返り時に、 fflags は、フィルタをトリガしたイベントを含んでいます。

EVFILT_PROC
識別子として監視するプロセス ID と fflags を監視するイベントを取り、プロセスが 1 つ以上の要求されたイベントを実行するとき、返ります。プロセスが通常、別のプロセスを見ることができるなら、それにイベントをアタッチすることができます。監視するイベントは、次の通りです:
NOTE_EXIT
プロセスは、終了しました。終了ステータスは、 data に格納されます。
NOTE_FORK
プロセスは、 fork() を呼び出しました。
NOTE_EXEC
プロセスは、 execve(2) または同様の呼び出しによって新しいプロセスを実行しました。
NOTE_TRACK
fork() 呼び出しに渡ってプロセスをたどります。親プロセスは、オリジナルのイベントとして、同じ fflags を使用して、子プロセスをモニタするために新しい kevent を登録します。子プロセスは、 fflags の NOTE_CHILD 設定があるイベントと data の親 PID にシグナルを送ります。

(通常リソースの制限のために) 親プロセスが新しい kevent の登録に失敗するなら、 fflags の NOTE_TRACKERR 設定があるイベントにシグナルを送り、子プロセスは、NOTE_CHILD イベントにシグナルを送りません。

返り時に、 fflags は、フィルタをトリガしたイベントを含んでいます。

EVFILT_SIGNAL
識別子として監視するシグナル番号を取り、与えられたシグナルがプロセスに配信されるとき、返ります。これは、 signal() と sigaction() 機能と共存し、より低い優先順位があります。無視されるなら、フィルタによって記録されない、 SIGCHLD シグナルを除いて、たとえシグナルが SIG_IGN とマークされていたとしても、フィルタは、プロセスにシグナルを配信するすべての試みを記録します。イベント通知は、通常のシグナル配信処理の後に起こります。 data は、 kevent() への最後の呼び出し以後、シグナルが生じた回数を返します。このフィルタは、内部で EV_CLEAR フラグを自動的に設定します。
EVFILT_TIMER
ident によって識別される任意のタイマを確立します。タイマを追加するとき、 data は、ミリ秒単位でタイムアウト期間を指定します。タイマは、EV_ONESHOT が指定されなければ、周期的です。返り時に、 data は、 kevent() への最後の呼び出し以後、タイムアウトが満了した回数を含んでいます。このフィルタは、内部で EV_CLEAR フラグを自動的に設定します。 kern.kq_calloutmax sysctl によって制御されるタイマの数に関してシステム全体の制限があります。

返り時に、 fflags は、フィルタをトリガしたイベントを含んでいます。

EVFILT_USER
あらゆるカーネルのメカニズムに関連していないが、ユーザレベルのコードによってトリガされる ident によって識別されるユーザイベントを確立します。 fflags の下位の 24 ビットは、ユーザ定義フラグのために使用され、次を使用して操作されます:
NOTE_FFNOP
入力 fflags を無視します。
NOTE_FFAND
fflags をビット単位の論理積 (AND) します。
NOTE_FFOR
fflags をビット単位の論理和 (OR) します。
NOTE_FFCOPY
fflags をコピーします。
NOTE_FFCTRLMASK
fflags のためのマスクを制御します。
NOTE_FFLAGSMASK
fflags のためのユーザ定義フラグのマスク。

ユーザのイベントは、次で出力のためにトリガされます:

NOTE_TRIGGER
イベントは、トリガされます。

返り時に、 fflags は、下位 24 ビットにユーザ定義のフラグを含んでいます。

戻り値

kqueue() システムコールは、新しいカーネルのイベントキューを作成し、ファイル記述子を返します。カーネルのイベントキューの作成でエラーがあったなら、-1 の値が返され、 errno が設定されます。

kevent() システムコールは、 nevents によって与えられた値まで、 eventlist に置かれたイベントの数を返します。エラーが changelist の要素を処理する間に生じて、 eventlist に十分な空間があるなら、イベントは、 flagsEV_ERROR が設定され、 data にシステムエラーが設定された eventlist に置かれます。そうでなければ、 -1 が返され、 errno は、エラー状態を示す値に設定されます。時間の制限が満了するなら、 kevent() は、0 を返します。

エラー

kqueue() システムコールは、次の場合に失敗します:
[ ENOMEM]
カーネルがカーネルキューのための十分なメモリを割り付けることに失敗しました。
[ EMFILE]
プロセスごとの記述子テーブルが、満杯です。
[ ENFILE]
システムファイルテーブルが、満杯です。

kevent() システムコールは、次の場合に失敗します:

[ EACCES]
プロセスには、フィルタを登録するためのパーミッションがありません。
[ EFAULT]
kevent 構造体を読み込むか、または書き込みでエラーがありました。
[ EBADF]
指定された記述子が無効です。
[ EINTR]
タイムアウトが満了する前に、そして、あらゆるイベントが返りの kqueue に置かれる前に、シグナルが配信されました。
[ EINVAL]
指定された時間の制限またはフィルタが無効です。
[ ENOENT]
修正されるか、または削除されるイベントが、見つかりません。
[ ENOMEM]
イベントを登録するためにメモリが利用可能でなかったか、またはタイマの特別な場合に、タイマの最大数が超過しました。この最大値は、 kern.kq_calloutmax sysctl によって設定可能です。
[ ESRCH]
アタッチする指定されたプロセスが存在しません。

歴史

kqueue() と kevent() システムコールは、 FreeBSD 4.1 ではじめて登場しました。

作者

kqueue() システムと、このマニュアルページは、 Jonathan Lemon <jlemon@FreeBSD.org>によって書かれました。

バグ

timeout 値は、24 時間に制限されています。より長いタイムアウトは、黙って 24 時間として解釈し直されます。
January 21, 2013 FreeBSD