- mruby の軽量スレッドである Fiber について、 mruby-fiber/ を読む
- mruby 組み込み型のひとつ
- 実装は割とシンプル
- もともと、 mrb_state, mrb_context が「前のコンテキストに戻る」ことを考慮した作りになっている
- Fiber は mrb_context を持つ。これを mrb_state に対して「次/前のコンテキストに移る」操作を提供することで resume/yield を実現する
- 単なる RiteVM の実行コンテキストを持ってるだけのオブジェクト
struct RFiber {
MRB_OBJECT_HEADER;
struct mrb_context *cxt;
};
- まずは現在の状態をチェック。下記条件にマッチした場合は FIBER_ERROR を raise する
- transfer された後の fiber を resume した
- 実行中の fiber を resume した
- 既に終了した fiber を resume した
- value へ代入しているあたりはよくわからん
- mrb_vm_exec() を介して RiteVM に mrb_context の処理の実行を開始させる
- yield されたら返ってくる。その時の戻り値を取得する
- mrb_vm_exec() 呼び出し前に退避させておいた、 resume 元の mrb_context を mrb_state に戻す
- 最後に戻り値を返して終了
- yield しようとしている fiber が root になっていないかチェック
- root からは yield 先がいない! FIBER_ERROR を raise する
- mrb_state の mrb_context を prev のもの、つまり親ファイバのものに戻す
- fiber_result() で yield クラスメソッドの引数をそのまま親に返す
渡された array? を元に、 nil か一つの値か、あるいは array 全体を取り出す
- MRB_ARGS_NONE であるが実際は block を引数にとる
- block が取れなかったら ARGUMENT_ERROR を raise する
- RiteVM のコンテキストを初期化する
- スタック領域の割当と初期化
- receiver (ってなんだろ)を block からコピー
- callinfo の割当と初期化
- callinfo 周りの調整
- block のポインタをコピーしたり pc を設定したりレジスタ数を設定したり
- ここで設定した callinfo を元に resume されると処理実行が行われるのか
- 最後に fiber の状態を初期化
- fiber は状態を持つ(そりゃそうか)
- コンストラクタが終わった状態では MRB_FIBER_CREATED
- 任意個の引数を受ける
- 実際の実行は fiber_switch() で。。。
- TODO: 気が向いたら読む
- TODO: 気が向いたら読む
- TODO: 気が向いたら読む
- 任意個の引数を受ける
- 実際の実行は mrb_fiber_yield() で。。。
- TODO: 気が向いたら読む
- mrb_context メンバの status で管理される(Fiber以外でもこの変数使ってるのかな・・・?)
- 以下のような状態をもつ
enum mrb_fiber_state {
MRB_FIBER_CREATED = 0,
MRB_FIBER_RUNNING,
MRB_FIBER_RESUMED,
MRB_FIBER_SUSPENDED,
MRB_FIBER_TRANSFERRED,
MRB_FIBER_TERMINATED,
};
状態遷移
- TODO: 詳細確認する