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の方が良いかも。