01.4共通域のGETMAINとアンカーポインター(NAME/TOKEN)
複数のジョブで構成されるソフトウェア、ジョブをまたがってデータをやり取りするようなソフトウェア(例えば通信サーバー、データベースなど)では共通域を使ってデータをやり取りすることができます。多重アドレス空間のMVSではジョブ内のメモリーはそれぞれ独立しているので、他のジョブのリージョン内領域を参照することは容易ではありません。現在のMVSではクロスメモリー・サービスも利用できますが、多くのソフトウェアは共通域であるCSAを利用する方法を採ってきました。この場合、CSAにデータを受け渡す領域を用意し、WAIT/POSTで互いの同期を取るような方法が使われます。
共通域(CSA)のGETMAIN
----+----1----+----2----+----3----+----4----+----5----+----6----+----7-- : L R3,LENGTH LOAD STORAGE LENGTH GETMAIN RC, OBTAIN COMMUNICATION AREA + LV=(3),SP=241,LOC=(ANY,ANY) LTR RF,RF SUCCESSFUL ? BNZ STOERROR NO, LR R2,R1 GR2 --> OBTAINED STORAGE ADDR : :
CSA領域をGETMAINする場合は、サブプール番号として241を指定します。CSAにはいくつかのサブプールがありますが、通常は241です。読み出し保護も掛けたい場合は231が利用できます。他のCSAサブプールはページ固定が掛かるので特別な場合でなければ利用しません。
MVSではGETMAINの代わりにSTORAGE OBTAINマクロも利用できます。どちらを利用してもCSAのGETMAINにはAPF許可が必要です。もしくはSVCルーチンとして動作するかです。
ジョブ間での同期取り
ジョブAのプログラム ----+----1----+----2----+----3----+----4----+----5----+----6----+----7-- : LR R2,R1 GR2 --> OBTAINED STORAGE ADDR MVC 0(80,R2),=CL80'PARAMETER...' L R3,ASCBJOBB LOAD JOB-B ASCB ADDRESS POST ecbaddr,postcode, WAKES JOB-B + ASCB=(3),ERRET=CVTBRET : :
ジョブBのプログラム ----+----1----+----2----+----3----+----4----+----5----+----6----+----7-- : WAIT ECB=ecbaddr WAITING JOB-A DATA MVC OURWORK,parameter from job-a : :
データさえ共通域に置ければ、どのジョブからもアクセスできます。したがってデータを待っているジョブにCSAにデータを書き終えたことを通知すればよいのです。POSTマクロを使うのが簡単です。相手はWAITマクロで待っています。
しかしここで問題が起きます。POSTしようにも相手のECBはどこにあるのでしょうか?データを受け取る相手側もECBにPOSTされた後、データをどこから持ってくればいいのでしょうか?
アンカーポインターを用意する
ジョブAのプログラム ----+----1----+----2----+----3----+----4----+----5----+----6----+----7-- : LR R2,R1 GR2 --> OBTAINED STORAGE ADDR USING COMMAREA,R2 ADDRESS IT FOR OUR COMM AREA MVC JOBAPARM,=CL80'PARAMETER...' L R3,ASCBJOBB LOAD JOB-B ASCB ADDRESS POST JOBBECB,0, WAKES JOB-B + ASCB=(3),ERRET=CVTBRET : : : COMMAREA DSECT JOBBECB DC F'0' WAITING ECB JOBAPARM DC CL80' ' INPUT PARAMETER JOBBRSLT DC CL256' ' PROCESSING RESULT :
ジョブBのプログラム ----+----1----+----2----+----3----+----4----+----5----+----6----+----7-- : L R2,anchor GR2 --> OUR COMM AREA USING COMMAREA,R2 ADDRESS IT FOR OUR COMM AREA WAIT ECB=JOBBECB WAITING JOB-A DATA MVC OURWORK,JOBAPARM READ INPUT DATA : : MVC JOBBRSLT,........ WRITE OUTPUT DATA : : COMMAREA DSECT JOBBECB DC F'0' WAITING ECB JOBAPARM DC CL80' ' INPUT PARAMETER JOBBRSLT DC CL256' ' PROCESSING RESULT :
プログラムデザインはさまざまなので、あくまでも一例として挙げます。空間が異なる複数のプログラムでデータをやり取りする場合、制御用も含めて必要なデータ域を1つにまとめたものを作ります。MVSではコントロール・ブロックと呼ばれます。C言語で言えば構造体です。この中に同期取りの待ち合わせに使うECBや受け渡しに使うデータ・フィールド、あるいはデータ領域へのポインターなどを入れます。そしてこのコントロール・ブロック自身をCSAにGETMAINして、コントロール・ブロックの先頭アドレスを、使用するプログラムが共通して参照できる場所に格納します。プログラムが共通して参照できる場所を「アンカーポインター」と呼びます。
上記の例では、ジョブBのプログラムがアンカーポインターからCOMMAREAのアドレスを持ってきています。ジョブAのプログラムは自分でCOMMAREAをGETMAINしたので、アンカーポインターがなくてもアドレスを知ることができます。しかしそれではジョブA以外のプログラムではアドレスを知りようがないので、ジョブAのプログラムは、ジョブBのプログラムがCOMMAREAのアドレスを求めることができるよう、どこかにアンカーポインターを用意して、そこにCOMMAREAのアドレスを書き込んでおかねばなりません。どこにアンカーポインターを持つかはデザイナーの腕の見せ所でもありました。
アンカーポインターの持ち方にはいくつかありますが、この例のように複数のアドレス空間から参照できるためにはCSAなどの共通域に用意しなければなりません。CVTUSERなどOSのコントロール・ブロックのユーザー・フィールドはこういう時のためにあるのですが、システムで1つしかないので取り合いになります。1つのプログラムでしか使わないのであればまぁいいとしても、ユーザー・アプリケーションであることが大前提です。ベンダー製品などではOSのサブシステムインターフェースで使用するSSCTを作ってチェインに繋げる方法がよく使われました。実際にサブシステムとして動く必要はなく、OSがサブシステムを識別するSSCTというコントロール・ブロックを作り、そこにアンカーポインターを設けるのです。1つのアドレス空間内での複数タスクであれば、ロードモジュールを使うこともできます。データ・フィールドだけで構成されたモジュールを作りローディングしておけば、同じアドレス空間なら自由に書き込み・参照ができます。モジュールの先頭アドレスはCSVQUERYマクロで求めることができます。モジュールをLPAへ置けば複数空間での参照も可能になりますが、実戦で見たことはありません。その他ENQを使った方法もありました。RNAMEにアンカーとなる情報を入れておき、参照する側はOSのENQ制御表のチェインをたどってターゲットのQNAME/RNAMEを見つける、といった方法でした。
そのようにいろいろ工夫されてきましたが、現在のMVSでは「NAME/TOKEN(名前付きトークン)」というサービスを使うのが便利です。他で使われてはいないだろうかなどを気にする必要もなくなりましたし、OSの制御表チェインを書き換えたりたどったりする方法では、OS側のエンハンスで構造が変わってしまうと動かなくなってしまいます。実際ENQの制御表チェインなどは昔のMVSでは共通域(SQA)に置かれていましたが、今では構造も変わりGRSアドレス空間で管理されています。
NAME/TOKENサービスを使ったアンカーポインター
ジョブAのプログラム ----+----1----+----2----+----3----+----4----+----5----+----6----+----7-- : LR R2,R1 GR2 --> OBTAINED STORAGE ADDR USING COMMAREA,R2 ADDRESS IT FOR OUR COMM AREA MVC JOBAPARM,=CL80'PARAMETER...' * *----------------------------------* * * CREATE OUR NEW ANCHOR POINTER * * *----------------------------------* L R0,=A(IEANT_SYSTEM_LEVEL) LOAD SYSTEM LEVEL VALUE ST R0,LEVEL SET IT L R0,=A(IEANT_NOPERSIST) LOAD PERSIST OPTION VALUE + DON'T USE PERSIST NAME/TOKEN + DUE TO AUTO DELETE AT OUR ADDR + SPACE ABENDED. ST R0,PERSIST SET IT ST R2,TOKEN SET COMM-AREA ADDR IN TOKEN SPACE , MODESET MODE=SUP CHANGE US TO SUP STATE L RF,CVTPTR LOAD CVT L RF,CVTCSRT-CVT(,RF) LOAD CSRTABLE L RF,X'14'(,RF) LOAD NAME/TOKEN VECTOR L RF,X'04'(,RF) LOAD IEANTCR ENTRY CALL (15), CALL IEANTCR TO ADD COMM-AREA + (LEVEL,NAME,TOKEN,PERSIST,RETCD) ANCHOR MODESET MODE=PROB BACK TO PROBLEM STATE CLI RETCD,IEANT_OK SUCCESSFUL ? BNE NMTERROR NO, NAME/TOKEN ERROR * *----------------------------------* * * FIND TARGET ADDRESS SPACE ASCB * * *----------------------------------* L R1,CVTPTR LOAD CVT L R1,CVTASVT-CVT(,R1) LOAD ASVT USING ASVT,R1 ADDRESS IT L R0,ASVTMAXU LOAD MAXIMUM ASID NUMBER FINDASCB DS 0H TM ASVTENTY,ASVTAVAL IS THIS ASSIGNED ASCB ? BO NEXTASCB NO, IGNORE THIS ENTRY L RE,ASVTENTY LOAD CURRENT ASCB ICM RF,15,ASCBJBNI-ASCB(RE) LOAD BATCH JOBNAME POINTER BNZ *+4+4 IF NZERO, MAY BE BATCH L RF,ASCBJBNS-ASCB(,RE) LOAD STC/TSO NAME POINTER CLC 0(8,RF),=CL8'MYJOB2' IS HERE TARGET JOB ASCB ? BE *+4+4+4+4 YES, FOUND TARGET NEXTASCB DS 0H LA R1,4(,R1) LOCATE NEXT ASCB ENTRY BCT R0,FINDASCB TRY TO NEXT B NOTARGET (TARGET JOB IS NOT ACTIVE) DROP R1 FORGET ASVT LR R4,RE GR4 --> TARGET SPACE ASCB * *----------------------------------* * * WAKE WAITING OUR PARTNER JOB * * *----------------------------------* L R3,CVTPTR LOAD CVT USING CVT,R3 ADDRESS IT POST JOBBECB,0, WAKES JOB-B + ASCB=(4),ERRET=CVTBRET DROP R3 FORGET CVT : : : : RETCD DC F'0' NAME/TOKEN RETURN CODE LEVEL DC F'0' NAME/TOKEN LEVEL PERSIST DC F'0' NAME/TOKEN PERSIST OPTION NAME DC CL16'MYJOB-ANCHOR' NAME/TOKEN NAME TOKEN DC XL16'00' NAME/TOKEN TOKEN : : COMMAREA DSECT JOBBECB DC F'0' WAITING ECB JOBAPARM DC CL80' ' INPUT PARAMETER JOBBRSLT DC CL256' ' PROCESSING RESULT :
ジョブBのプログラム ----+----1----+----2----+----3----+----4----+----5----+----6----+----7-- * *----------------------------------* * * EXTRACT OUR COMM-AREA ANCHOR * * *----------------------------------* L R0,=A(IEANT_SYSTEM_LEVEL) LOAD SYSTEM LEVEL VALUE ST R0,LEVEL SET IT L RF,CVTPTR LOAD CVT L RF,CVTCSRT-CVT(,RF) LOAD CSRTABLE L RF,X'14'(,RF) LOAD NAME/TOKEN VECTOR ? L RF,X'08'(,RF) LOAD IEANTRT ENTRY CALL (15), CALL IEANTRT TO GET COMM-AREA + (LEVEL,NAME,TOKEN,RETCD) ANCHOR LTR RF,RF SUCCESSFUL ? BNE NMTERROR NO, NAME/TOKEN ERROR ICM R2,B'1111',TOKEN GR2 --> OUR COMM AREA BZ CMAERROR IF NOT, COMM-AREA NOT AVAILABLE USING COMMAREA,R2 ADDRESS IT FOR OUR COMM AREA : : : * *----------------------------------* * * WAIT INPUT FROM PARTNER JOB * * *----------------------------------* WAIT ECB=JOBBECB WAITING JOB-A DATA MVC OURWORK,JOBPARM READ INPUT DATA : : MVC JOBRSLT,........ WRITE OUTPUT DATA : : : : RETCD DC F'0' NAME/TOKEN RETURN CODE LEVEL DC F'0' NAME/TOKEN LEVEL NAME DC CL16'MYJOB-ANCHOR' NAME/TOKEN NAME TOKEN DC XL16'00' NAME/TOKEN TOKEN : : COMMAREA DSECT JOBBECB DC F'0' WAITING ECB JOBAPARM DC CL80' ' INPUT PARAMETER JOBBRSLT DC CL256' ' PROCESSING RESULT : CVT DSECT=YES CVT IEANTASM , NAME/TOKEN SERVICE DECLARES
共通のデータ域を確保して初期設定するプログラムは、必要な設定が終わった後にアンカーポインターを作成するためにNAME/TOKENサービスを呼び出します。新しいトークンはIEANTCRルーチンを呼び出すことで作成することができます。複数空間で参照するアンカーポインターはシステムレベルのトークンとして作成する必要があり、呼び出し元はスーパーバイザー・モード(またはPSWキー0から7)でなければなりません。
作成済みのトークンはIEANTRTルーチンを呼び出すことで参照できます。レベルと名前を指定してIEANTRTルーチンを呼び出せば、名前に対応したトークン値が戻されます。この例ではトークンにGETMAIN済みの共通データ域のアドレスを使っています。ジョブAでGETMAINした共通データ域のアドレスは、NAME/TOKENサービスを介してジョブBに渡すことができます。
アンカーポインターが設定できれば、後は正しく同期を取るロジックを追加すればいいのです。このサンプルではプログラムの起動順やアンカーが設定されていなかったり、相手プログラムがアクティブでない場合の処理については載せていませんが、実際のプログラムでは必要になります。
空間をまたがったプログラム間通信を実装するには、CSAとWAIT/POSTによる方法以外にもクロスメモリー・サービスを利用して互いのリージョン内を直接参照する方法もあります。いずれもAPF許可がなければ作成できません。分類は中級にしましたが実際は上級編のプログラムでしょう。APF許可の取れないプログラムであれば、VTAMやTCPを利用した通信処理を利用する方法もあります。TCPを利用すれば同じプログラムで異なるOS間でのプログラム通信処理も可能になります。
Comment from HC Tsai
Time 2011年3月5日 at 22:47