■
今回の要約: とりあえずGC_oom_fn対策のコードだけ書いた。動作確認とかは帰ってからやる。
今日は、出社する事になった。
先日の優先順位を考えた。
- とりあえず、GC_oom_fn対策が実現可能な事を簡単に確認する
- とりあえず適当に動く、eval/svを作る(大体完了)
- とりあえず適当に動く、eval/memlimitを作る(大体完了)
- とりあえず適当に動く、「安全なeval」が仮完成
- とりあえず適当に動く、非同期入出力のキュー(圧縮機能/優先順位制御機能付き)を作る
- とりあえず適当に動く、コードジェネレータ用の環境を作る
- とりあえず適当に動く、コードジェネレータ用の入出力ドライバを作る
- とりあえず適当に動く、コードジェネレータ用の評価器を作る
- とりあえず適当に動く、コードジェネレータが仮完成
- eval/svを完璧かつ高速で動作するように直す
- GC_oom_fn対策を実装する
- eval/memlimitを完璧かつ高速で動作するように直す
- 「安全なeval」を完璧にする
- 非同期入出力のキュー(圧縮機能/優先順位制御機能付き)を完璧にする
- コードジェネレータ用の環境を完璧にする
- コードジェネレータ用の入出力ドライバを完璧にする
- コードジェネレータ用の評価器を完璧にする
- 完全なコードジェネレータが完成
GC_oom_fn対策は必要不可欠だが、実は、実装可能な事だけ確認したら、後回しにしても良さそうな事が分かった。
しかし、折角なので、この段階で実装してみる事にする。
実装方針は、以下の方針とする。
- 変更部分は#ifdef GAUCHE_EXPERIMENTAL_GC_OOM_FNで囲んで、フラグを与えない場合は元のGaucheとしてコンパイルできるようにする
- ちょっとずつ変更しては確認検証を行い、インクリメンタル開発をする
実装手順は、以下の順序とする。
- Scm_Init()内で、OOM用予備領域を確保するように変更する
- oom_handler()で、OOM用予備領域を解放再利用してからScm_Error()を投げるように変更する
- SCM_MALLOC系マクロを、OOM用予備領域のポインタがNULLになっていたら再確保するように変更する
- OOM用予備領域を使った後、どのタイミングでOOM用予備領域を再確保するか悩んだが、とりあえずSCM_MALLOC系のタイミングにする事にした。
- 再確保する条件は、仮に、元のOOM用予備領域のサイズの二倍の空き領域が確認されたら、という事にする。
とりあえず、このコードは簡単に書いてみた。
コンパイル&実行テスト&全コードのSCM_MALLOCやSCM_NEW等の確認は、帰ってきてからする。
- gauche/memory.h で、素のGC_MALLOC_WORDSを呼んだりしてるのを発見した。
- とりあえずSCM_INLINE_MALLOC_PRIMITIVESは一時的に0にする事にした。ちゃんと動くのを確認してから対策を考える。
- vm.c で、以下の関数が呼ばれている。これらがmalloc類に相当するか調べて、malloc類っぽかったら、それらしく対応する事。
この辺は家に帰ってきてから自分で調べます。
ところで、oom_handler()が、本当にあらゆる場面でScm_Error()を投げて安全だったとしても、「本当にエラー例外を投げるだけでいいのか」という問題がある。
- 単にエラー例外を投げるだけの場合、「単純なconsですらエラー例外が発生する可能性が常にある」という事で、厳密なコードを書く場合、ほぼあらゆる場面でエラー例外が発生する可能性を考えなくてはならなくなる
- 現実的には、そこまで考えなくてもまず大丈夫だとは思うけれど
- じゃあ、どうすればいいのかと言うと、「途中でOOMが発生したevalは信用ならないので、もう途中で中断する」という扱いにするのが妥当?
- ok。じゃあ、Scm_Eval直後で、脱出用継続を保持しといて、oom_handler()からそれを辿る事にしよう。
- ところで、OOMが発生する直前とかに、eval内からeval外の変数に継続をset!されてたら、せっかく抜けても、またevalが再実行されそうなんだけど?
- それと、継続を使って抜ける場合は、dynamic-windのafter thunkが実行される気がするけど、いいの?
- 仮に無理矢理dynamic-windのafter thunkを実行せずに抜けたとして、Scheme的にはそれでいいの?
- 例えば、さっきの、eval外の変数にset!された継続を辿って再突入した場合、after thunkは実行されてないのに再度before thunkは実行される事になるけど、これって、beforeとafterの対応が取れなくなるよね?
- 仮に無理矢理dynamic-windのafter thunkを実行せずに抜けたとして、Scheme的にはそれでいいの?
等と、考えた結果、やっぱりエラー例外しかないように思えてきた。
そもそも、OOMのScheme的セマンティクスって、どんななんだろう。
とりあえず無限エクステントと相反してる気はする……。
そう考えると、現在のGaucheの「いきなりScm_Panic()で終了」というのは、かなり正しいように思える。
思えるが、それだと「安全なeval」は実現できない……。
Scm_Cleanup()を呼ぶのもアリそうだけど、これもやっぱり「安全なeval」には使えなさそうだ。
とりあえず、帰ったら動くかどうか試そう。