07.1非同期事象の待ち合わせと通知(WAITとPOST)

By 神居 - Posted: 2008/11/25 Last updated: 2009/12/13 - Leave a Comment

システムプログラムでは「いつ来るかわからない」「いつ終わるかわからない」と言った事象(イベント)を待ち合わせることは多々あります。メインフレームでもイベントが発生・終了するまで、来たか?来たか?、終わったか?終わったか?、とループしてタイミングを合わせる方法がありますが、一般のプログラムでは使いません。OSであってもループによるタイミング合わせは本当に必要な所だけに限定して使っています。
MVSはイベントの完了の待ち合わせにWAIT、イベントの完了の通知にはPOSTと言うサービスを提供しています。プログラムはこのサービスを使うことで、ループなどしなくても、必要なイベントの発生や終了のタイミングを合わせることができます。

上に挙げたこれらの例も、いつ発生するかわからない事柄です。インターバルタイマーに関しては例えば10秒後と言う時間はわかっていても、いつが10秒後なのかわかりません。人間は時計を見ながら10秒後を知ることができますが、これはループと同じです。オペレーターコマンドや端末の受信データはわかりやすいでしょう。いつコマンドが入力されるか、いつ実行(エンター)キーが押されるかは人間様次第です。I/O動作の完了やJCLのサブミットの待ち合わせはOSに取っての待ち合わせ事象の1つです。チャネルで実行されたI/Oはいつ完了するかわかりません。JCLは人間がコマンドやパネルでサブミット操作を行いますが、OSにしてみれば、それがいつ行われるかまったく予測できません。
これらのようにいつ起きるかわからない事を非同期事象(asynchronous event)と呼びます。バッチ処理用のアプリケーション・プログラムを作るだけではなかなかわかりにくいのですが、MVSは基本的にイベント駆動型のソフトウェアです。さまざまな非同期事象の発生を待ち受け、それに応じた処理をディスパッチします。このサイクルを延々と繰り返して行くわけです。


タイマーによるインターバル時間の経過を待ち合わせる(WAIT)

WAITマクロはイベントの完了を待ち合わせます。WAITマクロではどのイベントかを識別するため、ECBと言う1ワードの領域を使用します。ECBの先頭のビット0をWAITビット、ビット1をPOSTビットと呼びます。WAITマクロを発行するためにはECBを用意し、ビット0をクリアーしておかなければなりません。サンプルではビット0のクリアーではなくMVIでバイト毎クリアーしていますが、これも一般的な方法で非同期事象の開始前であることがはっきりしている時は、その時点ではこのECBにPOSTするプログラムは存在しないためPOSTビットも含めて0クリアーしてかまいません。XC命令でワード毎クリアーしてもかまいません。
イベントの識別と言ってもややこしい規約があるわけではなく、単に待ちになる側と、完了を伝える側でどこにECBがあるかがわかっていればいいのです。複数のイベントを並行して取り扱うような場合、それぞれのイベントをどのECBを使って待ち合わせるかを取り決める、と言うことです。一般的にはWAITする前にECBのアドレスを、実際に非同期事象を実行する側のプログラム(POSTする側)に何らかの手段で伝えます。

WAITマクロを発行するとプログラム(タスク)は指定したECBにPOSTがなされるまで、スーパーバイザー(WAITルーチン)の中で待ち状態となります。ECBのWAITビットは1にされ、WAIT中プログラムを識別するトークン(RBアドレス)が下位3バイトに格納されます。

ECBをどこでクリアーするかは重要なことです。待ち合わせる事象が開始する前にクリアーするのが原則です。タイマーならSTIMER発行前、オペレータ応答の受け取りならWTOR発行前、データの受信ならRECEIVE要求の前です。イベントを開始させてしまってからクリアーするとタイミングによってはイベントをロストさせてしまいます。
イベントによってはWAITしようとする時点で既にPOSTされている場合もあり得ます。すでにPOST済みのECBを指定してWAITマクロを発行しても問題ありません。実際にWAITせずにすぐに発行元プログラムに戻ってきます。しかしWAITビットが1になっているECB(WAIT中ECB)を指定するとプログラムはABENDさせられます。

これは誤ったECBクリアーの例です。STIMETRマクロで指定する時刻や間隔時間にもよりますが、99%は正しく動くでしょう。しかし指定した時刻が15:00丁度である時、STIMETRマクロが15時に限りなく近い15時前での発行であった場合、STIMERマクロから復帰した時点でWKUPECBにはすでにPOSTがなされているかも知れません。指定した間隔時間が1/10秒などと言う極端に短い時間である時も、STIMERマクロから復帰した時点で実時間で1/10秒は過ぎてしまっているかも知れません。
ロジックでは無条件にECBをクリアーしていますから、その場合永遠にPOSTされないWAITに入ってしまいます。これがイベントのロストです。WAIT発行前にPOSTビットをテストして1であればWAITを迂回するロジックもありですが、この例に関して言えばそんなことをするよりはECBのクリアーをSTIMETRマクロの発行前に行えばよいのです。非同期事象はその名の通り非同期ですから指定したイベントがいつ完了するかは予測できませんが、この例では自分がSTIMERを出さない限り時間計測と言う非同期イベントは起き得ないのでPOSTされることもありません。そのきっかけとなるSTIMERマクロの前でECBをクリアーできます。


タイマーによるインターバル時間の経過を通知する(POST)

POSTマクロはWAITの逆でイベントの完了を通知します。指定したECBにPOSTビットを設定し、WAIT中のプログラムがあれば待ち状態を解きます。この時ECBのビット2?31に任意のPOSTコードを設定することもできます。省略すればビット2?31は0にクリアーされます。POSTする側は相手がWAITしているかどうかを考える必要はありません。
このサンプルはSTIMERマクロによるインターバル時間の経過の待ち合わせと通知の例です。STIMERマクロを出した後のWAITマクロによってプログラムのタスクは待ち状態になります。10秒経過するとTIMREXITルーチンが実行されます。タスクが止まっている状態でも割り込んで実行されます。このようなプログラムを非同期出口ルーチンと言います。MVSでは長時間掛かるサービスやいつ完了するか予測できないサービスの完了を通知するために非同期出口ルーチンが使われるものがいくつかあります。

WAIT/POSTはマルチタスクのプログラムで使うもの、と言うイメージがありますが、シングルタスクのプログラムでも使用するAPIによってはWAIT/POSTによる待ち合わせと通知の処理が必要になります。


複数のイベントを待ち合わせる(ECBLIST)

複数の非同期イベントを取り扱うプログラムでは、いずれかのイベントが完了したら通知してもらうようにすることもできます。サンプルでは複数のECBの内、どれか1つが完了したら通知してもらう例です。これはマルチイベント・シングルウェイトです。複数個のECBが完了したら通知してもらうようにすることも(マルチイベント・マルチウェイト)、すべてのECBが完了したら通知してもらうようにすることも(マルチイベント・オールウェイト)できます。ただしマルチウェイトの場合どのECBから完了したかはわかりません。シングルウェイトであってもWAITが解けた後に別のECBにもPOSTされることがあり得ます。同様にどのECBから終わったかはわかりません。どちらの場合であってもどのECBのイベントが終わったかは、プログラムが自分でPOSTビットの立っているECBを探す必要があります。
なおマルチイベントではWAITから復帰した後、POSTビットとPOSTコードはPOSTされたECBにのみ設定されています。POSTされたECBを含めすべてのECBのWAITビットは0になっていますが、POSTされなかったECBのPOSTコード部にはRBアドレスが設定されたままになっていることに注意してください。MVS側はECBにRBアドレスが設定されたままで再びWAITが出されても支障ありませんが、POSTされなかったECBはECBワード自体が0(あるいはWAIT発行時の内容)になっているものと期待してロジックを作ると正しく動きません。

Posted in .基礎編 • • Top Of Page