IBV_REQ_NOTIFY_CQ(3), IBV_GET_CQ_EVENT(3), IBV_ACK_CQ_EVENTS(3)

作成日:2014.05.10
修正日:2014.05.31

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 に負荷が掛かるため、発生条件を絞ることのできる機構である。

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 cqnevents 個のイベントを承認する。

cq には ibv_get_cq_event() によって取り出した CQ へのポインタを指定する。

nevents には cqibv_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 で復帰し、errnoEAGAIN が設定されるようになる。

完了イベントの到着は channel->fd が ready-to-input になるタイミングを select()epoll() で待ち合わせることができる。 channel->fd が "ready" になった後は、ibv_get_cq_event() を呼び出すと最低 1 つは完了イベントを取り出すことができる。

SEE ALSO

InfiniBand Verbs API Referenceibv_create_comp_channel(3)ibv_create_cq(3)ibv_poll_cq(3)

AUTHORS

原文 Dotan Barak <dotanba@gmail.com>
原文にない加筆がある。

コメント

コメントを書き込む

TOP    掲示板    戻る
Written by NAKAMURA Minoru, Email: nminoru atmark nminoru dot jp, Twitter:@nminoru_jp