Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

第37章. ホスト側のホットコードスワップ

この章の目的

この章を読み終える頃には、走っているモジュールをホストから、リセット境界で新しいモジュールに置き換えられるようになります。この章を読み終える頃には、走っているモジュールをホストから、リセット境界で新しいモジュールに置き換えられるようになります。

スワップする場所

ホットコードスワップはホスト主導です。loopスクリプトは自分を置き換えません。ホストが置き換え、しかも1つの地点 — VmState::Reset、ループ本体の2つの反復の間の境界 — でだけです。その境界ではスクリプトのオペランドスタックは空で、データセグメントだけがスクリプトの所有する生きている状態です。これがスワップを安全にしている要因です。ホットコードスワップはホスト主導です。loopスクリプトは自分を置き換えません。ホストが置き換え、しかも1つの地点 — VmState::Reset、ループ本体の2つの反復の間の境界 — でだけです。その境界ではスクリプトのオペランドスタックは空で、データセグメントだけがスクリプトの所有する生きている状態です。これがスワップを安全にしている要因です。

ホストはドライブループの中でResetを見張ってVm::replace_moduleを呼びます。ホストはドライブループの中でResetを見張ってVm::replace_moduleを呼びます。

#![allow(unused)]
fn main() {
match vm.resume(input)? {
    VmState::Reset => {
        let new_module = load_new_version()?;
        let slot_count = new_module_private_slot_count;
        let initial_data = vec![Value::Int(0); slot_count];
        vm.replace_module(new_module, initial_data)?;
        vm.call(&[Value::Int(next_input)])?;
    }
    other => { /* ... */ }
}
}

replace_moduleは新しいモジュールと、初期のデータセグメントベクタを取ります。長さは新しいモジュールが宣言したdataブロックと一致しなければなりません。スワップのあと、VMのコルーチン状態はクリアされるので、新しいモジュールはresumeではなくcallでエントリーポイントから動かします。replace_moduleは新しいモジュールと、初期のデータセグメントベクタを取ります。長さは新しいモジュールが宣言したdataブロックと一致しなければなりません。スワップのあと、VMのコルーチン状態はクリアされるので、新しいモジュールはresumeではなくcallでエントリーポイントから動かします。

スワップを生き残るもの

スワップを跨ぐ事柄について3つ理解すべき点があります。

  • 対話の型は変わってはいけません。新しいモジュールは古いものと同じ型をyieldし、同じ型で再開されなければなりません。ホストは会話を途切れさせずに動かし続けるからです。対話の型は変わってはいけません。新しいモジュールは古いものと同じ型をyieldし、同じ型で再開されなければなりません。ホストは会話を途切れさせずに動かし続けるからです。
  • データセグメントは新しいものとして渡されます。ホストは古い値を持ち越すこともできますし、ゼロに再初期化することも、新しいスキーマに合わせるための移行コードを走らせることもできます。ピアノロールは新しくゼロ化されたベクタを渡しているので、入ってくる各楽曲のinitブロックがクリーンな状態で走ります。データセグメントは新しいものとして渡されます。ホストは古い値を持ち越すこともできますし、ゼロに再初期化することも、新しいスキーマに合わせるための移行コードを走らせることもできます。ピアノロールは新しくゼロ化されたベクタを渡しているので、入ってくる各楽曲のinitブロックがクリーンな状態で走ります。
  • ネイティブ関数の登録はモジュールではなくVMに住んでいるので、スワップを跨ぎます。新しいモジュールは古いモジュールが見ていたのと同じネイティブを見ます。ネイティブ関数の登録はモジュールではなくVMに住んでいるので、スワップを跨ぎます。新しいモジュールは古いモジュールが見ていたのと同じネイティブを見ます。

署名付きの更新

スワップが署名付きバイトコードとして配信されたモジュールを取り付ける場合、ホストはVm::replace_module_from_bytesを使います。これは、モジュールを取り付ける前に、VMが運ぶ信頼マトリクス — 第36章で登録した — に対して署名を確認します。署名付きホットスワップは多関係者配信シナリオの裏のメカニズムです — ベースラインのデバイスがリンク経由で署名付きの更新を受け取り、署名が通る場合だけ取り付けます。スワップが署名付きバイトコードとして配信されたモジュールを取り付ける場合、ホストはVm::replace_module_from_bytesを使います。これは、モジュールを取り付ける前に、VMが運ぶ信頼マトリクス — 第36章で登録した — に対して署名を確認します。署名付きホットスワップは多関係者配信シナリオの裏のメカニズムです — ベースラインのデバイスがリンク経由で署名付きの更新を受け取り、署名が通る場合だけ取り付けます。

ピアノロールのスワップ

ピアノロールが作業例です。標準入力スレッドがキー入力をスワップ要求に変えます。メインループは、次のVmState::Resetで、replace_moduleを次の楽曲のモジュールと新しくゼロ化されたデータベクタで呼び、ホスト所有の音声状態をリセットし、新しいモジュールのエントリーポイントを呼びます。耳で聴ける楽曲の変更は、まさにこのコードパスです。ピアノロールが作業例です。標準入力スレッドがキー入力をスワップ要求に変えます。メインループは、次のVmState::Resetで、replace_moduleを次の楽曲のモジュールと新しくゼロ化されたデータベクタで呼び、ホスト所有の音声状態をリセットし、新しいモジュールのエントリーポイントを呼びます。耳で聴ける楽曲の変更は、まさにこのコードパスです。

この章のまとめ

  • ホットスワップはホスト主導で、VmState::Resetでだけ起こります。
  • replace_moduleは新しいモジュールと新しいデータセグメントを取り付け、新しいモジュールはその後callから動かします。replace_moduleは新しいモジュールと新しいデータセグメントを取り付け、新しいモジュールはその後callから動かします。
  • 対話の型は変わってはいけません。ネイティブ登録は持続します。データセグメントはホストが持ち越すか、リセットするか、移行させます。対話の型は変わってはいけません。ネイティブ登録は持続します。データセグメントはホストが持ち越すか、リセットするか、移行させます。
  • replace_module_from_bytesは信頼マトリクスに対して署名付きの更新を取り付けます。replace_module_from_bytesは信頼マトリクスに対して署名付きの更新を取り付けます。

次の章では実行コストを測ります。