読者です 読者をやめる 読者になる 読者になる

mrubyにThread実装のための機能を追加したい

LeapMotionのライブラリをmruby用に書いたり、SDL2.0のライブラリをmruby用に書いたりしていて、
mrubyのRiteVMにもThreadをサポートするための実装が欲しいなーと常々思っていました。
で、ふとTwitterでmrubyにもThreadのサポートが欲しいよー的なことを発言したところ、
Matzさんからこんなお返事をいただきました。

ということで、mrubyでThreadを使うために何が必要かをいろいろと考えてみようと思います。

背景

mrubyでは「Threadをsupportしません」というスタンス(というよりはISOで定義されていないものはサポート対象外という方針だったよう)でした。
そうした方針が採用される中で、mrbgemが登場しmruby本体の外側に多様なライブラリの実装を追加することが可能になりました。
このmrbgemの登場により、mruby-threadのような、外付けの拡張機能がユーザーの手によって追加されるようになりました。

こうした外付けの機能の中には、既存ライブラリをmrubyへbindするものも多く、私自身が開発して公開しているもののいくつかも、そうした既存ライブラリをmrubyから利用するためのものでした(mruby-openalとかmruby-sdl2とか)。
既存ライブラリをmrubyから利用する上で大きな問題として存在するのが、マルチスレッドが前提となる機能の場合に、安全にかつ低リソースでmrubyを利用することが難しいということです。

たとえば、mruby-threadの実装を読むと判りますが、現在のmrubyでは生成されたsub-thread上でのコードの実行のために、RiteVMのインスタンスを再生成する必要があります。
このため、シンボルテーブルやヒープなどの、本来であればスレッド間で共有して欲しいリソースがスレッドごとに存在してしまいます。

目的

mruby上で動くRubyのコードでThreadが実装可能なように、
RiteVM側にThreadを実装する上で必要な機能を実装したいと思います。
Threadクラス自体の実装は含みません(Threadの実装はプラットフォーム依存なので)。

必要な機能

Threadの実装にどんな機能が必要か思いつく限りあげて行こうと思います。
基本的にcompile optionでThreadのサポートを完全に外せるようにできたら良いなと思っています。

Thread関連APIの整備

  • Threadの生成/破棄のAPIの定義
    • スレッドサポートの有無のチェック: mrb_is_thread_supported
    • スレッドの生成: mrb_thread_create
    • スレッドの破棄: mrb_thread_join
  • 定義したThread APIの実装はpluggableにしたい
    • mrbgemでAPIの実装を追加する?
    • mrb_open_allocfみたいに実装用APIを実行時に注入する?

こうすることで、Threadクラスの実装はmrubyのThread APIを呼び出すだけにできて、
かつplatform dependentなcodeをユーザーが自由に定義しやすくなります。
Threadクラスの拡張(priority設定したりとか)もmrbgemを作ってユーザーが自由に行えます。

Threadの生成

  • Thread用のcontextの生成(Thread用のmrb_stateの生成)
  • 共有リソースのlock/unlock実装の指定(プラットフォーム依存なので、allocfのようにユーザが置き換えられるように実装する)
    • lock resourceの生成用ユーザー指定関数型の定義
    • lock resourceの破棄用ユーザー指定関数型の定義
    • lock resourceのロック用ユーザー指定関数型の定義
    • lock resourceのアンロック用ユーザー指定関数型の定義
    • 共有リソース個別のロック/アンロックAPIの追加(mrb_lock_vm_heapとかそんな感じ)
    • 可能ならread-write-lockのサポート

Threadの実行

  • VM heapへの安全なアクセス
  • symbol tableへの安全なアクセス
  • global variable tableへの安全なアクセス

Threadの破棄

  • Thread用contextの破棄
  • 全ての子Threadの終了の待機

Threadと例外

  • 例外のためのjump bufferのThreadごとの個別管理

ThreadとGC

  • 参照がなくなったが実行状態なThreadオブジェクトの破棄の遅延
  • VM heapへの安全なアクセスとGC
    • GC開始時に対象のスレッドの一時停止/再開
  • GC Threadの構築(これは必須ではないけど)

その他

  • arenaもThread個別に持っていた方が良いかな?冗長な気がするけど。少なくともthreadの数に比例してarenaの領域を拡大しないなら、thread個別管理が良い気がする。


パッと思いついたのはこのくらい。
他にもいろいろ抜けがありそうだけれど、最低限これだけの機能が実装できれば、
mrubyにThreadの実装を付け足すことができるようになるのではないかと思う。