[OSASK 5028] Re: シグナル(ぐいぐい01).

  こんにちは、川合です。


KOYANAGI, Masaaki さんは 2002/09/18 22:21:12 の「[OSASK 5018] Re
: シグナル(ぐいぐい01).」で書きました:

>私は「シグナル」というとUNIX でのシグナルとシグナルハンドラがまず思い
>浮かんでいました。どうもこのことをこれまでのメールで書いていなくて、
>自分の意見がはっきりと伝えられませんでした。すみません。
>
>OSASK のシグナルはイベントドリブンの考え方で、割り込みという考え方を
>しないように感じていますが、合っているでしょうか?

  たぶん誤解しているように思います。ということで、その誤解をとき
たいと思っています。

  まず、「割り込みの必要性」の意味の確認です。

  僕は[OSASK 5003]を読んだときに、シグナルの並べ替え的なことをお
っしゃっているんだろうと理解しました。つまり、「ABCabc」というシ
グナルが発生した場合に、シグナルボックス内で「abcABC」と並べ替え
て通知するような仕組みのことです。ここで、小文字は緊急性の高いシ
グナル、大文字は緊急性の低いシグナルです。

  それで、並べ替えについては、[OSASK 5016]のような回答になってお
ります。

  さて、僕は[OSASK 5018]を読んで、小柳さんがおっしゃりたいことは
もっと細かいことなのではないかと思いました。確認させてください。
・・・たとえばシグナルCの処理は3秒くらいかかるような大規模なもの
だったとします。この処理に入った瞬間にシグナルaが来ても、アプリ
は3秒後にしか気が付けないのではないか、という趣旨のご指摘でしょ
うか?

  そうだとすると、シグナルの並べ替え程度では太刀打ちできません。
小柳さんのご不満はごもっともです。

  これに対処する方法はいろいろあります。まずは、効率は悪いが分か
りやすい方法を紹介しましょう。それは、シグナルCの処理中にシグナ
ルボックスをちょくちょくチェックすることです。たとえばcheck_sig
という関数を作ります。

static int buf[1000], *rptr = buf, *wptr = buf;

int check_sig()
{
    int sig;
    for (;;) {
        sig = *sig_ptr;
        if (sig == REWIND_CODE) {
            lib_waitsignal(0x0000, *(sig_ptr + 1), 0);
            sig_ptr = sig_ptr0;
            continue;
        }
        if (sigは特別の値)
            break;
        if (sig == 0)
            break;
        /* 通常シグナルは受け取ってbufに貯めておく */
        sig_ptr++;
        *wptr++ = sig;
        lib_waitsignal(0x0000, 1, 0);
    }
    /* これだと通常シグナルを1000個しか扱えないので
        ちゃんとつかうならrewindなどを入れる */
    return sig;
}

int new_getsig()
{
    int sig = check_sig();
    if (sig != 0) {
        sig_ptr++;
        lib_waitsignal(0x0000, 1, 0);
        return sig;
    }
    if (rptr == wptr)
        return 0;
    return *rptr++;
    /* これだと通常シグナルを1000個しか扱えないので
        ちゃんとつかうならrewindなどを入れる */
}

  check_sig()は、シグナルボックスをチェックして、もし通常シグナ
ルを検出すればそれをバッファへ貯めて、また緊急シグナルを検出すれ
ば、それはシグナルボックスに残したままでreturnします。この関数の
返値が0なら緊急シグナルは何ら検出されていないことを意味し、非零
なら緊急シグナルがシグナルボックスに待機していることを示します。

  new_getsig()は、check_sig()との相性をよくして書き直しただけで
す。

  シグナルCを処理するルーチンでは、このcheck_sig()をちょくちょく
呼び出して、緊急シグナルが来ていないかどうかをチェックします。も
し緊急シグナルが検出されれば、しかるべき処理を呼び出したりできま
す。

  このやり方はポーリングという手法で、簡単で扱いやすいですがとに
かく効率が悪いです。できるだけ緊急シグナルの到着に敏感に反応しよ
うとすればそれだけ頻繁にcheck_sig()を呼び出さなければならず、負
荷が増えるのです。

  もう一つのやり方は、シグナルハンドラを使う方法です。これはシグ
ナルボックスにシグナルが溜まると所定の関数をすぐに呼び出す仕組み
で、シグナルボックスの中のシグナルが通常のものなのか緊急のものな
のかは判別しません。いうなれば、すべて緊急として扱っている、とい
えるでしょうか。

  アプリはシグナルハンドラ内で通常シグナルのキューイングや緊急シ
グナルへの応対などをするわけです。このシグナルハンドラについて詳
しく説明するとまた長くなるので、まずはcntupc3などをご覧ください
。シグナルをポールすることなく、シグナルが検出できるというなによ
りの例です。必要でしたら、このシグナルハンドラについて詳しく説明
いたします。

  ということで、ぐいぐい00ではシグナルをポーリングするやり方と、
シグナルハンドラを利用するやり方の両方を既にサポートしているわけ
です。それでプログラマは自分の書くプログラムの性質に合わせて、ど
ちらかのスタイルを選べばいいわけです(併用もできます)。

  シグナルへのレスポンスが悪いアプリは問題ですが、しかしそれを
仕様だと明言するなら、それはそれで一つの方針でしょう。時間のかか
る処理が一つもないなら、普通にgetsignal()を使っても問題はないで
しょう。緊急シグナルの前に通常シグナルが溜まる危険性があるなら、
new_getsig()を使うといいでしょう。重たい処理があるならcheck_sig(
)を使うか、もしくはシグナルハンドラに手を染めればいいわけです。
各自が自分のスキルと仕様とのバランスを考えて自由に選んでくれれば
と思います。

>UNIX のように、シグナルでプロセスの終了(SIGTERM)、中断(SIGSTOP)、
>再開(SIGSTOP)といった動作をさせる、あるいは、それらのシグナルをハンドル
>することは、OSASKではどのような実装になるのでしょうか?

  ということで、どんな実装でもいいわけです。速やかに反応できるか
どうかの違いはありますが。反応が悪くて困るなら、シェルからkillす
るとか、強制スリープをかけるとか(全てのローカルレベルをスリープ
に設定してしまう)、まあいろいろ手段はあるわけですし。・・・もち
ろん迅速に反応してくれればそれにこしたことはありません。


  それでは。

--
    川合 秀実(KAWAI Hidemi)
OSASK計画代表 / システム設計開発担当
E-mail:kawai !Atmark! imasy.org
Homepage http://www.imasy.org/~kawai/


ML番号でジャンプ
ML単語検索