週刊nmosh - x64対応復活 / 寝ているスレッドの起こし方 / groonga

MSBuild に "VCTargetsPath" プロパティの値が含まれていません。』病に悩む。Visual Studio2012(Visual Studio 11時代)のベータ版をアンインストールすると起こるようになるらしい。

ここにある通りレジストリを2箇所追加したら治った。

x64対応

永らく上手く動いていなかったWin64ビルドを一応動くように直した

他のportへの影響は今チェック中。。
一番微妙なのはGMPで、GMPにはuint64_tやlong longを直接操作するAPIが用意されていないので、Win64では64bit値を直接操作する方法がない。importとか演算を駆使してどうにかする必要がある。
Win64ではFFIは使えないが、nmoshのPFFIは問題なく使えるのでWin32/64では本来のFFIには依存しないように実装しなおした。

寝ているスレッドの起こし方

今回、Groongaサポートの一貫として"chime"の仕組みをPFFIに入れた(POSIX fdサポートはまだ)。chimeはコールバックとコールバックに渡すパラメタのペアで、要するに"寝ているスレッドを起こす"仕組みを抽象化したものといえる。
...一般に寝ているスレッドを起こす方法というとCondition variableのような仕組みが思い当たるが、実は今のところnmoshの非同期I/Oではcondition variableで寝ているものは無い。
寝ているスレッドを起こす方法は幾つかある。

重要なのは最後のフレーズで、実はWin32/SolarisのIOCP以外、結果ポインタを渡せないという罠がある(ただしself-pipeはポインタ自体をpipeに書き込むという方法で一応ポインタを渡せる)。つまり、IOCP以外の仕組みはスレッドを起こすことにしか使えないので、更にpthreadなり何なりの同期機構を使って、キューからデータを取ってくるようにする必要がある。
IOCPではポインタ(と、少なくとも32bit値)を渡すことが出来るので、他の同期機構に頼る必要はない。もっとも、常識的なpthread実装は待たない時はsyscallを起こさないので、これは大きな問題でない。
これらの仕組みは元々カーネル→ユーザ通知を実現するための仕組みで、nmoshで言えば非同期I/Oの完了イベントとして使われるのが普通の使い方となる。PFFIのようにFFI関数の終了通知に使うのは少々アウトローな使い方になるが、EVFILT_USERの出自がGCD対応であったようにユーザ間での操作もそれなりに有効性がある。つまり、あるスレッドが待っているのが大量のファイルデスクリプタ/その他カーネルオブジェクトで、多少のユーザイベントを待ちたいなら有効な方法と言える。
大量のユーザイベントを待ちたい - 例えば演算をマルチスレッドに分割して結果を統合したいなら通常のスレッドライブラリを使うべきということになる。
言い換えれば、nmoshはqueueとして以下の2種類を想定しないといけない。

  • IOCPやselect/poll/keventによるファイルI/O待ち
  • WaitForMultipleObjectsやpthreadのようなユーザオブジェクト待ち

今のところnmoshは前者のI/Oイベント待ちをio-master-queueとして定義し、こちらしかサポートしていない。つまり、nmoshのスレッドが寝るとき(nmoshは今のところVMマルチスレッドを想定していないので、これはVMが寝る時ということになる)は必ず何らかのI/Oを待つことになる。
nmoshのchimeのように、汎用のコールバックとしてスレッドを起こすルーチンを抽象化することで、FFIライブラリは任意の方法で寝ているスレッドを起こすことができる。ただし、chimeは全ての"寝方"に対応したものが別々に必要になる。

Groonga

タスク管理ツールのDBとしてGroongaを選定して、一応サポートを入れた。

Groongaはカラム指向DB付きの全文検索DBで、今回の用途にはバッチリと言える。ただ、Groongaはちょっと大げさな気がするので(デフォルトのDBは128MB食う)、Scheme側でカラムDBを実装してそのうち置き換えるつもり。特に組み込み用途は全く想定していないので、32bit環境ではあまり実用的でないように思える。
Groongaは文字列を入力してJSONを返すインターフェースを持っているので、nmoshのバインディングはそれを利用している。
ちなみに、Groongaの前身のSennaはminischemeベースのVMを内蔵してクエリ言語実現していたが、GroongaではECMAScript風の自前の評価器を持っている。この評価器をVisual Studioでビルドすると恐ろしく時間が掛かるので、手元では最適化を切っている。。

  • lib/CMakeLists.txt
if(MSVC)
    set_source_files_properties(
        FILES
        expr.c
        PROPERTIES
        COMPILE_FLAGS /Od)
endif()

地味に/O0(ゼロ)でなく/Odなのが罠な気もする。