Boost.Contextの微妙なところ

Boost.ContextのAda移植をしてたのですが、Boost.Contextオンリーイベントに間に合わずに完全に無駄に終わってしまいました。めでたしめでたし。

一応テストをパスするところまで→ https://gist.github.com/2342019 ……ただしこのエントリには全く関係ない!

で、その過程でいくつか不審な点を見つけて、オンリーイベントでも騒いでみたのですが、結局動作に問題はないということが判明しただけでした。問題はないのでバグ報告どやぁ、なんてこともできないのですが、微妙なことに変わりはないし放置も悔しいので残しときます。

ただの愚痴です!真に受けないでください!


http://svn.boost.org/svn/boost/trunk/boost/context/stack_allocator.hpp

このstack_allocatorは、標準のアロケータ互換のインターフェースを持ってますが、確保したスタックの先頭(つまり確保したメモリの最後尾)を返します。つまり、互換性がありません。スタック用アロケータはtemplateの引数になってはいるものの、間違ってstack_allocator以外の(標準準拠の)アロケータを渡したらえらいことになります。

http://svn.boost.org/svn/boost/trunk/libs/context/src/fcontext.cpp

boost_fcontext_align ……>> 4) << 4)は普通& ~15と書くと思います、最適化されるらしいですけど。で、それよりも-16。アライメントされてない領域をcontextのスタックとして使おうとすると、16バイト無駄に消費されます。この処理はcontextひとつにつき1回だけですので大したこと無いといえば無いんですが。
ちなみにデフォルトではスタックは上記stack_allocatorが割り当てます。こいつはページ単位で割り当てを行うので、アライメントは守られてるはずです。つまりカスタムアロケータを使わない限り関係ないです。

http://svn.boost.org/svn/boost/trunk/libs/context/src/stack_allocator_posix.cpp

stack_allocator::allocate ……Macの時に、開いてるfdが無駄。っていうかLinuxでもMAP_ANONYMOUS使えますよね?

http://svn.boost.org/svn/boost/trunk/libs/context/src/stack_utils_posix.cpp

page_count ……メモリサイズの計算にfloatて。(stacksize + pagesize() - 1) / pagesize()でいいじゃないですか。あとfloatの有効桁数から2^23=8MB以上で2の乗数ではないページサイズを持つ環境だと誤動作しますね。Boost.Contextのサポート範囲にはそんな環境無いですけど。

その他

ucontextではなく独自実装の理由は、POSIX仕様ではucontextが廃止予定だからだそうですしかしWindowsだとFiber使わない理由は何もないと思います……あ、BOOST_CONTEXT_FIBERを発見。作業中?

独自実装の場合一番気になる点としましては、例外とかシグナルとか大丈夫でしょうか?一応例外はちゃんと対応してるっぽいですが、あくまでOSレベルでの話。言語ランタイムが例外の状況をTLSに確保してたりすると恐ろしいことに。g++は知りませんがGNATは確実に衝突します。逆にgcjは例外オブジェクトの開放もGC丸投げで特別な管理はしてませんので恐らく大丈夫でしょう。またシグナルについては全く対応無しです。え?例外やシグナルの発生中にコンテキストの切り替えなんかするほうが悪い?

例外といえばドキュメントにはforced_unwindをcatchするなと書かれてますが、unwind.hの関数を使ってC++の例外とは別のコードで投げるようにすればcatch(...)も通過できて良いのではないでしょうか。でも面倒ですので私でもきっとやらない。第一C++から受け止められないですし……。*1

あと更にどーでもいいですが、fcontext.hppはdetail側でいいような?名前空間の階層をそのままAdaのパッケージ階層に対応させようとするとlimited withを使うことになるので若干面倒なことに……いやまあどーでもいいです。モジュールがない言語はこういうのいい加減でも全く困らないから。

あと偽pimplのせいで移譲コードだらけで移植してて指が痛いやなんでもないですすみません。

いやもう-16が何やってるのか突き止めるために熱が入ってしまって、単なるイチャモンです。

*1:Dwarf2 ZCXを受け止める労力>>>>>>コルーチンを実装する労力です。まずパーソナリティ関数を書く必要がありますし、そのパーソナリティ関数を使って例外を受けるにはアセンブラが必要です。その上でSJLJ例外にまで対応するとなると、もう言語ランタイムを作っているのと変わらないってのは言い過ぎですね。