SPINモデルチェッカでプログラムとか仕様とかをPromelaという言語で記述して、デッドロックしないとか調べてくれるもの。たぶんプロトコルの検証に強い。

プロセス間通信はチャンネルをつかうが、ちょっと文法のバリエーションが多いのでメモった。

// SPIN/Promelaのチャンネル操作いろいろ

// Cの文法に近い。
// セミコロンはCだとターミネータで文の終わりに必要だが、
// Promelaではセパレータで文の区切りなので最後のセミコロンは不要である。

// メッセージタイプはこんな感じで定義する。enumみたいな感じ。
mtype { ok, ng }

// チャンネル a をつくる。1メッセージためこめる。1メッセージの中身はここではタイプのみ。
chan a = [1] of { mtype }
active proctype senderA()
{
    // fifo send; 順番に送信
    a!ok;
    a!ng // recverAがa?okしてチャンネルに空きができるまで実行されない(ブロックされる)。
}
active proctype recverA()
{
    // fifo receive; 順番どおりに受信
    a?ok;
    a?ng
}

// 2メッセージためこめる。
chan b = [2] of { mtype }
active proctype senderB()
{
    b!ok;
    b!ng // ok,ngの順で送信するが..
}
active proctype recverB()
{
    // random receive
    b??ng; // ?? はメッセージの追い越しをして受信をする。
    b??ok  // もし ?? じゃなくて ? だと b?ng が成功しなくてエラー(timeout)になる。
}

chan c = [2] of { mtype }
active proctype senderC()
{
    c!ok;
    c!ng;
}
active proctype recverC()
{
    // poll
    c?<ok>; // okがエンキューされるまで待つがデキューしない。
    c?<ok>; // デキューしないので何度でもできる。
    c?ok;
    c?<ng>;
    c?<ng>;
    c?ng
}

chan d = [2] of { mtype }
active proctype senderD()
{
    d!ok;
    d!ng
}
active proctype recverD()
{
    // random poll
    d??<ng>;	// ?? と <〜> の組み合せ技。
    d??<ok>;	// ??<はトライグラフなのでcppが文句をいう...
    d?ok;
    d?ng
}

#if 1
chan e = [2] of { mtype }
active proctype senderE()
{
    e!ok;
    e!ng;
}
active proctype recverE()
{
    // c?[msg] はmsgがキューイングされているかの検査でtrue(1)/false(0)を返す。
#if 1
    do
    :: e??[ok] && e??[ng] ->
	//e??[ok];
	//e??[ng];
	break
    :: else -> skip
    od;
#else
    bool rdy_ng;
    bool rdy_ok;
    do
    :: true ->
	rdy_ok = e?[ng] -> true : false;
	rdy_ng = e?[ok] -> true : false;
	printf("%d %d\n", rdy_ng, rdy_ok);
	if
	:: rdy_ng && rdy_ok -> break
	:: else -> skip
	fi
    od;
    assert(rdy_ng == true);
    assert(rdy_ok == true);
#endif
    e?ok;
    e?ng;
}
#endif

chan f = [2] of { mtype }
active proctype senderF()
{
    f!ok;
    f!ng;
}
active proctype recverF()
{
    mtype w;
    f?w;
    assert(w == ok);
    w = ng;
    f?eval(w); // ふつうに f?w と書くと w に受信したメッセージが入ってくるが
               // この場合だと f?eval(w) は f?ng になる。
}

今回の仕事ではまったのが

chan ch[NCH] = [N] of { ... }

とチャンネルの配列でやろうしてたんだが

xr ch[0]

って書けないこと。xr,xsはそのプロセスしか受信/送信しないことを宣言するもので、これを宣言しておくとSPINが検査する空間がちっちゃくなってうれしいらいい。最新のSPINだと丁寧にも xr ch_0 のように書き換えればできるよってメッセージがでてくるけど、今回はそうはいかないのでしぶしぶあきらめ。