mod_wozozo

(この記事は、Pyspaアドベントカレンダー 2016の12/4のコミットを補足する形で書かれました。)

はじめに

皆様ご存知のことと思いますが、OSSコミュニティーにおいて、開発者が結婚する際には、新郎と新婦に

オリジナル○○○○○○○○○○○

を贈呈するという慣習があります。

はい、もちろん

オリジナルApacheモジュール

ですね。

タイムライン

10/3

ハンドルwozozoだしやっぱりOzネタで行くしかないだろうということで、OzのApacheモジュールを実装することにする。

12/4

11:00

起床。全日の京都での披露宴参加からの帰宅で思いのほか疲れており、8時起床予定が大幅にずれる。

11:30

鬼平犯科帳スペシャルを見始める

13:40

鬼平犯科帳スペシャルを見終わる。そろそろアドベントカレンダーのネタ仕込みするかと思い、github.com:mozart/mozart2 をチェックアウト

13:45

ビルドインストラクションを見る。とりま cmake などを入れてみて、 cmake . などする。

13:50

cmake が通らない。自動的に clang とか LLVM とか落としてくると書いてあるのだが... 仕方なく OS (Ubuntu 15.04) のパッケージから LLVM を入れてビルドを試みることに。

14:00

OS のパッケージの clang や LLVM では、なぜかインストールされるファイルの欠損がありビルドができない。Ubuntu 16.10 では直っているようなので、do-release-upgrade を試みる。

14:20

OS のアップグレードが完了したので、ビルドを開始する。

14:30

ビルドに失敗するので、いろいろ調べてみると、ライブラリ付属の cmake ファイルの甘さがいくらかあることが判明。どのオプションが必須なのかを調査する。

14:40

オプションの指定を解明できた。ビルドが走り始める。時間がかかりそうなので、食事に出かける。

15:00

食事から戻る。ビルドは無事完了していた。ランタイムのテストをするため、Oz の言語仕様などを調べ始める。

15:15

古いバージョン (Mozart1) の資料からコピペしてサンプルコードを動かすことに成功。

15:30

標準出力に出力する方法 (System.show) などを学ぶ。

16:00

ソースコードの構成を学びはじめる。

17:00

VMのフロントエンドとしてBoostにプラットフォームの差異を吸収させたboosthost と、それの対になる boostenv というコンポーネントがあることがわかる。この部分で切り出すことでApacheモジュールに組み込めそうだという見込みを立てる。

17:10

Apacheモジュールのひな形を書き始める。apxsはそのまま使えないのでapxsから変数だけクエリしてあとはMakefileでやることにする。

18:30

催促される。

19:00

libtool に -module オプションを渡しても .so が生成できない問題の謎が解ける。 (-rpath オプションが必要だった)

19:30

ひな形にMozart2のコードの一部を組み込んだ形でコンパイルを通すことに成功する。

だが、Mozart2のビルドシステムでビルドされるコンビニエンスライブラリ (最終的なバイナリ生成物である ozemulator を生成するためにビルドの途中で便宜的に作られるライブラリ) は、PIC コードではなかったのでリンクで失敗してしまう。

仕方ないので CMAKE_CXX_FLAGS-fPIC を追加した形で Mozart2 をビルドしなおすことに。ビルドに時間がかかるので食事に出かける。

20:00

食事から戻り、作業再開。すぐにビルドには成功する。

Apacheのconfigから得られた内容をVMの起動パラメータに変換する簡単なお仕事の開始。

21:00

I/Oスレッドの扱いに悩み始める。I/Oスレッドをひとまずpost_configフェーズで起動する形で実装。

22:00

handlerVMを起動させるところまで来る、が、VMが起動しない。デバッグを続ける。

23:40

ドはまりしたが、余計なパラメータを渡していることが原因と判明、修正し、リクエストURIで指定されたドキュメントルート配下のMozart2のバイナリを読み込んで実行することに成功する。しかし、この時点では、まだレスポンスを書き出すことはできていないので、標準エラー出力への実行結果の出力で確かめるのみ。

24:00

Apacheとのつなぎこみを始める。最初の難関である、VMの起動時にVMにrequest_recを渡すという部分への対応を開始する。

25:20

VMのパラメータとして渡しているのは、値渡しのVMIdentifier VirtualMachineOptions型と、 std::unique_ptr<std::string> 渡しのアプリケーションURLのみ。

std::string を継承したクラスを作り、そこに request_rec を突っ込むという強引なやり方で成功する。

25:30

Mozart2 のビルトインプロシージャの作り方を調べる。C++のクラスの実装と、それをビルドシステムのブートストラップでclangのAPIを使ってパースしてスタブを生成するコードから成ることを解明して、スタブを自前で書くことで対応を開始する。

26:00

レスポンスを書き出すビルトインプロシージャを作るには、VM生成時に渡されたrequest_recをプロシージャの文脈で取得できなければならないが、しかし、エントリポイントは、スタティックメソッドである。

VMからビルトインモジュール名を指定してモジュールを取得できそうなことが分かったので、その方法を調べる。

27:10

vm/vm/main 配下のVM内部の実装を読み解き、ようやくモジュールを取得してもコンテキストは取れないので、代わりにビルトインプロシージャのスタブそのものへのポインタを取得する方法しかないことが判明する。

27:40

Apache.Rputs の実装ができ、ブラウザに文字を出力することに成功する。疲弊しきったため風呂に入る。

28:00

1時間ほどの仮眠を試みるが、4時間寝てしまう。

32:00

Ozで何をするかを決めようとする。I/Oスレッドが独立していることから、それが正しく動いていることを確認するためのコードを書きたく、それをそのままネタにすることにする。

32:10

TCPでの通信の方法を調べはじめる。とりあえずApacheの文脈から外れて、Ozでスタンドアロンで通信をするコードを書く。サーバー側はGoで実装した。

33:10

Goで実装したサーバーとの通信に成功する。

33:20

通信した内容をApacheを通じてレスポンスとして返すことに成功する。 ネタを仕込むための実装を始めるため、Ozの標準モジュールについていろいろ調べ始める。

33:40

ちょっとした遊びを実装するため、Apache.Rflush の実装をする。

34:10

通して動くようになる。レポジトリを作成して、push。

34:54

最後に

めでたい。