FreeBSDでaio - その2

id:hirose31:20070719:1184773995 の続き)

できた。

  • my_aiocb.aio_sigevent.sigev_notify = SIGEV_KEVENT を使えばおk

その名の通り、kqueue + kevent を組み合わせて非同期I/Oできたす。

  • 必要な大きさのstruct kevent *をまろっくして
  • kqueue()をこさえて
  • aiocbの通知設定をして
my_aiocb.aio_sigevent.sigev_notify          = SIGEV_KEVENT;
my_aiocb.aio_sigevent.sigev_notify_kqueue   = my_kqueue;
my_aiocb.aio_sigevent.sigev_value.sival_ptr = iocb;
  • aio_read or aio_write して非同期I/Oリクエストをして
  • keventでI/O完了したのを取り出して
  • あとは煮るなり焼くなり


若干はまったのは、struct sigeventのメンバがsival_ptrじゃなくてsigval_ptrな点。(Linuxだとgなしのsival_ptrなの)
めんどいんで↓な感じに。(lighttpdからのパクり)

#if (defined(__FreeBSD__) || defined(__DragonFly__))
#  define sival_ptr   sigval_ptr
#endif


あと、1このkeventの配列に、aio_readとaio_writeを混在させたときに、kevent()後にreadとwriteを判別する方法がいまいちわからんかったす。

とりあえず、

    :    :
iocb->aio_lio_opcode = LIO_READ;
rc = aio_read(iocb);
    or
    :    :
iocb->aio_lio_opcode = LIO_WRITE;
rc = aio_write(iocb);

して、kevent()後に

    switch (cb->aio_lio_opcode) {
    case LIO_READ:
      rd_done(cb);
      break;
    case LIO_WRITE:
      wr_done(cb);
      break;
    default:
      TRACE("%s","aio_lio_opcode: unknown case. hmmmmmm.....");
      break;
    }

な感じで判別はできたんだけど、これがいけてる方法なのかよくわからず。


はてなスターTシャツ欲しい!おっお!

Linuxでaio

実装が2つある。以下、あくまで今の時点でのLinuxの場合の状況/実装のおはなし。

POSIX aio

  • aio_read(3) とか aio_write(3), aio_error(3), aio_return(3) とか。
  • インターフェースはPOSIXで定義されているのと同じ。
  • システムコールじゃなくてライブラリ関数(librt)
  • 裏でpthreadつくってがんばってるげ。

libaio

Copy file by using a async I/O state machine.

1. Start read request
2. When read completes turn it into a write request
3. When write completes decrement counter and free resources

Usage: aiocp file(s) desination

    • がーっと読んでがーっと書くんじゃなくて、チャンクにブツ切りにして、読んだら新しいファイルの同じオフセットのところへ書く、というのをチャンクごとにやる。ほんで、このreadとwriteは全部非同期。仮に、おっそいチャンクがあってもほかのチャンクたちは影響ない、おっそいread(やwrite)がいてもほかのチャンクのreadやwriteには影響ない。あ、影響ないってのはいいすぎか。I/Oブロックされてほかの処理に移れないってことがなくなる。
    • イメージ的には、チーズをよってたかってみんなで一斉にちびっとずつ食べる感じ。

POSIX aio vs libaio

libaioはPOSIX aioの高レベルラッパだと思ってたんだけど違かった。どちらも「非同期I/O」だけど実装は別もの。

軽ーく比較したところ、Linuxの場合は、POSIX aioよりlibaioの方が超絶速かった。POSIX aioはライブラリ関数なのに対し、libaioはシステムコールであるというのが一因かも。

移植性優先ならPOSIX aio、性能優先ならlibaioか、な。