小ネタ3つ。

いくつかWin32対応を入れたchibi- scheme 0.8.0がリリースされた。 組込み言語として現状欠けているのは Win64 サポートなのでどうしたもんか考え中。bignumさえ無ければどうにでもなる気がするけど、chibi- scheme のbignum実装はfixnum * fixnumを格納できる整数型が言語に存在することを前提にしていて、 Win64 のようにfixnumで64bit巾整数を使ってしまうと、もう処理系の整数型でbignumの期待を満たすものがなくなってしまう。( gcc はint128_tが使えるため64bit アーキテクチャ でも アーキテクチャ のword * wordを直接処理できる。) 簡単には演算を全てマクロなりインライン関数でwrapしてしまうというのが考えられるけど、元の gcc 実装のパフォーマンスに影響せずに置き代える方法が見つからなかった。当然メンテナンス性にも影響する。 もう一つは Win64 ではfixnumを32bit巾に縮小するという手が考えられるが、chibi- scheme 内部では言語ポインタをfixnumで表現できることを前提にしている箇所がいくつか有るため諦めた。 gcc 専用の機能は一度依存するとなかなか抜け出せなくなってしまうのが絶妙と言える。yuniもネスト関数を使ってコールバックにコンテキストを渡すことを検討していた時期があった。

SagittariusがMinGWでもビルドできるようになったので試してみたが、ちょっと自分の実力では安定して動作させられそうにないので諦め気味。。

hg-gitからhgにコミットする？

実はできると勝手に思っていたが、hg-gitミラー( https://github.com/ktakashi/sagittarius-scheme )の作業をhgに戻す簡単な方法は無さそう。hg-gitはgitリポジトリからは常に一意なhgリポジトリを作るが、hgリポジトリをgitに変換したリポジトリを取り込んでも一意なリポジトリには戻らない(git-svnと異なりコミットログに入っているメタデータを認識しない)ため素直にhg上で作業する(Gitとのコマンド対照表が https://www.mercurial-scm.org/wiki/GitConcepts に有る)か、hg-gitミラーでの作業をgraftによって持ってくるかという方法になる。

今回はpull request( https://bitbucket.org/ktakashi/sagittarius-scheme/pull-requests/11/win32-fix-mingw-build-with-mingw64-native/diff )をGitで作ったコミットをgraftで持ってくるという手法で送信したが普通にdefaultブランチに誤爆したので公開されるコミットはhgで作業した方が良いだろう。。

Sagittariusの拡張モジュールはWin32上では何故かC++でコンパイルされている。MinGWでこれをやると依存DLLが増えてしまう(あるいは明示的にstatic linkさせる必要がある)ためどうにかしたいところ。

拡張モジュールは以下のようなコードを持ち:

#ifdef __cplusplus extern "C" { #endif extern __declspec(dllimport) void * Sg_ProcedureClass; #ifdef __cplusplus }; #endif struct tmp { void * addr; }; struct tmp check = { &Sg_ProcedureClass + 7 };

Windows上では、このコードはC++ではビルドが通り、Cではビルドが通らないという結果になる。

Microsoft(R) C/C++ Optimizing Compiler Version 19.11.25547 for x64 Copyright (C) Microsoft Corporation. All rights reserved. check.c check.c(14): error C2099: 初期化子が定数ではありません。

これはdllimportを付けたオブジェクトは定数とは見做されなくなる制約に依る。C言語では静的変数の初期化は定数で行わなければならないが、C++ではコンストラクタが使用できる(ため定数でなくて良い)。

One drawback to using this attribute is that a pointer to a variable marked as dllimport cannot be used as a constant address. However, a pointer to a function with the dllimport attribute can be used as a constant initializer; in this case, the address of a stub function in the import lib is referenced. On Microsoft Windows targets, the attribute can be disabled for functions by setting the -mnop-fun-dllimport flag.

というわけで単にdllimportを止めるか、DLL/.soを超えた変数の参照を行わないようにする必要がある。chibi-schemeやyuniは拡張モジュールからは初期化用APIをエクスポートし、ロード時に明示的に呼び出す方式にしている。関数のみを動的モジュールとの交信に使用するのは歴史的事情に依る: 遅延ロードや呼び出しのhookといった処理は関数の呼び出しの方が適用しやすい。

低確率でextlibsのテスト中に刺さる

1/20くらいの確率でテスト中に固まる現象がMinGWでビルドしたデバッグ版でのみ発生する。何らかの理由でSg_WaitWithTimeoutが無限待ちになっているような気がするが原因不明。

Visual Studioで見たparallel stack。(VSはDWARFが読めないためシンボルはあまり正しくない - 周辺の適当なDLLシンボルを出している)



Sagittariusは条件変数の絶対時刻タイムアウト(pthreadのもの)をsleepに使用しており、Windows上でもCritical Sectionを使用して条件変数をエミュレートすることで同じようなロジックを実現している。絶対時刻タイムアウトはタイムアウトの設定の瞬間にシステム時刻が変動すると待ち時間が一緒に変動するという問題があり、原理的には待ち時間が異常になる可能性はある。

Windows APIは相対時刻を取るため、Sagittarius自身の移植層でAPI呼び出し前に相対時刻に変換しなおしている。そもそも、実際にはLinuxのような他のOSでも内部で相対時刻に変換しているためこの挙動自体はWindows固有では無いとも言える。。(例えば、Linuxのプリミティブであるfutex(2)はnanosleep(2)と同じような相対時刻を取る。)