sjlj-exceptions

意外と簡単に--enable-sjlj-exceptionsなg++でも動くようになりました。
gccのソースを追ったところ、例外ハンドラに関する情報はスレッド固有領域にある、SjLj_Function_Context構造体で管理されていました。
この構造体は、

struct SjLj_Function_Context
{
    struct SjLj_Function_Context* prev;
    ...
};

というようにシングルリンクリストになっていて、スタックの巻き戻しの際にこのリストを辿るようになっています。
これをファイバに対応させるためには、ファイバ切り替えのタイミングでレジスタと同じように保存/復帰させればよいだろうと考えました。
関連する関数でstaticでないものは次の関数です。

// fcをリストの先頭に追加する
// fc->prev には直前の先頭要素が設定される
void _Unwind_SjLj_Register(SjLj_Function_Context* fc);

// fcをリストの先頭から取り除く
// fc->prev が先頭要素になる
void _Unwind_SjLj_Unregister(SjLj_Function_Context* fc);

あとはパズルです。

// 現在の先頭要素を取得する
SjLj_Function_Context* get_current_sjlj_context()
{
    SjLj_Function_Context dummy;

    // dummy.prev に先頭要素が設定されて戻ってくる
    _Unwind_SjLj_Register(&dummy);

    // dummyを取り除く
    _Unwind_SjLj_Unregister(&dummy);

    return dummy.prev;
}

// 別のリストを設定する
void set_sjlj_context_list(SjLj_Function_Context* fc)
{
    SjLj_Function_Context dummy;
    dummy.prev = fc;

    // dummy.prev が先頭要素になる
    _Unwind_SjLj_Unregister(&dummy);
}

実際のコードはもう少し手を加えてありますが、基本的な考え方は同じです。
<hamigaki/coroutine/detail/gcc/sjlj_context.hpp>


これでMinGWでは動くようになりましたが、Cygwinがまだ駄目です。
ファイバ自体は動いているようなのですが、終了時に落ちてしまいます。
ここまでやったからにはCygwinでも使えるようにしたいところですが、どうなることやら。