POSIX準拠の非同期I/O

これは、ライブラリ関数として実装されており、以下の関数群を持ちます。

aio_read(),aio_write(),aio_fsync(),aio_error()
aio_return(),aio_cancel(),aio_suspend()

詳しい使い方は説明しませんが、aio_read(),aio_write()を使い、I/O要求を発行します。I/O要求は、それぞれの関数中で要求を発行した段階で復帰してくれます。

では次のような、aio_readを行うプログラムを書いて、このライブラリ関数がどのように実装されているかを見てみます。aio_readの動作が見たいだけなので、たぶん、この非同期I/Oライブラリの使い方としては、だめだめです。

#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
#include <aio.h>

#define _POSIX_PRIORIZED_IO

int main(int argc, char** argv)
{
        int fd;
        void* buf;
        struct aiocb aioc;

        if ((fd = open(argv[0], O_RDONLY)) <= 0 ){
                return -1;
        }

        if ((buf = malloc(1024 * 1024)) == NULL) {
                close(fd);
                return -1;
        }
        aioc.aio_fildes = fd;
        aioc.aio_buf = buf;
        aioc.aio_nbytes = 1024 * 1024;
        aio_read(&aioc);

        free(buf);
        close(fd);
        return 0;
}

これをsample_aio.cとして、次のようにコンパイルします。

gcc -o sample_aio.o -g -lrt sample_aio.c

で、これをgdbで、ブレークポイントをmainにし、aio_readが実行されるまで、ステップ実行していきます。

$ gdb ./sample_aio.o
GNU gdb 6.4.90-debian
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".

(gdb) b main
Breakpoint 1 at 0x8048498: file sample_aio.c, line 17.
(gdb) start hoge
Breakpoint 2 at 0x8048498: file sample_aio.c, line 17.
Starting program: /home/taka/io/file_io/sample_aio.o hoge
Failed to read a valid object file image from memory.
[Thread debugging using libthread_db enabled]
[New Thread -1209805120 (LWP 2258)]
[Switching to Thread -1209805120 (LWP 2258)]

Breakpoint 1, main (argc=2, argv=0xbf955a34) at sample_aio.c:17
17              if ((fd = open(argv[0], O_RDONLY)) <= 0 ){
(gdb) s

21              if ((buf = malloc(1024 * 1024)) == NULL) {
(gdb)
25              aioc.aio_fildes = fd;
(gdb) s
26              aioc.aio_buf = buf;
(gdb)
27              aioc.aio_nbytes = 1024 * 1024;
(gdb)
28              aio_read(&aioc);
(gdb) s
[New Thread -1208419408 (LWP 2261)]
30              free(buf);

New Threadというメッセージがでて、スレッドが生成されているのがわかります。aio_read()は、スレッドを生成し、その中で通常のI/O要求を発行することによって、非同期でI/Oを行っているのです。

実をいいますと、POSIX準拠の非同期I/Oの簡易的な実装は、スレッドによって実装されているのは、詳解Linuxカーネルで説明されているのですが、実際どうなっているのか、gdbで確認いたしました。ふつうは、こういうのを確認するにはstraceを使うのがよいのでしょうが、ライブラリ関数等を読み込むところも表示されるので、あえてgdbにしました。また、コンパイル時につけている、rtというのは、たしかリアルタイムスレッドのライブラリです。