C/C++

C/C++

C/C++

Your one-stop destination to learn and collaborate about the latest innovations in IBM C/C++ for z/OS compilers to develop high-performing C/C++ applications and system programs on z/OS while maximizing hardware use and improving application performance.

 View Only

Handling basic exceptions when programming with Metal C on zOS

By FANG LU posted Mon July 06, 2020 04:34 AM

  
Disclaimer: This blog was origianally posted by Tianju Xu and migrated to this community.

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
basic_interruptions.jpg

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
useful_PICA_information.jpg
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

PDF of this content
rational-basic-exceptions-when-programming-metalc-zos-trs-pdf.pdf
Assembly code (fun.zip | 1KB)
 fun.zip

Related topics

  • For a detailed definition of the z/Architecture, read z/Architecture Principles of Operation, IBM Publication No. SA22-7832-03.
  • For reference information to use in debugging user or system programs, read z/OS V2R1 MVS Data Areas Volume 2, IBM Publication (GA32-0936-02).
  • Read the MVS Programming: Assembler Services Guide, on the z/OS 2.1.0, z/OS MVS Knowledge Center).
0 comments
14 views

Permalink