Next: Timer
Up: 中断、失敗処理: interrupt_goal
Previous: 関数型仕様
この関数に制御が移された時の状況、および、対応する処理については、
第3.4章 (
ページ) に記述した通りである。繰り返すと以下のようになる。
- 他にすべき処理が生じた時:
- この場合には、reasonp には 0が
セットされている。この場合には、resumed_goals にgoalを格納し、
他の処理をすべくreturnする。
- 述語が「失敗」したとき:
- この場合にはreasonpは中断スタック
の底を指している。
失敗の処理(関数do_fail())が呼び出される。
- 述語が「中断」しそうなとき:
- これまでの説明で判明したように、KLICでは、3段以上REFの連鎖がある場合には
コンパイルコード中では追跡をあきらめ、interrupt_goal の呼び出しを行って
いる。
この場合には、「中断原因の候補」は中断スタックに積まれているので、
それを調べ、候補が全て真に未定義変数であれば中断処理を行う。
候補のいずれかが具体値であることが判明すれば、resume_same_prio()関数
により、当該ゴールを「再開」する(つまり、エンキューしてしまう)。
これらに相当する処理を、interrupt_goal 内で行っており、
その内容を処理順に従い詳説する。
- 1.
- まず、中断スタックポインタreasonp
が 0であるかどうか検査する。0の場合には、
(擬似的に)heap溢れがおきており、GC要求または例外要求が起きている。
その場合には、現在実行中のゴールを、resumed_goals に接続する。
- 2.
- 中断スタックが空であれば失敗したことを
表わしているので、終了する。
中断スタックが空でない場合には、内容にある中断要因を調査する。
中断要因を手繰った結果、実は具体値であったことが判明した場合には、
ゴール引数を手繰った結果に置換し、現在実行中のゴールを再度実行する
(resume_same_prio())。全ての内容が未定義変数であることが分れば、
真に中断すべきゴールであるので、次の処理に進む。
- 3.
- トレースサポートのシステムであれば、stepping_flag,
trace_flag がONの場合、各々、step_susp(), trace_susp() を
呼びだす(
ページ、第8.5.3章参照)。
- 4.
- ゴールを中断させる処理を行う。
- (a)
- ゴールレコードに現在の優先度を記録する。
- (b)
- 再度中断スタックの内容を1つづつ手繰る。
一重ループの変数(つまり、純粋未定義変数)であることがわかれば、
中断レコードを作り、中断要因となった未定義変数とポインタを張り合う。
- (c)
- 二重ループの変数であれば、そこには、中断ゴール/consumer群、または、
generatorがぶらさがっている。この判断はマクロ
is_generator_susp()で行うことができる。
- 中断ゴール/consumerがぶらさがっていることがわかれば、
その中断レコードの先に現在実行中のゴールもぶらさげる。
- Generatorの場合には、
objectに対して、generateメソッドを発行する。
これはマクロgeneric_generate()で行うことができる。
- 結果がmakecons(0)(つまり、consタグでVALUEが0)であれば、
これは「generate遅延」を意味するので、suspendメソッド(generic_suspend()) を
発行する。その結果がmakeref(0)以外であれば、このジェネレータにより
具体化が行われたことになる。そこで再実行するため、flag redo_requestを
onにする。
makeref(0)以外であれば、なにもしない。
- 結果がmakecons(0)以外であれば、「その値で変数は具体化される」ことを
意味するので、変数を戻り値で具体化し、再実行をするため、redo_requestを
onにする。
- (d)
- 以上の処理を中断スタック中の変数すべてに行ったらredo_requestを参照し、
onであれば resume_same_prio() により再実行する。
Sekita Daigo
1998-05-18