Contents


Handling basic exceptions when programming with Metal C on zOS

Comments

When software does not take all possible circumstances into its consideration, exceptions can occur during program execution. These exceptions and interruptions cause the system to enter a state where the software and hardware need to work together to reach a decision. For a superscalar pipelined Z processor, the system usually follows these basic steps to find a solution to an exception:

  1. The exception is detected in the hardware.
  2. The processor control stops the instruction that caused the exception at the execution stage of the pipeline.
  3. The instructions that were fetched and decoded prior to the exception instruction are completed normally.
  4. The pipeline control (scheduler) flushes the instructions that are currently in the pipeline after the exception instruction.
  5. The processor takes a "snapshot" of the current pipeline state.
  6. The address of the exception instruction pointed to by the old Program Status Word (PSW ) is stored in the first 8K of storage.
  7. The hardware passes control to the OS's exception handler.
  8. The exception handler examines the exception and performs various actions such as:
    • Creating abend and core-dump events if the exception can't be handled by default.
    • If the exception is an I/O interrupt or valid page fault, service the interrupt first. Then, restore processor state to restart the program from old_PSW + instruction_length.

While it is the hardware that controls most part of the exception handling process, developers can control the outcome of abends or abnormal exits.

What zOS offers

Some languages provide exception handling capabilities. C++ offers the throw and catch mechanism, while C assists developers with routines defined in signal.h. Metal C users have the advantage of customizing the control and outcome of an exception using the rich set of assembler service macros provided with zOS.

Program interruptions

Service macros are like other HLASM instructions. They can be inserted in the generated assembly (.s) file after compiling the program using the –qMETAL and –S options. There are two system macros to help you handle your own exceptions on two levels:

  • Use a Program Interruption Exit (ESPIE FOR 31-bit or SPIE for 24-bit) macro to redirect the execution to a user exit to handle basic program interruptions. This article explains this process.
  • Use a Task Abnormal Termination Exit (ESTEAX) to investigate any abend. ESTEAX receives control on an abnormal termination and redirects to a user routine for proper actions. Because the interface is more complex than ESPIE, it will be the subject of another article.

Basic program interruptions that can be handled using ESPIE include the following 15 interruption codes from 01 to 0F:

Table 1. Basic interruptions
IdentificationInterruption code
BinaryHex
Operation P0000001 0001
Privileged operation P0000010 0002
Execute P0000011 0003
Protection P0000100 0004
Addressing P0000101 0005
Specification P0000110 0006
Data P0000111 0007
Fixed-pt overflow P0001000 0008
Fixed-pt divide P0001001 0009
Decimal overflow P0001010 000a
Decimal divide P0001011 000b
HFP exp. overflow P0001100 000c
HFP exp. underflow P0001101 000d
HFP significance P0001110 000e
HFP divide P0001111 000f

Establishing an entry

Use the ESPIE SET macro to give control to an exit routine upon exception and establish Program Interruption Exit. For example, to give control to an exit routine named EXIT for any of the 15 interruptions:

ESPIE SET,EXIT,((1,15))

The first operand SET establishes the exit. The second operand is the name of the exit routine. The third and last operands specify the types of interrupts handle. The format ((1,15)) means all types from 1 to 15. If you want to handle specific types, use (1,15) to handle only type 1 and 15.

This macro expands to the instructions shown here:

Listing 1. ESPIE SET macro
11 ESPIE SET,EXIT,((1,15))
12+* MACDATE = xx/xx/xx
13+  CNOP     0,4
14+  BAS      1,*+20
15+IHB00002  EQU *
16+  DC       A(EXIT)             EXIT ROUTINE ADDRESS
17+  DC       A(0)                PARAMETER LIST ADDRESS
18+  DC       B?0111111111111111? INTERRUPTION MASK
19+  DC       B?0000000000000000?
20+  DC       A(0)                PLACE HOLDER
21+  LA       0,4                 FUNCTION CODE
22+  LA       15,28
23+  SVC      109
24   ST       1,token              Save EPIE

Statement 19 contains 1-bit for each type of the 15 interruptions you want to cover. For this example, I want to cover all 15. An Extended Program Interruption Element is created when the ESPIE macro is called. It contains data about the interruption. The data is saved in an area called Program Interruption Control Area (PICA). The address of the area is returned in register 1. In the above example, register 1 is saved in token. When the control passes to the exit routine, the system puts the information shown in Table 2 in PICA of the EPIE.

Note: Only the useful ones are shown, full EPIE can be found in MVS Data Areas Volume 2, see Related topics for a link.

Table 2. Useful PICA information
OffsetTypeLengthNameDescription
Dechex
0 0 Character 4 EPIEEPIE EPIE block identifier C'EPIE'
4 4 Address 4 EPIEPARM Parameter list address
8 8 Character 64 EPIEGPR 32-bit GPRs at time of interruption
72 48 Character 8 EPIEPSW EC mode 8-byte old PSW at time of interruption
74 4A Bitstring 1 EPIECCPM Condition code and program mask
76 4c Address 4 EPIENXT1 Address of next instruction
81 51 Bitstring 1 EPIEILC1 Instruction length code
83 53 Bitstring 1 EPIEICD1 Program interrupt code
160 A0 Character 128 EPIEG64 64-bit GPRs at time of interruption
296 128 Character 16 EPIEPS16 16-byte PSW before interruption

You can access the information in Table 2 by providing the offset to the address in register 1. The Instruction Length Code and old PSW are useful when writing the exit routine. The usage is discussed in More advanced exits.

Example

When the control passes to the exit routine, the system assigns the registers. If the exit routine has I/O operations, the system preserves the following registers:

  • GPR 0: Used as a work register by the system.
  • GPR 1: Address of the PIE or EPIE for the task that caused the interruption.
  • GPR 14: Return address
  • GPR 15: Address of the exit routine

A simple example is used in Listing 2 to demonstrate how to use ESPIE SET to quit a program with divided-by-zero exception gracefully.

Listing 2. Main program
int main(){
    int divident=10;
    int divisor=0;
    int quotient=divident/divisor;
    return 0;
}

Compiling with MetalC option and without optimization levels yields the assembly code fun.s (see Downloadable resources to get the fun.s file).

Note: The function property and post-fix blocks are excluded because they are irrelevant. If assembling and running this program, the system terminates the program because of a fixed-point divide exception.

You'll first want this program to quit gracefully with a return value of 0, regardless of the exception. To accomplish this, insert the ESPIE SET macro at the beginning of fun.s before entering the MAIN routine:

Listing 3. ESPIE macro initialization
USING *,15
ESPIE SET,EXIT,((1,15))
DROP  15
J     MAIN

Add the routine EXIT after the main routine (label @@LAB@2 in fun.s):

Listing 4. Exit routine that returns 0
EXIT     DS    0H
         BR    14

Branching to 14 is all you need to do because GR14 contains the return address and you only want to return the address without changing the return code. Assembling and running the program gives the return code = 0, with a normal exit. You can also add extra code to EXIT to make the program return with a different return code (for example, 55) and release any previously allocated storage, such as Listing 5.

Listing 5. Exit routine that returns 55
EXIT            DS        0F
                DROP
                LR        3,13
                L         13,4(,13)
                ST        15,16(,13)
RETURN   LARL   15,RETURN
                USING RETURN,15
                STORAGE RELEASE,LENGTH=160,ADDR=(3)
                DROP      15
                L         15,16(,13)
                LA        15,55       return 55 when
                                      interruption happens
                L         14,12(,13)
                BR        14
                DS        0F

More advanced exits

Besides the simple exit shown in Listing 5, you can use more complicated routines for the exit, including:

  • Print an error message and resume execution at the address of the next instruction.
  • If the interruption is caused by the invalid data, you can issue a re-try after correcting the data by subtracting Instruction Length Code (ILC) provided in Table 2 from the old PSW.
    Note: Use re-try with caution so that the program doesn't go into an interruption loop.
  • Modify the old PSW or just do a simple JUMP operation to another label. This continues the control at a different place in the program, thus skipping the faulting instruction.

Conclusion

In this article you learned techniques to handle basic system interruptions and exceptions. This can happen on zOS when using zOS assembler services when programming with Metal C, where language-specific libraries are not available to assist. You learned to utilize assembler service macros provided by zOS to create low-level exception handling routines to change the program's reaction to exceptions and interruptions.

Acknowledgement

Thanks to Visda Vokhshoori whose technical advice helped construct this article.


Downloadable resources


Related topics


Comments

Sign in or register to add and subscribe to comments.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Rational
ArticleID=1019377
ArticleTitle=Handling basic exceptions when programming with Metal C on zOS
publish-date=11042015