Lua 4.7 – Handling Yields in C の yasuoka 訳
コルーチンをイールドするために、内部では、Lua は C の longjmp 機構を用いる。このため、ある関数 foo がある API 関数を呼び出し、この API 関数がイールド(直接でもイールドする別の関数を呼び出すことで間接でも) すると、longjmp は C スタックからフレームを削除するため、Lua は foo に二度と戻れなくなる。
この種の問題を回避するため、API 呼び出し越しにイールドしようとすると、lua_yieldk, lua_callk, lua_pcallk の三つの関数を除き、Lua はエラーを発生させる。これらすべての関数は、k と呼ばれるパラメータとして「再開(continuation)」関数を受け取る。
再開を説明するために文言を定める必要がある。Lua から呼ばれるある C の関数があり、これを「原関数(original function)」と呼ぶ。この原関数は、続いてこの3つ関数の一つを C の API で呼び出し(これを「呼出先関数(callee function)」と呼ぶ)、これにより現在のスレッドをイールドする。(これは呼出先関数が lua_yieldk() の場合と、または呼出先関数が lua_callk() また lua_pcallk() でその呼ばれる関数がイールドする時に発生しうる)
走行中のスレッドが呼出先関数を実行中にイールドすることを考える。スレッドが再開したのち、呼出先関数の走行が終了するだろう。C スタックのフレームはイールドにより破壊されているため、しかし呼出先関数は原関数に戻ることができない。この代わりに、Lua は「再開」関数を呼び出し、呼出先関数をパラメータとして与える。名前が示唆するように、再開関数は原関数のタスクを継続しなければならない。
Lua は、再開関数をあたかも原関数であるように扱う。再開関数は原関数から同じ Lua スタックを、呼出先関数から戻った同じステートで受け取る。(たとえば lua_callk 関数の後は、その関数と引数はスタックから削除され呼出の結果に置き換えられる) また、同じ upvalue も持っている。返却されるものは、何であれ、あたかも原関数からの戻りだっかのように扱われる。
Lua ステートにおける原関数と再開関数の唯一の違いは、lua_getctx() を呼び出した結果である。