libeioのサンプルコード

「libeio」は、C言語で書かれた非同期I/Oライブラリです。
実装的には、キューとスレッドプールを使い、I/Oを非同期並行処理します。
先程の「Boost application performance using asynchronous I/O」の図の右下(Asynchronous + Non-blocking)に「libeio」は位置するのではないかと思います。

  • libeioのサンプル

以下、libeioに含まれるdemo.cから抜粋したサンプルです。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <poll.h>
#include <string.h>
#include <assert.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "eio.h"

int respipe [2];
int last_fd;

// EIOスレッドで実行される
void want_poll (void) {
    char dummy;
    printf ("want_poll ()\n");
    write (respipe [1], &dummy, 1);
}

// EIOスレッドで実行される
void done_poll (void) {
    char dummy;
    printf ("done_poll ()\n");
    read (respipe [0], &dummy, 1);
}

// mainスレッドのイベントループ
void event_loop (void) {
    struct pollfd pfd;
    pfd.fd     = respipe [0];
    pfd.events = POLLIN;

    printf ("\nentering event loop\n");
    while (eio_nreqs ()) {
    	// イベントを待つ
        poll (&pfd, 1, -1);
        // mainスレッドでeio_poll()を実行する。
        printf ("eio_poll () = %d\n", eio_poll ());
    }
    printf ("leaving event loop\n");
}

// mainスレッドで実行される
int res_cb (eio_req *req) {
    printf ("res_cb(%d|%s) = %d\n", req->type, req->data ? req->data : "?", EIO_RESULT (req));
    if (req->result < 0) perror(req->errorno);
    return 0;
}

// mainスレッドで実行される
int read_cb (eio_req *req) {
    unsigned char *buf = (unsigned char *)EIO_BUF (req);
    printf ("read_cb = %d (%s)\n",
            EIO_RESULT (req),
            buf);
    return 0;
}

// mainスレッドで実行される
int open_cb (eio_req *req) {
    printf ("open_cb = %d\n", EIO_RESULT (req));
    last_fd = EIO_RESULT (req);
    return 0;
}

int main (void) {
    printf ("pipe ()\n");
    if (pipe (respipe)) abort ();

    printf ("eio_init ()\n");
    // libeioにwant_poll()とdone_poll()を登録。
    // libeioがpollして欲しいときに、このwant_poll()が呼び出される。
    if (eio_init (want_poll, done_poll)) abort ();
    do {
    	// eio_open()呼び出し後、メインループを実行する。
        eio_open ("eio-test-file", O_RDWR | O_CREAT, 0777, 0, open_cb, "open");
        event_loop ();

    	// eio_write()呼び出し後、メインループを実行する。
        eio_write (last_fd, "aaaaaaaaaa", 10, 0, 0, res_cb, "write");
        event_loop ();

    	// eio_read()呼び出し後、メインループを実行する。
        eio_read (last_fd, 0, 8, 0, EIO_PRI_DEFAULT, read_cb, "read");
        event_loop ();

    	// eio_close()呼び出し後、メインループを実行する。
        eio_close (last_fd, 0, res_cb, "close");
        event_loop ();
    } while (0);
    return 0;
}

libeioもlibevと同様に事前にインストールが必要です。libeioのソースコードは、Node.jsのdeps配下にあります。

$ cd libeio
$ ./autogen.sh
$ ./configure
$ make
$ make install
  • 共有ライブラリのパスに「/usr/local/lib」を追加する。
$ sudo ldconfig

eio-test-fileを作成モードで開き、write(2)とread(2)を実行し、close(2)します。
libeioは、スレッドプールにより並行処理します。mainスレッドとEIOスレッドで通信を行うために、eio_init()で、libeioがpoll通知できるようにします。

mainスレッドから、eio_open()等のeioのI/O関数が呼ばれると、キューにたまります。
EIOスレッドは、キューから取り出して、システムコールを実行し、結果をキューに返して、eio_poll()を呼び出すようmainスレッドに通知します。

mainスレッドがeio_poll()を呼び出すと、事前に設定していた関数がコールバックで呼び出されます。コールバックは、mainスレッドで行われます。