プログラムがコンソール・オペレーターと通信(対話)を行うには2つの方法があります。1つは、メッセージを出力してそのメッセージに対する応答を受け取る方法です。もう1つは、メッセージとは無関係にオペレーターがMODIFYコマンドやSTOPコマンドによってプログラムに指示を与える方法です。
前者は、プログラムでオペレーターの判断を必要とする何らかの事態が起きたときに利用されます。例えば、DASDボリュームを初期化することがパラメーターで指定された時に、本当にクリアーしてもいいのかを再確認するような機能を持たせる場合や、誤った入力データを見つけたような時に処理不能で異常終了するのか、誤ったデータを無視して処理を続けるのかなどを選択させるような場合に、その旨のメッセージをコンソールに出してこの後どう動くかをオペレーターに判断してもらうようなプログラムを作ることができます。
後者は、システム運用などの都合によって、プログラムに特定の動作を行わせたり動きを変える場合などに利用されます。バッチ処理のように入力データが終わったらプログラムの処理も終わるのではなく、一定時間あるいはオペレーターが指示するまで動き続ける常駐型のプログラムを作る際に必要となる機能です。MODIFYコマンドでプログラムの動作や機能を変更し、STOPコマンドでプログラムを終了させるのが一般的です。
メッセージに対するオペレーター応答を受け取る
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
----+----1----+----2----+----3----+----4----+----5----+----6----+----7-- MVI WTORECB,0 CLEAR WTOR ECB WTOR 'MYP003D INVALID INPUT DATA FOUND, REPLY ''GO'' TO CONTI+ NUE OR ''CANCEL''', + RPLYAREA,L'RPLYAREA,WTORECB WAIT ECB=WTORECB WAIT UNTIL REPLIED BY OPERATOR : : : WTORECB DC F'0' ECB OF WTOR SERVICE RPLYAREA DC CL6' ' ENTERED REPLY COMMAND AREA MVI WTORECB,0 CLEAR WTOR ECB WTOR TEXT=(MSGLENG,RPLYAREA,L'RPLYAREA,WTORECB) WAIT ECB=WTORECB WAIT UNTIL REPLIED BY OPERATOR : : : WTORECB DC F'0' ECB OF WTOR SERVICE RPLYAREA DC CL6' ' ENTERED REPLY COMMAND AREA MSGLENG DC AL2(L'MSGTEXT) MSGTEXT DC C'MYP004A ENTER EXECUTE OPTIONS OR U' |
WTORマクロは、コンソールにメッセージを表示してオペレーターからの応答を受け取ります。出力するメッセージの指定方法はWTOマクロと同じですが、オペレーターからの応答を受け取る領域とその長さ及び待ち受けのためのECBアドレスを追加で指定します。
WTORマクロの完了は、オペレーターが応答を入力したときではありません。コンソールへのメッセージ出力がスケジュールされたら完了してプログラムに戻ってきます。この時、返答領域にオペレーターからの応答が入力されているかはわかりません(殆どの場合未だ入力されてません)。オペレーターからの応答を待ち受けるには、WTORマクロで指定したECBでWAITマクロを発行しなければなりません。オペレーターが応答すればWAITマクロが完了します。
バッチ処理のプログラムではあまり必要ありませんが、WTORマクロの後ですぐにWAITを出さず、オペレーターが入力するまでの間も止まることなく別の処理を行うこともできます。なお、WTORでもマクロ完了時にGR1にメッセージ識別番号が返ります。必要なら応答を待たずにメッセージを取り消すことも可能です。
最初の例は、古典的なWTORマクロのコーディングです。2番目は、後から追加されたTEXTパラメーターによって利用可能なメッセージ・テキストをマクロの外に記述する方法です。
オペレーター・コマンドを受け取る
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
----+----1----+----2----+----3----+----4----+----5----+----6----+----7-- MAINENTR CSECT , DEFINE CONTROL SECTION USING *,RC DEFINE BASE REGISTER STM 14,12,12(13) SAVE CALLER REGISTERS LA 12,0(,15) GR12 -> OUR 1ST BASE ADDRESS LR 15,13 SAVE CALLER SAVEAREA CNOP 0,4 INSURE FULL WORD BOUNDARY BAS 13,*+4+72 AROUND OUR SAVEAREA DC 18F'-1' OUR GPR SAVEAREA ST 15,4(,13) SAVE CALLER SAVEAREA POINTER ST 13,8(,15) SET BACK CHAIN FOR LINK TRACE *---------------------------------------------------------------------* 初期設定の処理 USING DCOM,2 ADDRESS TO COMM AREA(IEZCOM) USING DCIB,3 ADDRESS TO CIB EXTRACT ACOMLIST,FIELDS=COMM ISSUE EXTRACT COMM L R2,ACOMLIST LOAD COMLIST ADDRESS ICM R3,B'1111',COMCIBPT LOAD START COMMAND CIB BZ *+4+4+4+4+4 IF WE ARE NOT STC TASK LH R0,CIBDATLN LOAD COMMAND LENGTH LA R1,CIBDATA LOCATE TO COMMAND AREA STM R0,R1,LCMDPARM SAVE START COMMAND PARAMETER BAS RA,FREECIB FREE START COMMAND CIB SPACE , QEDIT ORIGIN=COMCIBPT, SET AVAILABLE COMMAND QUEUES + CIBCTR=10 DROP R2,R3 FORGET COMM-AREA AND CIB *---------------------------------------------------------------------* : : : : : : : *---------------------------------------------------------------------* オペレーターコマンドの待ち合わせと受け取りの処理 USING DCOM,2 ADDRESS TO COMM AREA(IEZCOM) USING DCIB,3 ADDRESS TO CIB CMNDWAIT DS 0H L R2,ACOMLIST LOAD COMLIST ADDRESS L R1,COMECBPT LOAD OP-COMMAND ECB ADDRESS WAIT ECB=(1) WAIT ANY OP-COMMAND CMNDNEXT DS 0H ICM R3,B'1111',COMCIBPT LOAD NEXT CIB BZ CMNDWAIT IF NOT, WAIT AGAIN CLI CIBVERB,CIBSTOP STOP COMMAND ? BE CMNDSTOP YES, PROGRAM DONE LH RF,CIBDATLN LOAD ENTERED OP-COMMAND LENGTH BAS RA,ECHOCMD ECHO ENTERED OP-COMMAND SPACE , ここに入力されたコマンドの処理を入れる。 SPACE , BAS RA,FREECIB FREE CURRENT CIB B CMNDNEXT PICKUP NEXT CIB DROP R2,R3 FORGET COMM-AREA AND CIB SPACE , *---------------------------------------------------------------------* STOPコマンドの処理 CMNDSTOP DS 0H WTO 'SAMPLE STC PROCESSOR, STOP COMMAND ACCEPTED.' SLR RF,RF SET CC=0 L RD,4(,RD) LOAD CALLER SAVEAREA L RE,12(,RD) RESTORE CALLER GPR14 LM R0,RC,20(RD) RESTORE CALLER GPR0-12 BR RE PROGRAM END SPACE , *---------------------------------------------------------------------* CIB解放の内部サブルーチン USING DCOM,2 ADDRESS TO COMM AREA(IEZCOM) FREECIB DS 0H GR2 --> COMMAREA + GR3 --> CIB QEDIT ORIGIN=COMCIBPT, FREE THIS CIB + BLOCK=(3) B 0(,RA) RETURN TO CALLER DROP R2 FORGET COMM-AREA SPACE , *---------------------------------------------------------------------* 入力されたコマンドをエコーする内部サブルーチン USING DCIB,3 ADDRESS TO CIB ECHOCMD DS 0H GR3 --> CIB + GR15 -> ENTERED COMMAND LENGTH MVC ECHOMSG(LCHOMDL),ECHOMDL INIT ECHO MESSAGE AREA CVD RF,DOUBLE EDIT ENTERED OP-COMMAND MSG UNPK ECHOMSG+4+33(2),DOUBLE I (MAX 32BYTES) OI ECHOMSG+4+34,C'0' I CH RF,=H'32' I BNH *+4+4 I LH RF,=H'32' I LH R0,ECHOMSG I SH R0,=H'32' I AR R0,RF I STH R0,ECHOMSG I LTR RF,RF I BZ *+4+4+4+4+2 I LA R0,ECHOMSG+4+36 I LA R1,32 I LA RE,CIBDATA I MVCL R0,RE I WTO MF=(E,ECHOMSG) INFORM IT B 0(,RA) RETURN TO CALLER DROP R3 FORGET CIB SPACE , *---------------------------------------------------------------------* DOUBLE DC D'0' DOUBLE WORD WORK AREA ACOMLIST DC A(0) POINTER TO COMLIST LCMDPARM DC F'0' LNG OF START CMD PARM ACMDPARM DC A(0) TXT POINTER OF START CMD PARM ECHOMDL WTO 'SAMPLE STC PROCESSOR, ENTR CMND=(XX) + ',MF=L LCHOMDL EQU *-ECHOMDL MESSAGE MODEL AND LENGTH ECHOMSG DC (LCHOMDL)X'00' MESSAGE EDIT AREA *---------------------------------------------------------------------* LTORG , USER LITERAL PLACE AT HERE *---------------------------------------------------------------------* DCOM DSECT IEZCOM , COMMUNICATION AREA DCIB DSECT IEZCIB , CIB *---------------------------------------------------------------------* : : END |
アドレス空間に常駐してオペレーターが指示するまで一定の処理を行い続けるサーバー型のプログラムでは、「次に何を行うか?」といったことをオペレーターからのコマンドによって判定したい場合があります。このような場合、OSのMODIFYコマンドやSTOPコマンドでオペレーターの指示を受け取ることができます。上記のプログラムは、MODIFY及びSTOPコマンドを処理するサンプルです。WTORに比べるとロジックはやや複雑になりますが、STCタスクとして動かす常駐型のサーバー・プログラムでは必須となる機能です。
プログラム起動時の初期設定として、EXTRACTマクロを発行してMVSのコマンド・スケジューラー・リスト(COMMAREA)のアドレスを得ます。STARTコマンドで起動されたSTCタスクの場合は、STARTコマンド用CIBがチェインされているのでそのアドレスを求めます。これは、COMMAREA内のCOMCIBPTフィールドにあります。バッチジョブなど、STARTコマンド以外の方法で起動された場合はチェインされていません。このアドレスを調べれば、STARTコマンドで起動されたSTCタスクかそうでないかを判定できます。STC起動の場合は、BLOCK指定のQEDITマクロを発行してSTARTコマンド用CIBをクリアーしておきます(サンプルでは内部サブルーチンFREECIBで行っています)。STARTコマンドでも起動パラメーター指定を可能にするプログラムであれば、CIB解放前にパラメーター文字列を解析するなりコピーするなりを行います。STC起動されたプログラムの場合、STARTコマンドでパラメーターを指定していなくてもCIBは作成されることを知っておいて下さい。
S procname,,,parameter
STARTコマンドでパラメーターを指定する場合は、上記のようにコマンドを入力します。例えば、 S MYSTC1,,,MODE=DEBUG とすれば、MODE=DEBUG の文字列がSTARTコマンド用CIBで渡されます。CIBDATLNはパラメーターの長さ、CIBDATAがパラメーター文字列です。
次に、MODIFYコマンド用のコマンド・キューを作るため、CIBCTR指定のQEDITマクロを発行します。CIBCTRには同時に入力可能なコマンド数(最大255)を指定します。入力されたコマンドは、まとめてプログラムに渡ってくるわけではありません。1つずつ順番に取り出して、1つずつ順番に処理することができます。従って、CIBCTRは1でもかまいませんが、プログラム側のコマンド処理に時間が掛かると、オペレーターは次のコマンドを入力してもMVSにリジェクトされてしまいます。極端に多くする必要なありませんが、10個程度はあってもいいでしょう。CIBCTR=10なら、未処理のコマンドを10個分OS内でキューイングできることになります。ORIGINパラメーターには、COMMAREAのCOMCIBPTフィールドを指定します。これでオペレーターコマンドを受け取る準備ができました。
EXTRACTを出した後で、QEDITマクロも含めてOSのコントロール・ブロックをプログラムで直接参照します。このため、コントロール・ブロックをフィールド名でアクセスするためにコントロール・ブロックのマッピング・マクロを使います。参照するコントロール・ブロックはCOMMAREAとCIBです。それぞれIEZCOMマクロとIEZCIBマクロでマッピングします。DSECT展開マクロでないため、サンプルのように自分でDSECTを定義します。
プログラムは、コマンドを受け取るタイミングになったら、COMMAREA内のCOMECBPTフィールドでポイントされているコマンド入力待ち合わせ用のECBを指定してWAITします。COMECBPTフィールドは、ECBそのものではなくECBアドレスが格納されたポインターフィールドです。既に何らかのコマンドが入力されていたり、新たなコマンドが入力された時点でWAITは解除されます。
COMMAREA内のCOMCIBPTフィールドには、入力されたコマンドのCIBアドレスが入っています。ここが0なら全てのCIBは処理済みなので、次のオペレーター・コマンドの入力を待ち受けるために再びWAITします。CIBアドレスが入っていれば、そのCIBを調べることで入力されたコマンド文字列を求めることができます。CIBのCIBVERBフィールドは、入力されたコマンド種類を示します。x44ならMODIFY、x40ならSTOPコマンドですが、サンプルのように必ずラベル名で参照します。CIBSTOPは、STOPコマンドを示すEQUラベルです。STOPコマンドは、通常プログラムの終了を意味しますから、サンプルのように終了処理へ移ってしまってかまいません。MODIFYコマンドの場合は、入力されたコマンド文字列と長さが必要なのでCIBから求めます。CIBDATLNはコマンド文字列の長さ、CIBDATAがコマンド文字列です。コマンドを入力したコンソールIDもわかります。z/OSではCIBX内のCIBXCNIDまたはCIBXCNNMフィールドを利用します。CIBXはCIBに連続して配置されている拡張CIBで、その先頭アドレスはCIBアドレスにCIBXOFFフィールドの値を加えることで求められます。特定のコンソールからのコマンド入力かどうかをチェックしたり、コマンド発行元コンソールを記録することなどもできます。
コマンド文字列が求められたら、対応するコマンド処理を行い、その後に処理済みコマンドのCIBを解放します(サンプルでは内部サブルーチンFREECIBで行っています)。先にCIBを解放してもかまいませんが、その場合は入力されたコマンド文字列をプログラム側の領域に適宜コピーしておく必要があります。解放したCIB領域を後から参照してはなりません。このサンプルでは、入力されたコマンド文字列と長さを先頭の32バイト分コンソールにエコーしています。
コマンド処理が終わりCIBを解放したら、次のコマンドをチェックします。再びCOMCIBPTフィールドを参照して、次のCIBがセットされているかを調べます。COMCIBPTは、CIBを解放するためのBLOCK指定のQEDITマクロによって内容が更新されます。次のCIBがなければWAITへ回ります。このようなサイクルでオペレーター・コマンドの処理を行っていきます。MODIFYコマンドで独自のコマンド処理をする場合であっても、プログラムはSTCタスクである必要はありません。バッチで起動されても同じロジックで処理できます。異なる点は、初期設定時のSTARTコマンド用CIBの有無だけです。もし、STARTコマンドではパラメーターを受け取らないなら、少し乱暴ですが初期設定時にSTCかどうかを判定せずにSTARTコマンド用CIBをQEDITで無条件にクリアーしてもかまいません。バッチの場合は、そのQEDITがエラーになるだけでABENDするようなことにはなりません。
STOPコマンド入力後もオペレーター・コマンドを受け取るには
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
----+----1----+----2----+----3----+----4----+----5----+----6----+----7-- CMNDSTOP DS 0H WTO 'SAMPLE STC PROCESSOR, STOP COMMAND ACCEPTED.' SPACE , L RF,STOPCTR INCREMENT NUM OF STOP ENTERED LA RF,1(,RF) I ST RF,STOPCTR V CH RF,=H'3' 3RD TIME ENTER ? BNL PROGDONE NO, CONTINUE PROCESSING SPACE , L R2,ACOMLIST LOAD COMLIST ADDRESS USING DCOM,2 ADDRESS TO COMM AREA(IEZCOM) BAS RA,FREECIB FREE STOP COMMAND CIB QEDIT ORIGIN=COMCIBPT, SET AVAILABLE COMMAND QUEUES + CIBCTR=10 B CMNDNEXT PICKUP NEXT CIB DROP R2 FORGET COMM-AREA SPACE , PROGDONE DS 0H SLR RF,RF SET CC=0 L RD,4(,RD) LOAD CALLER SAVEAREA L RE,12(,RD) RESTORE CALLER GPR14 LM R0,RC,20(RD) RESTORE CALLER GPR0-12 BR RE PROGRAM END |
STOPコマンドが入ると、QEDITで指定したCIBカウンターは0にされてしまいコマンド・キューは無効になり、以降のMODIFYコマンドは受け付けられなくなります(STOPコマンドだけは入力可能)。STOPコマンドが入った後も、引き続きMODIFYコマンドでコマンドを受け取るためには改めてCIBCTR指定のQEDITマクロを発行する必要があります。