Pen
pen build fooしてみた
./.pen/default/
.turtle/
archives/
.aだけがある
objects/
.bcとか.oがある
packages/
pen_ffi/
pen_os/
pen_prelude/
git cloneしてきたもの?
scripts/
*.ninjaがある(生成された?)
osパッケージ(非同期版)とos-syncパッケージ(同期版)があるとのこと
非同期版ではtokio-mainから_pen_mainをよぶ
そのあと50ms待っている…
Rust関数をPen側にエクスポートする場合、stackとcontinueを受け取るようにラップされる
push時に自動でreallocする
任意の値をpushできるっぽい
ただpop時にも正しい型を指定しないと壊れる…という感じ?
というか、popで何を取れるか呼び出し側がわかってる前提ということか。
現状のRustがTCOに対応していないためトランポリンが必要とのこと
というのを踏まえて…
まずpollをよぶ
Poll::Readyだった(値がとれた)ならstack.trampolineで次に進む
Poll::Pendingだったら、値がとれるまで待つ必要があるので、stack.suspendを呼ぶ
スタックにfuture, resume, continuationの順で積む
stack.resumeがresumeとcontinuationを取り出す
futureはstack.restoreが取り出す
stack.suspendはスタックにデータをしまうだけなので、永久に復活しないそうに見えるが…?
import!というマクロがある
例:import!(pen_ffi_any_is_boolean, fn(any: BoxAny) -> Boolean);
RustからPenの関数を呼ぶためのものっぽい
pen_ffi_any_is_booleanという名前、fn(any: BoxAny) -> Booleanという型でアクセスできるようになる
fnだけでなくasync fnもいける
その場合、import!はcall_function!(...).awaitに展開される
特に、
code:packages/os/ffi/application/src/main.rs
ffi::import!(_pen_main, async fn() -> ffi::None);
async fn main() {
_pen_main().await;
...
なのでcall_function!(_pen_main).awaitがtokioスケジューラに渡されるということかな?
おおまかにcore::future::poll_fn(|context| ...).awaitを行う
まずinitializeで指定された関数を呼ぶ
一度もasyncな機能が使われなければ、stack.resolved_value()で結果の値が取れるのでそれを返して終わり
一方途中でsuspendされた場合は、変数trampolineにメモを残してPoll::Pendingを返す
ここからはtokioチュートリアル見ての想像だけど、折を見てwakerが呼ばれる?tokioスケジューラはそれをたどってこのFutureを再度pollする? trampolineに残されたメモとは何か
Pen自体にsuspendする機能はないので、suspendが起こるのはいつもRust側
bindgen!は、Rust関数をPen側に提供するためのマクロ
対象がasync fnの場合、まずfuture.as_mut().pollを呼ぶ
Pendingが返った場合、resume関数をstackに積む(これがメモの正体)
Futureが再度pollされた際、resume関数が呼ばれる
やることは最初のpollと同じ(値が取れたら再開、Pendingならもう一度待つ)
どのようにしてループ構造が実現されているのか?
ループになるには、tokioランタイム(スケジューラ)にPoll::Pendingを返すことが必要
call_function!では、stackにpollを行う関数を積むことでそれを実現している