タイマー関数
ある関数を周期的に呼び出すには、POSIXタイマーやSIGALRMのようにシグナルハンドラを使うことになるけど、Infernoだとチャネルの同期的な性質を利用して、次のように書ける。
implement Timer;
include "sys.m";
include "draw.m";
sys : Sys;
Timer : module {
init : fn(nil : ref Draw->Context, nil : list of string);
};
init(nil : ref Draw->Context, nil : list of string)
{
sync := chan of int;
n := 10;
sys = load Sys Sys->PATH;
spawn timer(sync, n);
for (i := 0; i < n; i++) {
<- sync;
sys->print("%d\n", i);
}
}
timer(sync : chan of int, n : int)
{
for (i := 0; i < n; i++) {
sys->sleep(1000);
sync <-= 1;
}
}変数syncが同期に使っているチャネルだ。
ちなみに、このプログラム実行時にpsでスレッドの状態を見てみると次のようになる。
% ps | grep Timer
34 19 oraccha 0:00.0 recv 73K Timer
35 19 oraccha 0:00.0 release 1K Timer[$sys]5カラム目がスレッドの状態である。Recvはチャネルの受信待ち状態で、メインスレッドが"<- sync;"で待っていることを意味する。当然、Sendという送信待ち状態も存在する。もう一方のスレッド(spawnしたtimerスレッド)の状態はreleaseと表示されている。これはDis VMのレディキューから切り離され、組込みモジュールの実行完了を待っていることを意味する。組込みモジュールということはCで実装されているので、Dis VMの管理外ということになる。"[$sys]"という表示から察しがつくように、Sysモジュール、つまりこの場合はsleep()待ちしている状態である。
スレッドの状態を列挙すると、alt、broken、exiting、ready、recv、release、sendとなる。馴染みがないのはaltという状態だろうが、これは次のエントリで紹介するalt文での待ち状態になる。