業務用アプリケーションでは、誤ったデータによる演算の結果、プログラムが異常終了することがしばしば起こります。プログラム・ロジックには問題がないのにデータが原因でプログラム割込みが引き起こされるためです。このようなことを防止するため、入力されたデータやデータセットから読み込んだデータの妥当性をチェックすることは、よく行われるプログラミング手法です。他の方法として、結果として誤りであったらその誤りをなかったことにする方法もあります。読み込んだデータが悪いために演算命令がエラーになったら、プログラムをそこで終了するのではなく、そのデータを捨てて次のデータを処理するようにできます。例外処理とも呼ばれ、コンパイラー言語などではON ERROR、TRY~CATCHなどの記述で行われます。
MVSでは、SPIEまたはESPIEマクロによって例外処理を設定することができます。SPIE/ESPIEは、プログラム割込みが発生した時に、プログラムをABENDさせずに予め指定されたルーチン(SPIE出口ルーチン)を実行してエラーが発生したことをプログラムに通知します。
0による除算をトラップしてメッセージを出力する
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 |
----+----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 R14 RETURN TO OS : : 残りのトラップ処理があれば続ける : : |
SPIEを使うと、指定した種類のプログラム割込みであれば、それが発生してもABENDせずに指定のSPIE出口ルーチンが実行されることでプログラムに通知されます。トラップ・ルーチンにはPIEというパラメータ・リストが渡され、それを見ることでABENDの内容、発生したアドレスを知ることができます。このサンプルのように、PIE内容を変更しなければABENDした次の命令から実行を再開させることができます。
指定可能な全てのプログラム割込みをトラップして、独自のABENDメッセージを出す。
データ例外であれば、その入力データを捨てる。
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 |
----+----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 R15,BADDATA LOAD RESUME ADDRESS STCM R15,B'0111',9(R1) SET IT IN RESUME PSW ADDRESS BR R14 CONTINUE MAINLINE PROCESSING SPACE , DOABEND DS 0H LH R0,6(,R1) LOAD INTERRUPT CODE L R1,8(,R1) LOAD ABENDED ADDR14SS LR R15,0 EDIT INTERRUPT CODE TO TEXT LA R15,240(,R15) I CH R0,=H'9' I BNH *+4+4 I SH R15,=H'57' V STC R15,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 R14,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 R15,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 R15,*-2-4-6-4-4 I BR R14 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ビット・モードのプログラムの場合はSPIEではなくESPIEを利用します。
31ビットモード・プログラムにおけるSPIE(ESPIE)
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 |
----+----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 R15,=A(BADDATA+X'80000000') LOAD RESUME ADDRESS ST R15,EPIENXT1 SET IT IN RESUME PSW ADDRESS BSM 0,R14 CONTINUE MAINLINE PROCESSING SPACE , DOABEND DS 0H LH R0,EPIEINC1 LOAD INTERRUPT CODE L R1,EPIENXT1 LOAD ABENDED ADDRESS LR R15,0 EDIT INTERRUPT CODE TO TEXT LA R15,240(,R15) I CH R0,=H'9' I BNH *+4+4 I SH R15,=H'57' V STC R15,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 R14,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 R15,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 R15,*-2-4-6-4-4 I BR R14 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マクロを提供しています。
大量の入力データを処理するようなプログラムでは、その中にいくつかの誤りデータが入っていても、途中で処理をやめずにエラー・データだけを外して正常なデータについては全て処理しきってしまいたいという仕様もあります。処理前にチェックしてはじくか、エラーになったものをはじくか何れの方法もありますが、後者であればSPIEやESPIEを利用すれば、プログラム割込みによるABENDは回避できます。どちらの場合であっても、どのデータを外したかをきちんとログを取って、完了コードも0ではなく4にするなど運用面でも誤りに気付きやすい設計にすることが大切です。