あどけない話

インターネットに関する技術的な話など

(続)Haskell(GHC)での軽量ユーザスレッドの実装方法

Haskell(GHC)での軽量ユーザスレッドの実装方法で、Cmm が軽量スレッドのポイントと書きました。しかし、GHC の実装者 Simon Marlow 先生から「Cmm は関係ないよ」と教えて頂きました。

StgCall

StgCall がいくつかのレジスタを保存するのは、採用しているCの関数呼び出し規約がそうなっているから。スレッドとはまったく無関係。

GHC のランタイムは C で書かれている。よって、スケジューラからスレッドを呼び出すと、C から Haskell を呼び出すことになる。C では、呼び出された関数がレジスタを保存しなければならない。Haskell の関数には、こういった制約はない。なので、C から Haskell の関数を呼び出す際は、C の規約を肩代わりしてやる必要がある。それが StgCall。

スタック

Haskell のスタックは C のスタックと同様、特定のレジスタが指す場所。(Cの場合はスタックレジスタだろうが、Haskell の場合はそうではない。しかし本質的には同じこと。)

ただし、Haskell のスタックは、自由に領域を拡張したり、動かしたりできる。GC は、スタックを正しく扱えるように作られている。だから、スレッドのスタックは小さい領域で始められる。

コンテキストスイッチ

安全なポイントのみでコンテキストスイッチする。(コードを見る限り、タイムアウトやスタック溢れのなどが対象。スタック溢れの場合は、スタックを拡張してキューに入れる。これは安全そう。しかし、タイムアップの場合は安全なのか僕には判断できない。)

よって、保存しなければならないコンテキストは、CPU に依存しない。だから、真のプリエンプティブだとは言えないが、十分に頻繁なのでプログラマーには認識できない。

外部言語の関数呼び出し

ユーザスレッドの実装は、外部言語の関数呼び出しをサポートする際に行き詰まることが多い。つまり、呼び出した外部言語の関数でブロックされ、他のユーザスレッドが動かなくなる。

Haskell では、外部言語の関数呼び出し専用のカーネルスレッドを用意していて、ユーザスレッドがブロックされないようになっている。この手法は素晴らしいが、他の言語コミュニティは、素晴らしさに気付いていないようだ。