キューの抽象化

nmoshの非同期I/O APIは、今のところ1つの master queue だけを処理できる。通常のOSではkqueueやIOCPのようなI/O多重化キューは同時に1つしか待てないため。
キューにはいくつかの種類がある:

  • Computeキュー。CPU上の関数コールバックやGPUイベントキュー。OpenCLIntel TBB等が該当する。
  • インターフェースキュー。libusb等移植性のあるAPIセットで、そのAPIのみで通用するライブラリローカルなキュー。UNIXシグナルもここに相当する。
  • I/Oキュー。Win32のIOCPやMacOSのkqueueのように、I/Oプリミティブの多重化に特化したキュー。
  • (非多重化ブロック - Mutex/Condvarのような通常の同期オブジェクト、ブロックI/O)

今のnmoshにはI/Oキューだけが実装されている。
重要な制限: 1つのスレッドは1つのキューしか処理できない。nmoshは異なるキューを待っているスレッド同士を連携させるために、キューのwaitを解除させるための共通インターフェースとしてchimeを持っている。キューのプロバイダ(= IOCPやlibusbのようなAPIバインディング)はchime callbackを提供する必要がある。chimeとしてwait解除インターフェースを共通化することで、いわゆるcallbackスタイルの非同期 APIは全てこのキューの仕組みに乗ることが出来る。
chimeのAPIはC APIとして提供される。つまり、chimeはVMスレッド以外からも発火することができる。nmoshは、司令塔としての少数のVMスレッドと多数の(native)ワーカースレッドというスタイルを想定している。Evalが実行時にも自由にできるSchemeの特徴を考えると、言語フロントエンドをスレッドの数だけ常駐させるのはあまり効率的でない。
また、キューは自分の"ネイティブ"リクエストかchimeしか処理できない。Win32のIOCPキューならReadFileやWriteFileであり、POSIXのpollによるキューならreadやwriteとなる。例えばComputeキューにI/Oリクエストを発行することは出来ない。
nmoshはI/Oキューのファイル/ソケット I/Oに関しては共通のライブラリを提供する。他のキューに対する共通APIは提供しない; 例えばいくら性質が似ているからといって、DirectComputeとOpenCLを共通APIでwrapするのはあまり良いアイデアでない。

キューをエンドユーザに見せるか

キューはなるべくエンドユーザに見せたくない需要がある。例えば、Node.jsのような一般的な非同期I/Oスタイルのフレームワークはキューを直接的に見せることを避けている。しかし、この手のデザイン方針には、複数種類のキューをサポートすることが困難になる問題が有る。
一般的に、OSのI/Oキューは、fdやハンドル等のI/Oオブジェクトを一旦キューにbindする必要がある。つまり、kevent syscallやCreateIoCompletionPort等のAPIを一度I/Oオブジェクトに対して発行してから、実際のI/Oリクエストを発行しなければならない。
このため、一度登録したI/Oオブジェクトをスレッド間でやり取りすることは難しく、I/Oオブジェクトは属スレッド(= 属キュー)の資源として管理する必要がある。なのでキューをエンドユーザに全く意識させないことは困難で、"スレッドのデフォルトキュー"を決めることくらいしかできない。
デフォルトキューは最初のI/Oオブジェクトを登録するまでに選ぶ必要がある。例えば、スレッドを作るタイミングで指定させるのはいいアイデアかもしれない。つまり、スレッドを作成する時に、デフォルトキューとなるキューの種類を設定する。(libusb用スレッド、HANDLE処理用のスレッド、...)

メインループを抽象化するか

メインループを抽象化するかどうかも絶妙なポイントになる。例えば、Node.jsのコードでは、readリクエストの結果を処理するcallbackはimplicitに呼ばれる。しかし、Node.jsの基盤となっているlibuvでは明示的にloopを実行するためのrun関数を呼ぶ必要がある( http://nikhilm.github.com/uvbook/basics.html#event-loops )。
一般に、この手のrun関数は、関連付けられたI/Oオブジェクトが全て破棄されるまで返らない。
nmoshの非同期I/Oでよくあるミスとして、このメインループ手続きの呼び忘れがある。このメインループ手続きの呼び出しは通常のシチュエーションではプログラム末尾に常に存在するので、省略できるようにすることには一定の意味が有るように思える。