SRB – Service Request Block Overview

A Service Request Block (SRB) defines a dispatchable unit of work (Service Routine) in MVS.  A dispatchable unit of work is just a fancy way of saying some code that will be run by the dispatcher.  A SRB as opposed to a Task Control Block is considered a lightweight task.  This simply means it has less overhead associated with creating and dispatching it.  It also means that the capabilities are more limited.  SRB routines always run in supervisor mode.  They may not issue SVC calls and they are nonpreemptiable – meaning a higher priority task cannot preempt them.

SRB routines can be scheduled to run in any Address Space.  This makes them very useful for cross memory access in a pre-XA environment.  This is exactly what we will ultimately do with our SRB routine.  We will schedule it into an address space to allow us to copy local memory into a Common Service Area (CSA) storage (shared memory location).

SRB routines are fairly simple but we do have to be careful since we are writing code that executes in supervisor mode and key zero.  When I was initially testing my SRB code I did manage to crash my MVS system a few times due to simple coding mistakes. Fortunately, with Hercules I can IPL and be back up and running quickly.  It also helps that I am the only user on the system.

A SRB routine is created by allocating some memory to hold the SRB and then using the SCHEDULE macro to schedule it for execution.  The SRB must reside in fixed, commonly-addressable storage.

SRB Control Block

The SRB is defined by the macro IHASRB in SYS1.MACLIB.

SRBSECT  DSECT
SRB      DS    0A
SRBID    DS    CL4                      EBCDIC ACRONYM   FOR SRB
SRBFLNK  DS    A                        FORWARD CHAIN FIELD
SRBASCB  DS    A                        PTR TO ASCB OF ADDRESS SPACE
*                                       SRB IS TO BE DISPATCHED TO
SRBFLC   DS    0CL8                     SRB AREA MOVED TO LOW CORE
SRBCPAFF DS    BL2                      CPU AFFINITY MASK
SRBPASID DS    H                        PURGEDQ ASID IDENTIFIER
SRBPTCB  DS    A                        PURGEDQ TCB IDENTIFIER
SRBEP    DS    A                        ENTRY POINT OF ROUTINE
SRBRMTR  DS    A                        ADDRESS OF RESOURCE MGR RTN
SRBPARM  DS    A                        USER PARAMETER
SRBSAVE  DS    A                        SAVE AREA POINTER
SRBPKF   DS    B                        PROTECT KEY INDICATION
SRBPRIOR DS    B                        PRIORITY LEVEL INDICATION
SRBPSYS  EQU   0                        SYSTEM PRIORITY LEVEL
SRBPNONQ EQU   4                        NON-QUIESCEABLE PRIORITY
         DS    BL2                      RESERVED
         DS    A                        RESERVED
SRBEND   EQU   *                        END OF SRB
SRBSIZE  EQU   SRBEND-SRBSECT           SIZE OF SRB

SRBID is the eyeball identifier for the block and should contain ‘SRB .

SRBFLNK if the forward chain pointer and should be initialized to binary zeros.

SRBASCB is the address of the ASCB for the address space this SRB is to be dispatched into.

SRBCPAFF is a bitmask that indicates which CPUs may dispatch this SRB.  If it is binary zero or all ones the SRB can be dispatched to any CPU.  Since MVS 3.8 usually only runs on single CPU systems we can set it to zeros.

SRBPASID may contain a pointer to the ASCB of the address space associated withthis SRB.  It may be set to zero if SRBPTCB is also zero otherwise it must be specified.

SRBPTCB may contain a pointer to the TCB associated with this SRB.  If it is specified the SRBPASID field must also be set.  If these fields are set and a double failure occurs then the associated TCB will be scheduled for abnormal termination (ABEND).  A double failure occurs when an error has been trapped by a recovery routine and the recovery routine also fails.  Setting this field also allows the SRB to be purged if the associated TCB is terminated.  This field may be set to zero if not needed.

SRBEP is the entry point of the SRB routine.

SRBRMTR is the address of a Resource Manager Termination Routine that is called if the SRB is purged before it is scheduled.  The RMTR is responsible for any cleanup.

SRBPARM is a fullword parameter value that is passed to the SRB routine when it is dispatched.

SRBSAVE is the address of the status save area and must be initialized to zeros.

SRBPKF specifies the PSW protect key for the SRB routine.  The high-order four bits specify the protect key and the low-order four bits must be zero.

SRBPRIOR is the priority of a GLOBAL SRB.  GLOBAL SRBs are dispatched at a higher priority than any address space.  LOCAL SRBs are dispatched at the priority of the address space they run in but at a higher priority than any TCB.  GLOBAL SRBs have an additional priority level that indicates if they are for general system usage or a special priority necessary to quiesce SRBs.  A value of zero indicates a general system SRB.  A value of four indicates a priority of NONQ (nonquiesceable).  We can always set this value to zero.

The additional reserved fields should be set to binary zeros.

CSA – Global Storage

The SRB must be located in Fixed, Global storage.  When system storage is allocated by GETMAIN the type of stroage is specified by the subpool.  Each system subpool has a set of characteristics associated with it.  We will place our SRB in Common Service Area (CSA) stroage.  There are several subpools that are associated with CSA, each haveing different characteristics.

Subpool Pageable Protect Key Fetch Protect
227 Fixed Requester Key Yes
228 Fixed Requester Key No
231 Pageable Requester Key Yes
239 Fixed Zero Yes
241 Pageable User Key No

For our purposes we will use subpool 228 as it meets our requirements of being fixed (nonpageable) CSA.  Now is proabably a good time to mention that CSA storage is explicitly freed.  Once it is allocated by a GETMAIN request it remains allocated untill a FREEMAIN is issued, or until the next IPL.  If we allocate CSA we should always have a plan to free it.

APF Authorization

Before we can allocate CSA storage we must be authorized.  There are various ways to accomplish this goal.  We can run from an authorized library and set the AC flag at linkedit.  When the program specified on the EXEC statement in JCL is in an APF authorized library and the AC flag is set in the load module a bit will be set in the JSCB indicating the program is APF authorized.  Since I am interested in poking around inside MVS and since I am not too concerned about security on my personal MVS system I have installed a user SVC that will set or clear the APF bit in the JFCB.  By calling the SVC to set the bit it appars to MVS that I am running from an APF authorized library.

Once we have the APF bit set we can use the MODESET macro to get into supervisor state and key zero.  The MODESET macro has two parameters: MODE= and KEY=.  MODE is used to set the PSW to either supervisor state (MODE=SUP) or problem program stat (MODE=PROB).  The KEY parameter can be used to set the PSW protection key to zero (KEY=ZERO) or the protect key associated with the TCB (KEY=NZERO).  It should be noted that once we are in supervisor mode we can also switch PSW keys using the SPKA privledged instruction.

A Simple Program To Schedule A SRB

We now know enough to write a simple program to schedule a SRB.  Our initial SRB routine will not do anything except immediately exit but it will allow us to get through the basics of creating, scheduling and running a SRB routine.

SRB01    CSECT ,
        STM   R14,R12,12(R13)
        LR    R12,R15
        USING SRB01,R12
*
        LA    R1,SAVEA           CHAIN
        ST    R13,4(,R1)              ON
        ST    R1,8(,R13)                SAVE
        LR    R13,R1                        AREA

We begin by saving the caller’s registers, establishing a base register, and setting up a new register save area.

*                                                     
******************************************************
*                     GET INTO SUP STATE, KEY ZERO    
******************************************************
*                                                     
         LA    R1,=C'AUTH'        << GET APF AUTH >>  
         SVC   245                <<     AC = 1   >>  
*                                                     
         MODESET MODE=SUP,KEY=ZERO                    
*                                                     
         LA    R1,0               << RESET APF AUTH >>
         SVC   245                <<      AC = 0    >>

Next I invoke my user SVC to establish APF authorization. On my system I use SVC 245. If you run from an APF authorized library you can remove the SVC 245 calls. If you have a similar SVC installed on your system you may need to modify the code to work.

Next we issue the MODESET macro to set our PSW to supervisor state and protect key zero. Once we are in supervisor state I usually call my SVC 245 to turn off the APF bit in the JSCB. As long as we are in supervisor state or in PSW protect key of 0 through 7 we are considered APF authorized by MVS.

*****************************************************
*                       SET UP CSA STORAGE           
*****************************************************
*                                                    
         LA    R4,WKLEN           LENGTH OF WORK AERA
*                                                    
         GETMAIN R,LV=(R4),SP=228                    
*                                                    
         LR    R6,R1                                 
         USING WKAREA,R6          MAP CSA STORAGE    
*                                                    
         XC    WKAREA(WKLEN),WKAREA

Now that we are in supervisor state and key zero we can allocate our CSA storage. WKLEN is an equated symbol that represents the lenght of our DSECT used to map our CSA storage.  We can then issue a GETMAIN request for subpool 228 to get CSA storage that is globally accessable from all address spaces.  This storage is fixed, non-pageable and will not be fetch protected.  We then save the address of our CSA storage in register 6 and map it with our DSECT.  Finally the storage area is cleared to binary zeros using the exclusive or characters instruction.

WKAREA   DSECT ,                   
SRBAREA  DS    CL(44)              
SRBCODE  DS    CL(ENDSRTN-SRBRTN)  
*                                  
*                                  
WKLEN    EQU   *-WKAREA

Here is our DSECT for our common storage.  First we need 44 bytes to contain the SRB control block.  Next we need a place to copy our SRB routine executable code into CSA.  Since we ultimately plan to schedule a SRB into another address space the code in our private storage area would be unavailable.

*                                                     
         L     R8,CVTPTR          CVT ADDRESS         
         L     R8,0(,R8)          PSATNEW             
         L     R8,12(,R8)         CURRENT ASCB (OURS)

Next we get the address of the ASCB for the address space we are currently located.  First we get the address of the CVT which is always located in low memory at location X’10’ .  I often simply would code  L   R8,16  but here I use the label generated by the CVT mapping macro.  The first word of the CVT points to an area that contains the address of our TCB and our ASCB that is currently dispatched.  We get the ASCB address in register 8 and save it for later.

         LA    R2,SRBCODE         SRB CODE IN CSA      
         LA    R3,ENDSRTN-SRBRTN  LENGTH OF SRB ROUTINE
         LA    R4,SRBRTN          MODEL CODE TO COPY   
         LR    R5,R3                                   
         MVCL  R2,R4              COPY INTO CSA

Now we need to copy our SRB routine into CSA.  Here it set up the registers and use the MVCL instruction to copy the code.  You could also use one or more MVC instructions depending on the length of the code.  The advantage of using MVCL is we don’t have to keep checking the size of the SRB executable routine and add an additional MVC instruction when we exceede a 256 byte boundary.

         LA    R7,SRBAREA         SRB STORAGE AREA
         USING SRB,R7                             
         XC    0(SRBSIZE,R7),0(R7)    CLEAR

Next I clear the SRB control block to binary zeros.  This is not really necessary since I cleared the entire area after the GETMAIN but I include it here so when we later reuse the SRB control block I am reminded to clear it first.

         MVC   SRBID,=CL4'SRB '   SRB ID                      
*                                                             
         ST    R8,SRBASCB         TARGET ASCB TO SCHEDULE TO  
*                                                             
*                                                             
         LA    R1,SRBCODE                    SRB ENTRY POINT  
         ST    R1,SRBEP                                       
*                                                             
         LA    R1,SRBCLEAN-SRBRTN(,R1)       SRB PURGE ROUTINE
         ST    R1,SRBRMTR                                     
*                                                             
         LA    R1,0                          PARM LIST        
         ST    R1,SRBPARM

Now we can fill in the required fileds for the SRB control block.  First we move in the eyeball identifier ‘SRB ‘.  For now we will schedule the SRB into our own address space.  We set the entry point address to the location in CSA where we copied the SRB routine executable code.  We also set the entry point of a purge routnie.  Since our SRB routine will immediately exit we don’t need to pass any parameters for now.  This completes our SRB control block and it is now ready for scheduling.

*************************************************
*                       SCHEDULE SRB AND WAIT    
*************************************************
*                                                
         SCHEDULE SRB=(R7),SCOPE=LOCAL

We can now use the SCHEDULE macro to schedule to add our SRB to the dispatcher queue.  To issue the SCHEDULE macro we must be in key zero and supervisor state.  We must also include the mapping macros for the CVT and SRB data areas.  We must provide the address of our SRB in CSA and we set our priority to LOCAL or address space priority.

*                                                                                                                                       
         STIMER WAIT,DINTVL=WAITTIME         WAIT FOR SRB TO COMPLETE
*

Now we can issue a WAIT macro to pause and give the SRB time to execute.  Since our SRB does not do anything we don’t have any indication of when it is complete.  By waiting 10 seconds (which is a very long time) our SRB should have plenty of time to be dispatched and to complete execution before we clean up.

         DS    0D                                 
WAITTIME DC    C'00001000'        WAIT 10 SECONDS 
*                HHMMSSTH

Our wait time value must be in a double word in unpacked format.

CLEANUP  DS    0H                          
         LA    R4,WKLEN                    
*                                          
         FREEMAIN R,LV=(R4),A=(R6),SP=228  
*                                          
         MODESET MODE=PROB,KEY=NZERO

When we exit from our wait we can cleanup and exit.  First it is important to free the CSA stroage we allocated.  If we fail to free the CSA it will remain allocated until the next IPL.  Failure to free CSA storage can result if running out of CSA and make an IPL necessary.  It is always good practice to make every effort to clean up any system resources we use.  For production quality code we would include some error recovery code to free the CSA in the event our program abnormally terminated.  Since we are testing in a non-production environment it is not a necessity.

As part of our cleanup we also reset the PSW back to problem program state and TCB storage protect key.

EXIT     DS    0H                                   
         SLR   R15,R15            SET RETURN CODE  
         L     R13,4(,R13)        UNCHAIN SAVE AREA 
         L     R14,12(,R13)       RESTORE R14       
         LM    R0,R12,20(R13)     RESTORE REGS 0-12 
         BR    R14                RETURN TO CALLER

Now all that is left is to restore the caller’s registers and exit back to the caller.

Constants and Data Areas

We need to define one constant, our wait time.  We also need to generate any literal constants using LTORG.  We also have one data area, our register save area.

         DS    0D                                  
WAITTIME DC    C'00001000'        WAIT 10 SECONDS  
*                HHMMSSTH                          
*                                                  
*                                                  
         LTORG ,                                   
*                                                  
*                                                  
SAVEA    DS    18F                SAVE AREA

SRB Routine Code

Now all we need is the code for the SRB routine.  For now we can keep it very simple and as soon as our SRB routine is dispatched it will immediately exit.

SRBRTN   DS    0H                                     
         LR    R6,R15             SRB ROUTINE EP      
         USING SRBRTN,R6                              
*                                                     
         LR    R4,R1              SAVE PARM REGISTER  
*                                                     
         LR    R5,R14             SAVE RETURN ADDRESS 
*                                                     
         BR    R5                  DONE - EXIT        
*                                                     
*                                                     
SRBCLEAN DS    0H                  SRB PURGE ROUTINE                      
         BR    R14
*                     
*                     
         LTORG ,      
*                     
*                     
         DROP  R6     
*                     
*                     
ENDSRTN  EQU   *

CSA Storage Area Dsect

Now we need our DSECT that maps our CSA storage.

WKAREA   DSECT ,                   
SRBAREA  DS    CL(44)              
SRBCODE  DS    CL(ENDSRTN-SRBRTN)  
*                                  
*                                  
WKLEN    EQU   *-WKAREA

Finishing Touches

All that is missing to complete our program is a few system data area mapping macros and the register equates.

*                        
         PRINT OFF       
         CVT   DSECT=YES 
         IHASRB  ,       
         IHAPSA  ,       
*                        
*                        
R0       EQU     0 
R1       EQU     1  
R2       EQU     2  
R3       EQU     3  
R4       EQU     4  
R5       EQU     5  
R6       EQU     6  
R7       EQU     7  
R8       EQU     8  
R9       EQU     9  
R10      EQU     10 
R11      EQU     11 
R12      EQU     12 
R13      EQU     13 
R14      EQU     14 
R15      EQU     15 
*                   
         END     ,

Now we can compile and link edit our program. When we run the program it should wait for ten seconds and then exit.

JOB 6757  $HASP373 SRB01    STARTED - INIT 12 - CLASS A - SYS TCS3
JOB 6757  15.42.10   0.00.10   0.00.00  0000   SRB01     MVSSP    
JOB 6757  15.42.10   0.00.10   0.00.00  0000   SRB01     ######## 
JOB 6757  $HASP395 SRB01    ENDED

If we did something wrong it is very possible running this program will crash MVS. If that happens we can simply restart with an IPL and try to fix the problem.

Cross Memory Post

MVS 3.8 does no have any of the modern cross memory services available software or hardware.  In order to communicate between address spaces some system level code must be used.  Shared data can be placed into Common Service Area (CSA) storage which can be accessed by all address spaces.  If address space A wants to send a message to address space B, address space A could copy the message into an area of CSA known by both A and B.  The problem is how address space B knows the data is available.  We could loop looking for changes but that would consume a lot of CPU time and would not be very efficient.  We could look for changes and upon finding none we could wait some time interval before loooking again.  If the delay interval is set too low a large amount of CPU time would still be consumed.  If the interval is set too high the program becomes unresponsive since a delay is built in.

The normal way to synchronize between multiple tasks is to use the WAIT/POST functionality.  A task issues a WAIT supervisor call pointing to an Event Control Block (ECB).  The signaling task issues a POST supervisor call pointing to the same ECB to wake up the waiting task.  This works very well inside a single address space but does not work across address spaces.

MVS does provide a way to POST and ECB in another address space.  Is is a little more complicated than simply using the POST macro.  In addition to the SVC interface to POST, MVS also provides a Branch Entry.  Using Branch Entry is more complicated and requires the caller to be in supervisor mode and key zero.  It does have the advantage of allowing us to post and ECB in an address space other than our own.

Below is a summary of the registers used as input for Branch Entry POST.

R10 - POST Completion Code (to be placed into ECB)
R11 - ECB Address (high order bit of register must be set to X'80')
R12 - Error Return Address
R13 - ASCB Address of address space containing ECB
R14 - Linkage Return Address
R15 - Entry Point (CVT0PT01)

The high order bit of register 11 determines if the request is a cross memory post.  When calling the Branch Entry POST routine for a non-cross memory post we must hold the Local Lock.  For a cross memory post we do not have to hold any locks but we must be aware that the contents all registers except register 9 will be destroyed.

SRB Cross Memory Post

We now have enough to modify our simple SRB routine to post an ECB to signal a waiting task in another address space.  We will begin by expanding our CSA storage map to include a parmameter list to be passed to the SRB routine.

WKAREA   DSECT ,                                            
PARMLIST DS    0F            PARAMETER LIST FOR SRB ROUTINE 
WAITECB  DS    A             ADDRESS OF LOCAL ECB                            
WAITASCB DS    A             ADDRESS OF WAITING ASCB        
*                                                           
SRBAREA  DS    CL(44)                                       
SRBCODE  DS    CL(ENDSRTN-SRBRTN)                           
*                                                           
*                                                           
WKLEN    EQU   *-WKAREA

We will pass two parameters to the SRB routine. The first is the address of the waiting ECB located in the private area and the second is the address of the ASCB for the waiting address space.  When our SRB routine is dispatched the address of the parmaeter list will be contained in register 1.

SRBRTN   DS    0H                                     
         LR    R6,R15             SRB ROUTINE EP      
         USING SRBRTN,R6                              
*                                                     
         LR    R4,R1              SAVE PARM REGISTER  
         USING PARMLIST,R4                            
*                                                     
         LR    R9,R14             SAVE RETURN ADDRESS 
*                                                     
*                                                     
         LA    R10,X'7F'          POST                
         SLL   R10,24                 COMPLETION CODE 
*                                                     
         L     R11,WAITECB        ECB ADDRESS         
         LA    R1,X'80'           SET                 
         SLL   R1,24                 HIGH-ORDER       
         OR    R11,R1                          BIT    
*                                                     
         LA    R12,POSTERR        ERROR ROUTINE       
         L     R13,WAITASCB       ASCB ADDRESS        
*                                                     
         L     R15,CVTPTR         CVT ADDRESS                
         L     R15,CVT0PT01-CVTMAP(,R15)   POST BRANCH-ENTRY 
         BALR  R14,R15                                       
*                                                            
*                                                            
         BR    R9                  DONE - EXIT               
*                                                            
*                                                            
SRBCLEAN DS    0H                  SRB PURGE ROUTINE         
         XC    0(SRBSIZE,R1),0(R1)                           
         BR    R14                                           
*                                                            
*                                                            
POSTERR  DS    0H                  POST ERROR ROUTINE        
         BR    R14                                           
*                                                            
*                                                            
         LTORG ,

The first thing we do is copy the address of the parm list into register 4.  Next we save the return address in register 9 (this is because register 9 is the only register preserved when we call Branch Entry POST).  Next we set our post code into register 10.  It can be anything we want so I chose X’7F000000′ but it really doesn’t matter. Next we load the address of the ECB into register 11 and set the high order bit to X’80’ to indicate a cross memory post.  The address of our Post Error Routine goes into R12 and the address of the ASCB for the task that is waiting goes into R13.  All the remains is to get the address of the Branch Entry Post routine into register 15 and then call it.  Upon return the contents of all registers except R9 will be lost.  Since all we need to do is exit all we need is the return address we saved in R9.  We also added our Post Error Routine which immediately returns to the caller.

That’s it for the SRB routine but we still need some changes in our code that sets up and schedules the SRB.

                                                               
         L     R9,CVTPTR               CVT ADDRESS               
         L     R9,CVTASVT-CVTMAP(,R9)  ASVT ADDRESS              
         L     R9,ASVTENTY-ASVT(,R9)   FIRST ASCB POINTER        
         L     R9,4(,R9)               ASCB FOR ASID=0002 (JES2)

We could continue to schedule the SRB into our own address space and call the cross memory post routine but we really should schedule the SRB routine into a different address space so we really are doing a cross memory post.  I chose to use the JES2 address space since it is always active and I can be pretty confident it will be in ASID x’0002′.  Again it really doesn’t matter for now and any valid address space could be used.  To find the JES2 ASCB we get the Address Space Vector Table address from the CVT.  We then offset to the list of pointers to ASCBs.  The first entry is ASID x’0001′, the second ASID x’002′, and so on.  We take the address of the second ASCB which should be the addres space for JES2.  We save this address in R9.

         ST    R9,SRBASCB         TARGET ASCB TO SCHEDULE TO

Next we need to place the address of the ASCB  for JES2 into the SRB so it will be scheduled there.

                                                               
         LA    R1,PARMLIST                   PARM LIST               
         ST    R1,SRBPARM                                            
*                                                                    
         ST    R8,WAITASCB        SAVE OUR ASCB ADDRESS INTO PARMLIST
*                                                                    
         LA    R1,LOCALECB                                           
         ST    R1,WAITECB

Now we have to set up the parameter list for the SRB routine.  We place the pointer to the parm list into the SRB control block.  The address of the ASCB for our address space goes into the parameter list along with the address of an ecb.

         WAIT  1,ECB=LOCALECB     WAIT FOR SRB TO COMPLETE

Now instead of setting a delay we wait for our ECB to be posted by the SRB routine.

LOCALECB DC    F'0'

Here is the ECB we will wait on (located in our private storage).

         IHAASVT ,

Finally we need to include the mapping macro for the ASVT. With this we are done and our program can be compiled, link edited and we can run it. If everything goes as planned it should run very quickly.

JOB 6755  $HASP373 SRB02    STARTED - INIT 12 - CLASS A - SYS TCS3 
JOB 6755  15.39.08   0.00.00   0.00.00  0000   SRB02     MVSSP     
JOB 6755  15.39.08   0.00.00   0.00.00  0000   SRB02     ########  
JOB 6755  $HASP395 SRB02    ENDED

SRB Error Recovery

Now that we can schedule a SRB into another address space and use cross memory post to synchronize between the scheduling task and the SRB it is almost time to start writing some more complex code in our SRB routine. Before doing this we should probably consider what happens when our SRB routine encounters an error.

A Simple Test

We can start with a simple experiment to see what happens when our SRB routine fails.  All we need to do is cause an error condition which can easily be done by inserting the line:

         DC    X'0000'

into our SRB routine. It can be placed anywhere before the BALR to the POST routine. I placed it immediately after the LR to save the address of the parameter list.

When our program is compiled, link edited, and run we see nothing happen.  The SRB is scheduled, the task waits on the ECB, the SRB is dispatched and immediately fails with a S0C1 (or program interruption x’01’ to be more specific) and the ECB is never posted.  The scheduling task has no way of knowing the SRB failed and continues to wait.  If the job is not cancelled by an operator command it should eventually fail with a S522 ABEND.

This is probably not the behaviour we want when our SRB routine fails.  It would probably be better if the scheduling task failed when the SRB routine failed. This can be done with just a few more lines of code.  There are two fields in the SRB control block we need to fill in.  SRBPASID is a two byte field where we place the ASID (not the ASCB address) of the task associated with the SRB.  SRBPTCB is a pointer to the TCB associated with the SRB.  When these fields are specified and the SRB routine fails the failure will be propagated back to the TCB.

We already have the address of our ASCB so it is pretty simple to get the ASID value.  It is also pretty simple to get the address of our TCB at the same time we are finding our ASCB address.

          L     R8,CVTPTR          CVT ADDRESS         
          L     R8,0(,R8)          PSATNEW             
          L     R10,4(,R8)         CURRENT TCB ADDRESS  <------ Insert This Line
          L     R8,12(,R8)         CURRENT ASCB (OURS)

Now register 10 will contain the address of our TCB.

         ST    R10,SRBPTCB        PURGE TCB ADDRESS       
         SLR   R1,R1                                      
         ICM   R1,B'0011',ASCBASID-ASCB(R8)  GET OUR ASID 
         STH   R1,SRBPASID        PURGE ASID

By adding the above lines in our SRB setup code we now should be able to detect SRB errors.  Now we assemble, link edit, and run our test program.

JOB 6771  $HASP100 SRB03    ON INTRDR      RUN TEST PGM            
JOB 6771  $HASP373 SRB03    STARTED - INIT 12 - CLASS A - SYS TCS3 
JOB 6771  IEF450I SRB03 MVSSP - ABEND S0C1 U0000 - TIME=08.33.41   
JOB 6771   8.33.42   0.00.00   0.00.00  S0C1   SRB03     MVSSP     
JOB 6771   8.33.42   0.00.00   0.00.00  S0C1   SRB03     ########  
JOB 6771  $HASP395 SRB03    ENDED

And there we are!  When the SRB routine abnormally terminates our job ABENDs with a SoC1.  This is much better than waiting for the eventual S522 ABEND.

Functional Recovery Routines

Now we can deal with how to recover from an error while running a SRB routine.  We can’t use ESTAE to trap errors since ESTAE doesn’t work when running under a SRB.  Instead we have to use a Functional Recovery Routine (FRR) to trap the error.  If you are familiar with ESTAE then using a FRR should be pretty familiar.  When a FRR has been established and and error occurs, the FRR will be given control and then decide what action to take.

A FRR is established using the SETFRR macro.

         SETFRR A,FRRAD=(R3),WRKREGS=(R7,R8),RELATED=(DELETE)

This will add a FRR, the address of the FRR is contained in register 3, and we supply two work registers to the macro (registers 7 and 8).  The RELATED parameter is provided to allow a method of associating comments directly with the macro.  It must be specified but the value doesn’t matter to the expansion of the macro.  To use this macro we must include the mapping macros IHAFRRS and IHAPSA.

Now when an error occurs during execution of our SRB the FRR will be given control.  On entry to the FRR register 0 contains the address of a 200 byte FRR work area.  Register 1 contains the address of the SDWA.  Unlike an ESTAE routine where there are conditions where a SDWA may not be available, a SDWA is always passed to the FRR.

Here is a simple FRR that will resume execution of our SRB at a recovery point.  This type of recovery is good when we want to try an action that may fail and recover from that failure.

FRREXIT  DS    0H
         USING FRREXIT,R15
*
         L     R7,RETADDR
         SETRP RC=4,RETREGS=YES,RETADDR=(R7)
         BR    R14
*
RETADDR  DC    A(0)

We use the SETRP macro to set recovery options in the SDWA.  A return code of 4 specifys a retry action.  We indicate that the registers should be restored and that the retry address is contained in register 7.  We then return using register 14 to initiate the retry.

Note that the retry address (RETADDR) must be set before establishing the FRR environment.  We can’t specify it using something like A(RETRY) because we relocate the SRB code from our private area into CSA.  Instead we need to use something like this.

        LA    R1,RETRY
        ST    R1,RETADDR

We now have enough to implement a FRR in our SRB routine.  Here is the updated SRB routine.

SRBRTN   DS    0H                                            
         LR    R6,R15             SRB ROUTINE EP             
         USING SRBRTN,R6                                     
*                                                            
         LR    R4,R1              SAVE PARM REGISTER         
         USING PARMLIST,R4                                   
*                                                            
         LR    R9,R14             SAVE RETURN ADDRESS        
*                                                            
         LA    R1,RTRYRTN         ADDRESS OF RETRY POINT     
         ST    R1,RETADDR         SAVE FOR FRR               
*                                                            
         LA    R3,FRREXIT         ADDRESS OF FRR             
         SETFRR A,FRRAD=(R3),WRKREGS=(R7,R8),RELATED=(DELETE)
*                                                            
         LA    R10,X'41'          POST                       
         SLL   R10,24                 COMPLETION CODE        
*                                                            
         DC    X'0000'            SOC1 ABEND                 
*                                                            
         LA    R10,X'7F'          POST                       
         SLL   R10,24                 COMPLETION CODE        
*                                                            
RTRYRTN  DS    0H                                            
         SETFRR D,WRKREGS=(R7,R8),RELATED=(ADD)              
*                                                            
         L     R11,WAITECB        ECB ADDRESS                
         LA    R1,X'80'           SET                        
         SLL   R1,24                 HIGH-ORDER              
         OR    R11,R1                          BIT           
*                                                            
         LA    R12,POSTERR        ERROR ROUTINE              
         L     R13,WAITASCB       ASCB ADDRESS               
*                                                            
         L     R15,CVTPTR         CVT ADDRESS                
         L     R15,CVT0PT01-CVTMAP(,R15)   POST BRANCH-ENTRY 
         BALR  R14,R15                                       
*                                                            
*                                                            
         BR    R9                  DONE - EXIT               
*                                                        
SRBCLEAN DS    0H                  SRB PURGE ROUTINE     
         XC    0(SRBSIZE,R1),0(R1)                       
         BR    R14                                       
*                                                        
*                                                        
POSTERR  DS    0H                  POST ERROR ROUTINE    
         BR    R14                                       
*                                                        
*                                                        
FRREXIT  DS    0H                                        
         USING FRREXIT,R15                               
*                                                        
         L     R7,RETADDR                                
         SETRP RC=4,RETREGS=YES,RETADDR=(R7)             
         BR    R14                                       
*                                                        
RETADDR  DC    A(0)                                      
*                            
         LTORG ,             
*                            
*                            
         DROP  R4,R6         
*                            
*                            
ENDSRTN  EQU   *

Notice we included a SETFRR macro with the D or delete option to remove our FRR environment once we were past the  section of code where we wanted to trap errors.  If we did not delete our FRR and an error occured after our retry point a endless loop could occur.

Checking The Post Code

Now we have two different post codes used by our SRB routine.  A value of x’7F000000′ indicates success and a value of x’41000000′ indicates a failure.  There is nothing magic about these codes and they only have meaning withing our program.  We can update our scheduling program to report on the post code status.

         CLI   LOCALECB,X'7F'     CHECK FOR GOOD COMPLETION CODE 
         BE    SUCCESS                                           
*                                                                
         CLI   LOCALECB,X'41'     CHECK FOR FAIL COMPLETION CODE 
         BE    FAIL                                              
*                                                                
         WTO   '*** UNKNOWN POST CODE ***',ROUTCDE=(1,11)        
         B     CLEANUP                                           
*                                                                
*                                                                
SUCCESS  DS    0H                                                
         WTO   '*** SUCCESS POST CODE ***',ROUTCDE=(1,11)        
         B     CLEANUP                                           
*                                                                
*                                                                
FAIL     DS    0H                                                
         WTO   '*** FAIL POST CODE ***',ROUTCDE=(1,11)           
         B     CLEANUP

Now with these updates in place we can assemble, linkedit and execute our program.

JOB 6775  $HASP100 SRB04    ON INTRDR      RUN TEST PGM              
JOB 6775  $HASP373 SRB04    STARTED - INIT 12 - CLASS A - SYS TCS3   
JOB 6775  *** FAIL POST CODE ***                                     
JOB 6775   7.39.43   0.00.00   0.00.00  0000   SRB04     MVSSP       
JOB 6775   7.39.43   0.00.00   0.00.00  0000   SRB04     ########    
JOB 6775  $HASP395 SRB04    ENDED

We can remove our abend by commenting out the line

*------->DC    X'0000'            SOC1 ABEND

and then we assemble, linkedit and execute.

6778  $HASP100 SRB04    ON INTRDR      RUN TEST PGM            
6778  $HASP373 SRB04    STARTED - INIT 12 - CLASS A - SYS TCS3 
6778  *** SUCCESS POST CODE ***                                
6778   8.43.04   0.00.00   0.00.00  0000   SRB04     MVSSP     
6778   8.43.04   0.00.00   0.00.00  0000   SRB04     ########  
6778  $HASP395 SRB04    ENDED

An this proves we can capture and report on an error contition in our SRB routine.

Cross Memory Access Using A SRB

Now we know enough to modify our SRB routine to allow us to actually access data in another address space. We just need to make a few simple modifications to our existing code. For our initial test we will retrieve the Job Step program name contained in the JSCB. We can locate the JSCB by following a chain of control blocks beginning with the ASCB. The ASCB resides in common storage it can be accessed from any address space. The ASCB points to the ASXB which resides in private storage. The ASXB has a pointer to a TCB and the TCB points to the JSCB. The JSCB contains the program name we are looking for. We will add code to our SRB routine to follow the control block chain to locate the JSCB and then copy the program name into common storage before posting the ECB.

WKAREA   DSECT ,                                           
PARMLIST DS    0F            PARAMETER LIST FOR SRB ROUTINE
WAITECB  DS    A             ADDRESS OF LOCAL ECB          
WAITASCB DS    A             ADDRESS OF WAITING ASCB       
XMASCB   DS    A             CROSS MEM - ASCB ADDRESS      
XMPGM    DS    CL8           PROGRAM NAME RETURN AREA      
*                                                          
SRBAREA  DS    CL(44)                                      
SRBCODE  DS    CL(ENDSRTN-SRBRTN)                          
*                                                          
*                                                          
WKLEN    EQU   *-WKAREA

We begin by adding two additional fields to our SRB parameters in our CSA storage. First we pass the address of the ASCB of the address space we dispatched our SRB into (XMASCB). We also provide an area to return the program name (XMPGM).

         ST    R9,XMASCB          SAVE TARGET ASCB ADDRESS IN PARMS

We need to place the target ASCB address into the parameter list prior to scheduling the SRB. We already have the ASCB address so we just need to add one line of code.

         LA    R3,FRREXIT         ADDRESS OF FRR              
         SETFRR A,FRRAD=(R3),WRKREGS=(R7,R8),RELATED=(DELETE) 
*                                                             
         LA    R10,X'41'          POST                        
         SLL   R10,24                 COMPLETION CODE         
*                                                             
         L     R1,XMASCB          GET XM ASCB ADDRESS         
         L     R1,ASCBASXB-ASCB(,R1)   GET ASXB ADDRESS       
         L     R1,ASXBLTCB-ASXB(,R1)   GET TCB ADDRESS        
         L     R1,TCBJSCB-TCB(,R1)     GET JSCB ADDRESS       
         LA    R1,JSCBPGMN-IEZJSCB(,R1)  POINT TO PGM NAME    
         MVC   XMPGM,0(R1)                                    
*                                                             
         LA    R10,X'7F'          POST                        
         SLL   R10,24                 COMPLETION CODE         
*                                                             
RTRYRTN  DS    0H                                             
         SETFRR D,WRKREGS=(R7,R8),RELATED=(ADD)

We insert our new SRB code in the FRR protected section. This way if an error occurs (like a SOC4), the error will be trapped and reported back to the caller with a post code. The fail post code is initially placed into register 10. It will be updated if the program name is successfully copied. Next we get the pointer to the ASCB. From there we chain down to the JSCB and point to the program name field. We can then copy the program name into our parameter area in CSA. Once the name is successfully copied we can update the post code to indicate success and then continue on to the cross memory post.

SUCCESS  DS    0H                                         
         WTO   '*** SUCCESS POST CODE ***',ROUTCDE=(1,11) 
*                                                         
         MVC   WTOMSG+12(8),XMPGM                         
WTOMSG   WTO   '>>> ******** <<<',ROUTCDE=(1,11)          
         B     CLEANUP

If the ECB is posted with the success code we can copy the program name from the CSA area into our private storage.  In this case we copy it into a WTO message.  This will cause the program name to be displayed on the operator console.

          IHAASXB ,                 
          IKJTCB  DSECT=YES,LIST=NO 
          IEZJSCB ,

We need to add the mapping macros for the ASXB, TCB, and JSCB.

JOB 6806  $HASP100 SRB05    ON INTRDR      RUN TEST PGM            
JOB 6806  $HASP373 SRB05    STARTED - INIT 12 - CLASS A - SYS TCS3 
JOB 6806  *** SUCCESS POST CODE ***                                
JOB 6806  >>> HASJES20 <<<                                         
JOB 6806  20.46.41   0.00.00   0.00.00  0000   SRB05     MVSSP     
JOB 6806  20.46.41   0.00.00   0.00.00  0000   SRB05     ########  
JOB 6806  $HASP395 SRB05    ENDED

Now we assemble, link edit, and run our program.  Everything looks good – since we scheduled our SRB into the address space for JES2 we should expect to find HASJES20 as the job step program.  We have successfully accessed storage in the private area of another address space.