C言語で継続
C言語で継続を実装できるかを考えてみた。もちろん、生のC言語でできるわけがないのだけど、環境を制限すればできないこともない。
前提、setjmp()とlongjmp()について。
setjmp()とlongjmp()の用途はあくまでも大域脱出である。そのため、setjmp()を呼び出した段よりも深いスタックフレームがすべて保存されていなければならない。
OK
stack | setjmp | |||
---|---|---|---|---|
stack | work1 | ... | workN | longjmp |
NG
stack | work1 | ... | workN | setjmp |
---|---|---|---|---|
stack | longjmp |
コピーしよう。
stack | work1 | ... | workN | xsetjmp |
---|---|---|---|---|
stack | xlongjmp |
xsetjmp()はスタックのwork1...N領域をバッファ上にコピーしてからsetjmp()を呼び出す。これでスタックフレームを保存することが出来そう。
xlongjmp()はバッファのwork1...N領域をスタック上にコピーしてからlongjmp()を呼び出す。これでスタックフレームを復帰することが出来そう。
そうは甘くない。
上の手法で継続の復帰をしようとしても上手く行かない。何故かというとコピー先とxlongjmpの作業領域が重なるためにxlongjmp()に失敗するからだ。
問題が作業領域の重なりならば自分で作業領域を作れば良い。例えば、無駄な再帰呼び出しを繰り返すなり、alloca()を使って生成するなり、といった手段がある。
stack | work1 | ... | workN | xsetjmp |
---|---|---|---|---|
stack | xlongjmp | |||
stack | padd1 | ... | paddN | memcpy |
stack | work1 | ... | workN | longjmp |
〆。
一応、POSIX全般で動くはず。sigsetjmpの方が良いかも。