05.3プログラム割込みのトラップ(SPIE,ESPIE)
業務用アプリケーションでは、誤ったデータによる演算の結果、プログラムが異常終了することがしばしば起こります。プログラムロジックには問題がないのにデータが原因でプログラム割り込みが引き起こされるためです。このようなことを防止するため、入力されたデータや、データセットから読み込んだデータの妥当性をチェックすることは、よく行われるプログラミング手法です。他の方法として、結果として誤りであったら、その誤りをなかったことにする方法もあります。読み込んだデータが悪いため、演算命令がエラーになったら、プログラムをそこで終了するのではなく、そのデータを捨てて、次のデータを処理できるようにできます。例外処理とも呼ばれ、コンパイラー言語などではON ERROR、TRY?CATCHなどの記述で行われます。MVSではSPIE,ESPIE APIによって例外処理を設定することができます。
SPIEはプログラム割り込みが発生した時、プログラムをABENDさせずに、予め指定されたルーチン(SPIE出口ルーチン)を実行してエラーが発生したことをプログラムに通知します。
0による除算をトラップしてメッセージを出力する
----+----1----+----2----+----3----+----4----+----5----+----6----+----7-- MAINLINE DS 0H : : SPIE TRAPPCHK,(9) TRAP ABENDS0C9 ST R1,PREVPICA SAVE PREVIOUS PICA * SLR R0,R0 CLEAR GR0 L R1,=F'100' LOAD DIVIDEND INTO GR1 D R0,=F'0' TRY TO DIVIDE BY ZERO * WTO '(MAIN)DO I LIVE ?' INFORM ALIVE MESSAGE : : 残りの処理があれば続ける : : L R1,PREVPICA LOAD PREVIOUS PICA SPIE MF=(E,(1)) RESTORE PREVIOUS ENVIRONMENT これは以前のSPIE環境に戻す処理。 他のモジュールから呼ばれる サブルーチンであれば必ず以前の 環境を戻すこと。 : : PREVPICA DC F'0' PREVIOUS SPIE PICA ADDRESS : : * *----------------------------------* * * SPIE EXIT ROUTINE * * * ============================== * * * GR0 -----> N/A * * * GR1 -----> PIE * * * GR2-13 --> SAME AT ABEND * * * GR14 ----> RETURN ADDR TO OS * * * GR15 ----> ENTRY ADDR * * *----------------------------------* TRAPPCHK DS 0H ENTER AT HERE WHEN OCCURED + PGM-CHECK INTERRUPTION LR R2,R1 GR2 --> OUR PIE WTO '(EXIT)OCCURED ZERO DIVIDE' INFORM ZERO DIVIDE ERROR BR RE RETURN TO OS : : 残りのトラップ処理があれば続ける : :
このようにSPIEを使うと、指定したプログラム割り込みであれば、発生してもABENDせずに、指定のSPIE出口ルーチンが実行されることでプログラムに通知されます。トラップルーチンにはPIEと言うパラメータ・リストが渡され、それを見ることでABENDの内容、発生したアドレスを知ることができます。このサンプルのようにPIE内容を変更しなければ、ABENDした次の命令からメインラインの実行を再開させることができます。
指定可能なすべてのプログラム割り込みをトラップして、独自のABENDメッセージを出す。
データ例外であれば、その入力データを捨てる。
----+----1----+----2----+----3----+----4----+----5----+----6----+----7-- MAINLINE DS 0H : : SPIE TRAPPCHK,((1,15)) TRAP ALL ABENDS0CX ST R1,PREVPICA SAVE PREVIOUS PICA * MAINLOOP DS : : 主処理のループ : : B MAINLOOP * BADDATA DS 0H WTO '(MAIN)IGNORE BAD TRANSACTION DATA' : : 誤ったデータを持った入力データを捨てる処理 : : B MAINLOOP : : PREVPICA DC F'0' PREVIOUS SPIE PICA ADDRESS : : : : * *----------------------------------* * * SPIE EXIT ROUTINE * * * ============================== * * * GR0 -----> N/A * * * GR1 -----> PIE * * * GR2-13 --> SAME AT ABEND * * * GR14 ----> RETURN ADDR TO OS * * * GR15 ----> ENTRY ADDR * * *----------------------------------* TRAPPCHK DS 0H ENTER AT HERE WHEN OCCURED + PGM-CHECK INTERRUPTION CLC 6(2,R1),=XL2'0007' DATA EXCEPTION(ABEND S0C7) ? BNE DOABEND NO, ABEND WITH DIAG MSG SPACE , LA RF,BADDATA LOAD RESUME ADDRESS STCM RF,B'0111',9(R1) SET IT IN RESUME PSW ADDRESS BR RE CONTINUE MAINLINE PROCESSING SPACE , DOABEND DS 0H LH R0,6(,R1) LOAD INTERRUPT CODE L R1,8(,R1) LOAD ABENDED ADDRESS LR RF,0 EDIT INTERRUPT CODE TO TEXT LA RF,240(,RF) I CH R0,=H'9' I BNH *+4+4 I SH RF,=H'57' V STC RF,SWTOLIST+28 SET INTERRUPT CODE IN MSG SLL R1,8 EDIT INTERRUPTED ADDRESS SRL R1,8 I SLR R1,RC V LR R0,R1 SET INTERRUPT ADDR IN MSG LA R1,SWTOLIST+39 I BAS RE,CNVRTX V WTO MF=(E,SWTOLIST) INFORM PROGRAM ABENDED MSG SVC 3 RETURN TO OS(END OF PROGRAM) CNVRTX DS 0H CONVERT GR0 TO HEX-DECIMAL LA R1,3(,R1) I LA RF,4 I STC R0,0(,R1) I NI 0(R1),X'0F' I TR 0(1,R1),CNVTRT I SRL R0,4 I BCTR R1,0 I BCT RF,*-2-4-6-4-4 I BR RE V CNVTRT DC CL16'0123456789ABCDEF' SWTOLIST DS 0F WTO 'THIS PROGRAM ABENDED(S0C0) OFFSET(X0000)',MF=L
サンプルなので無理して全部のプログラム割り込みをトラップしていますが、実際には必要なものだけに絞って行う方がよいでしょう。一般のアプリケーションであれば、0C7や0C9で十分かと思います。
ABENDしたアドレスや割り込みコードは出口ルーチンに渡される、PIE(Program Interruption Element)を参照すれば知ることができます。PIE内のPSWアドレスフィールドを書き換えれば、任意の場所からプログラムを再開させることができます。この例ではS0C7ABENDの場合にそれを行っています。
なおSPIEは24ビットモードのプログラムでなければ使用できません。31ビットモード・プログラムの場合は次に示す、ESPIEを利用します。
31ビットモード・プログラムにおけるSPIE(ESPIE)
----+----1----+----2----+----3----+----4----+----5----+----6----+----7-- MAINLINE DS 0H : : L R2,usrparm PASS USER OWN PARM TO EXIT-RTN ESPIE SET,TRAPPCHK,((1,15)), TRAP ALL ABENDS0CX + PARAM=(2) ST R1,PREVPICA SAVE PREVIOUS PICA * MAINLOOP DS : : 主処理のループ : : B MAINLOOP * BADDATA DS 0H WTO '(MAIN)IGNORE BAD TRANSACTION DATA' : : 誤ったデータを持った入力データを捨てる処理 : : B MAINLOOP : : : : L R1,PREVPICA LOAD PREVIOUS PICA ESPIE RESET,(1) RESTORE PREVIOUS ENVIRONMENT : 以前のESPIE環境に戻す場合 : : : PREVPICA DC F'0' PREVIOUS SPIE PICA ADDRESS : : : : * *----------------------------------* * * ESPIE EXIT ROUTINE * * * ============================== * * * GR0 -----> N/A * * * GR1 -----> EPIE(SEE IHAEPIE) * * * GR2-13 --> SAME AT ABEND * * * GR14 ----> RETURN ADDR TO OS * * * GR15 ----> ENTRY ADDR * * *----------------------------------* USING EPIE,R1 ADDRESS TO EPIE TRAPPCHK DS 0H ENTER AT HERE WHEN OCCURED + PGM-CHECK INTERRUPTION CLI EPIEICD1,7 DATA EXCEPTION(ABEND S0C7) ? BNE DOABEND NO, ABEND WITH DIAG MSG SPACE , L RF,=A(BADDATA+X'80000000') LOAD RESUME ADDRESS ST RF,EPIENXT1 SET IT IN RESUME PSW ADDRESS BSM 0,RE CONTINUE MAINLINE PROCESSING SPACE , DOABEND DS 0H LH R0,EPIEINC1 LOAD INTERRUPT CODE L R1,EPIENXT1 LOAD ABENDED ADDRESS LR RF,0 EDIT INTERRUPT CODE TO TEXT LA RF,240(,RF) I CH R0,=H'9' I BNH *+4+4 I SH RF,=H'57' V STC RF,SWTOLIST+28 SET INTERRUPT CODE IN MSG SLL R1,8 EDIT INTERRUPTED ADDRESS SRL R1,8 I SLR R1,RC V LR R0,R1 SET INTERRUPT ADDR IN MSG LA R1,SWTOLIST+39 I BAS RE,CNVRTX V WTO MF=(E,SWTOLIST) INFORM PROGRAM ABENDED MSG SVC 3 RETURN TO OS(END OF PROGRAM) CNVRTX DS 0H CONVERT GR0 TO HEX-DECIMAL LA R1,3(,R1) I LA RF,4 I STC R0,0(,R1) I NI 0(R1),X'0F' I TR 0(1,R1),CNVTRT I SRL R0,4 I BCTR R1,0 I BCT RF,*-2-4-6-4-4 I BR RE V CNVTRT DC CL16'0123456789ABCDEF' SWTOLIST DS 0F WTO 'THIS PROGRAM ABENDED(S0C0) OFFSET(X0000)',MF=L : : : : IHAEPIE , INCLUDE EPIE MAP
2番目のサンプルと同じものを、31ビットモード・プログラム用のESPIEで置き換えた例です。
ESPIEでは出口ルーチンに渡されるPIEはESPIE(Extend PIE)に変わり、そのフォーマットは異なります。そのためSPIEを使っている24ビットモード・プログラムを31ビットモードに書き換える場合、単にマクロをSPIEからESPIEに交換するだけでは済みません。対応するフィールドのオフセットをESPIE用に変更しなければなりません。3番目のサンプルでは直接オフセット値を指定せずに、EPIEのマッピングマクロを使用してフィールドを名前で参照するようにしました。
MVSはPIE用にIHAPIE、EPIE用にIHAEPIEマクロを提供しています。MSPではそれぞれKAAPIEとKAAEPIE、VOS3ではMVSと同じIHAPIEが利用できます。なおVOS3では31ビットモード・プログラム用のSPIE機能は存在しますが公開されていないため、ここでは紹介しません。
大量の入力データを処理するようなプログラムでは、その中にいくつかの誤りデータが入っていても、途中で処理をやめずにエラーデータだけをはずして、正常なデータについてはすべて処理しきってしまいたい、という仕様もあります。処理前にチェックしてはじくか、エラーになったものをはじくか、いずれの方法もありますが、後者であればSPIE/ESPIEを利用すれば、プログラムチェック割り込みによるABENDは回避できます。どちらの場合であってもどのデータをはずしたか、きちんとログを取って、完了コードも0ではなく4にするなど、運用面でも誤りに気づきやすい設計にすることが大切です。