- 「メインフレーム・コンピューター」で遊ぼう - http://www.arteceed.net -

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にするなど、運用面でも誤りに気づきやすい設計にすることが大切です。