next up previous contents index
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