C言語で継続2

http://d.hatena.ne.jp/kilrey/20090921#p1で作成した継続は本当に「スタックを巻き戻す」ことしかできない。例えば、外部リソースを再利用できない、といった問題がある。

外部リソースを再利用できない。

下のソースコードでf1()で記録した継続をf2()で巻き戻した場合、ptrを二重free()してしまうというのが問題になる。もちろん、f1()でptrに読み書きするのも危険だろう。

void f0() {
  void* ptr = malloc(0x1000);
  f1(ptr);
  free(ptr);
  f2();
}

これは元々setjmp(), longjmp()が抱えていた問題の変種だ。例外とRAIIとにより元の問題は解決されているが、この問題は解決できていない。GCとRAIIとにより解決することはできるが、ゼロ・オーバーヘッド原則に反しており、わざわざC言語で行うべきものとは思えない。

void f0() {
  void* ptr = GC_malloc(0x1000);
  f1(ptr);
  f2();
}

サンドボックスで解決できないか。

サンドボックスの内部でのみxsetjmp(), xlongjmp()を利用することができる、というように条件を変えてみよう。本来free()を呼んでいた箇所ではサンドボックス終了時に呼び出したい関数とその引数を登録する。これならゼロ・オーバーヘッド原則にも反していないだろう。

void f0() {
  void* ptr = malloc(0x1000);
  f1(ptr);
  on_exit_from_sandbox(free, ptr);
  f2();
}

〆。

まあ、メモリの話に限ってしまえばApache Portable Runtimeのようなメモリプールを使う方が楽だろう。それ以外でも汎用に使えるのが利点ということで。

void f0() {
  FILE* fout= fopen(...);
  f1(fout);
  on_exit_from_sandbox(fclose, fout);
  f2();
}