NAME
ibv_req_notify_cq - Completion queue (CQ) に completion notification を要求する。
ibv_get_cq_event, ibv_ack_cq_events - Completion queue (CQ) events を取得・承認(acknowledge)する。
SYNOPSIS
#include <infiniband/verbs.h> int ibv_req_notify_cq(struct ibv_cq *cq, int solicited_only); int ibv_get_cq_event(struct ibv_comp_channel *channel, struct ibv_cq **cq, void **cq_context); void ibv_ack_cq_events(struct ibv_cq *cq, unsigned int nevents);
DESCRIPTION
ibv_req_notify_cq()
は cq が completion notification が発生するように要求する。
ibv_req_notify_cq()
は以降、cq に新しい CQ Entry(CQE) が追加された時、CQ に関連付けられた completion channel に CQ が追加される。
solicited_only は、0 または非 0 を指定する。 これは completion notification を発生させると CPU に負荷が掛かるため、発生条件を絞ることのできる機構である。
- solicited_only が 0 の場合、全ての CQE を completion event とする。
- solicited_only が非 0 の場合、solicited(応答型)の CQE のみを completion event とする。 Solicited completion event とは、全ての完了エラーと、send_flags は IBV_SEND_SOLICITED をセットして ibv_post_send() したメッセージの成功した完了である。 送信側の成功した完了と、IBV_SEND_SOLICITED がセットされていないメッセージを受信した完了は含まれない。
ibv_get_cq_event()
は completion event channel channel から完了イベント(completion event)が到着するまで待機する。
ibv_get_cq_event()
の呼び出しに成功した場合、完了イベントが 1 個だけ取得し CQ へのポインタを cq の領域へ、ibv_create_cq() の引数 cq_context として渡した値を cq_context の領域へコピーする。
失敗した場合は、完了イベントの取得なしで ibv_get_cq_event()
の呼び出しから復帰する。
ibv_ack_cq_events()
は CQ cq の nevents 個のイベントを承認する。
cq には ibv_get_cq_event()
によって取り出した CQ へのポインタを指定する。
nevents には cq を ibv_get_cq_event()
によって取り出した回数を指定する。
Completion event channel に関しては、「InfiniBand プログラムに必要な基礎知識」 8.1 Completion Channel と 「まず InfiniBand Verbs プログラムを作成してみよう」 8.2 Completion Channel を使ってみるを参照のこと。
完了イベントとは、端的に言って完了を受け取った CQ のことである。
RETURN VALUE
ibv_req_notify_cq()
は成功した場合、0 を返す。
失敗した場合は、エラーの原因を示す値(errno と同じ)を返す。
ibv_get_cq_event()
は成功すれば 0 を返す。
失敗すれば -1 を返す。
ibv_ack_cq_events()
には戻り値はない。
ERRORS
ibv_get_cq_event()
は仕様に明記されていないが、-1 で返ってきた場合 errno にエラー原因が登録されている。
EINTR | シグナルによる割り込みが入った。 |
EAGAIN | (channel->fd をノンブロッキングモードに設定している場合) 取り出し可能な非同期イベントがない。 |
errno の利用は仕様外なので、自己責任になる。
NOTES
Notification の要求は "ワン ショット" である。
1 回 CQ に ibv_req_notify_cq()
を設定した後は、1 個の completion event しか発生しない。
ibv_get_cq_event()
で取り出した完了イベントは必ず ibv_ack_cq_events()
を使って承認する必要がある。
ibv_get_cq_event()
で取り出した CQ を破壊する操作(ibv_destroy_cq(3))を実行すると、ibv_ack_cq_events()
が呼ばれるまで待機することになる。
これは InfiniBand Verbs 内での競合を避けるためのガード機構である。
逆に言うと cq が指す CQ に触ってよいのは、ibv_get_cq_event()
で取得した後、ibv_ack_cq_events()
を呼び出す前までである。
ibv_ack_cq_events()
が呼ばれた後は、CQ は破壊されメモリ領域が回収されている可能性がある。
ibv_ack_cq_events()
の呼び出しは、内部で mutex を呼び出すなど比較的重い処理である。
そこで同一の CQ に対して複数回 ibv_get_cq_event()
で取り出して置き、ibv_ack_cq_events()
はまとめて 1 回だけ呼び出すという最適化をすることができる。
EXAMPLES
channel->fd をノンブロッキングモードに設定するには以下のコードのように fcntl()
を設定する。
static void channel_change_blocking_mode(struct ibv_comp_channel *channel) { int ret, flags; flags = fcntl(channel->fd, F_GETFL); if (flags < 0) { perror("fcntl(channel->fd, F_GETFL)"); exit(EXIT_FAILURE); } ret = fcntl(channel->fd, F_SETFL, flags | O_NONBLOCK); if (ret < 0) { perror("fcntl(channel->fd, F_SETFL, flags | O_NONBLOCK)"); exit(EXIT_FAILURE); } }
ノンブロッキングモードに設定以降は ibv_get_cq_event()
もブロックせず、取り出し可能な非同期イベントがない場合は -1 で復帰し、errno に EAGAIN が設定されるようになる。
完了イベントの到着は channel->fd が ready-to-input になるタイミングを select()
や epoll()
で待ち合わせることができる。
channel->fd が "ready" になった後は、ibv_get_cq_event()
を呼び出すと最低 1 つは完了イベントを取り出すことができる。
SEE ALSO
InfiniBand Verbs API Reference、ibv_create_comp_channel(3)、ibv_create_cq(3)、ibv_poll_cq(3)
AUTHORS
原文 Dotan Barak <dotanba@gmail.com>
原文にない加筆がある。