• The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
Menu
  • The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
  • Let Me Out of Here!

    November 10, 2004 Hey, Ted

    Having read your article “Subprocedures: Better than Subroutines,” I have been inspired to use subroutines less and subprocedures more in RPG programs. However, I have come up against a problem that I can’t solve.

    In many of my programs I include a clean-up subroutine that runs when the program ends, whether the program ends normally or abnormally. The subroutine includes various house-keeping tasks, sets on the LR indicator, and executes a RETURN operation. You probably know what happens when I implement such a routine in a subprocedure. Instead of returning to the calling program, control returns to the calling routine within the program.

    How can I make my RPG program end from a subprocedure?

    –Rick

    As you’ve discovered, there is no RPG op code that ends a program. I suggest you replace the RETURN operation in the shutdown subprocedure to the C exit function. Here’s a short example program to illustrate the use of the exit function.

    H dftactgrp(*no) actgrp(*new)
    H bnddir('QC2LE')
    
    D SomeAmount      s              7p 2
    D SomeTypeField   s              1a
    
    D Quit            pr
    D Exit            pr                  extproc('exit')
    D                                3u 0 value
    
     /free
         if SomeAmount < *zero                                    ;
             Quit()                                               ;
         endif                                                    ;
    
               // ... some calcs omitted ...
    
         if SomeTypeField = 'X'                                   ;
             Quit()                                               ;
         endif                                                    ;
    
               // ... some more calcs omitted ...
    
         // Normal end of procedure
         Quit()                                                   ;
     /end-free
     * =========================================================  ;
    P Quit            b
     /free
         // clean-up calcs go here
         *inlr = *on                                              ;
         exit(0)                                                  ;
     /end-free
    P Quit            e
    

    Here are a few things to notice.

    • You need to bind to the QC2LE binding directory in order for the compiler to find the exit routine.

    • Prototype the exit function, specifying one argument–a three-digit unsigned integer.

    • As far as I know, any value from zero to 255 is acceptable as the argument to exit because the system won’t do anything with the value, anyway.

    To make sure that I wasn’t giving you bad advice, I asked Barbara Morris of IBM Toronto about your dilemma. She gave me quite a bit more useful information. Here it is, for the edification of us all.

    –Ted

    Calling exit( ) behaves the same as calling CEETREC. The behavior is complex, but basically what happens is that all contiguous call-stack invocations in the same activation group as the caller end. What it actually does depends on the activation groups of the entries in the call stack. Imagine the following call stack under two scenarios.

    Procedure Scenario 1 Scenario 2
    PGMmain AG1 AG1
    proc1 AG1 AG1
    proc2 AG1 AG2
    proc3 AG1 AG1

    Suppose proc3 issues the exit( ) or CEETREC( ). In scenario 1, in which the entire application is in same activation group, all the activations, including PGMmain, would end, as desired. In scenario 2, where proc2 is in a different activation group, only proc3 would end.

    If you have a cancel handler enabled, one of the parameters to the cancel handler is the value specified on the exit( ) or CEETREC( ). The cancel handler would be enabled by the top-level program/procedure in the application. The cancel handler would do the cleanup. If it wanted to pass the value back to the caller of the application, it could have access to the parameters of the top-level procedure, and pass back the exit status in one of those parameters. Or it could send a message to its caller.

    If you have the cancel handler do the cleanup, a good way to handle it is to have a cleanup procedure that is called both by normal end processing and from the cancel handler. The cleanup routine should keep track of what it has already done, in case it gets cancelled the first normal time and gets called again through cancel processing.

    Sending an escape message to a particular invocation is more reliable. If proc3 sends an escape to PGMmain, then activation group AG1 would end in both scenarios. But having a cancel handler is still a good idea, because the application might get ended through, say, the subsystem being ended.

    Below is some code for playing around with this. I used DSPLY with an exported variable to show whether the program really was ended, since non-exported variables are subject to RPG’s LR processing. You could also use static variables in subprocedures to show whether things got cleaned up.

    Create all the programs. Call EXITMAIN (uses exit), and answer some value to the DSPLYs. Call EXITMAIN again and notice the prompt values of the DSPLYs. Everything gets cleaned up.

    Now change the source for EXIT1 to use AG2 instead of AG1. Repeat the double call and see how nothing really got cleaned up.

    Do the same for EXITMMAIN, which uses an escape message from the subprogram and exit() at the top level to do the final cleanup. With everything being AGM1, everything gets cleaned up. With EXITM1 being AGM2, almost everything gets cleaned up, except the one program in AGM2.

    1. Using exit:

     * pgm EXITMAIN
    H actgrp('AG1')                                                
    D msg             s              5a   export                  
    C     'exitmain'    dsply                   msg                
    C                   call      'EXIT1'                          
    C     'exitmain aft'dsply    
    C                   return                                    
    
     * pgm EXIT1
    H actgrp('AG1')                                    
    H*actgrp('AG2')
    D msg             s              5a   export        
    C     'exit1'       dsply                   msg    
    C                   call      'EXIT2'              
    C     'exit1 after' dsply    
    C                   return                          
    
     * pgm EXIT2
    H actgrp('AG1') bnddir('QC2LE')                          
    D exit            pr                  extproc('exit')    
    D   rc                          10i 0 value              
    D msg             s              5a   export              
    C     'exit2'       dsply                   msg          
    C                   callp     exit(1)                    
    C     'exit2 after' dsply    
    C                   return                                
    


    2. Using an escape message:

     * pgm EXITMMAIN
    H actgrp('AGM1') bnddir('QC2LE')                        
    D msg             s              5a   export            
    D say             s             52a                    
    D exit            pr                  extproc('exit')  
    D   rc                          10i 0 value            
    C     'exitmmain'   dsply                   msg        
    C                   call(e)   'EXITM1'                  
    C     'exitmmain af'dsply                              
    C                   if        %error                    
    C     'exitmmain er'dsply                              
    C                   callp     exit(1)                  
    C                   endif                              
    C                   return                        
    
     * pgm EXITM1      
    H actgrp('AGM1')                                  
    H*actgrp('AGM2')
    D msg             s              5a   export      
    C     'exitm1'      dsply                   msg  
    C                   call      'EXITM2'            
    C     'exitm1 after'dsply                        
    C                   return                        
    
     * pgm EXITM2
    H actgrp('AGM1')
    D msg             s              5a   export            
    C     'exitm2'      dsply                   msg        
    C                   call      'EXITM3'                  
    C     'exitm2 after'dsply                              
    C                   return                              
    
     * CLLE pgm EXITM3 (could be CLP, doesn't matter what AG)
          SNDPGMMSG  MSGID(CPF9898) MSGF(QCPFMSG) MSGDTA('escape +
                       message') TOPGMQ(*SAME ('EXITMMAIN')) +    
                       MSGTYPE(*ESCAPE)                            
    

    –Barbara Morris

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Tags:

    Sponsored by
    Maxava

    Migrating to New IBM i Hardware?

    Whether you are moving to POWER9, Power10, or a cloud hosted system MAXAVA HAS YOU COVERED!

    Learn More

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Symantec Adds Regulatory Compliance to Security Management Tool How the i5s Compare with Other Big Boxes

    Leave a Reply Cancel reply

Content archive

  • The Four Hundred
  • Four Hundred Stuff
  • Four Hundred Guru

Recent Posts

  • LANSA Developing Business Intelligence Tool
  • Blazing The Trail For VTL In The Cloud
  • Data De-Dupe Gives VTL Customers More Options
  • Four Hundred Monitor, March 29
  • The Big Spending On IT Security Is Only Going To Get Bigger
  • IBM Tweaks Some Power Systems Prices Down, Others Up
  • Disaster Recovery: From OS/400 V5R3 To IBM i 7.4 In 36 Hours
  • The Disconnect In Modernization Planning And Execution
  • Superior Support: One Of The Reasons You Pay The Power Systems Premium
  • IBM i PTF Guide, Volume 25, Number 13

Subscribe

To get news from IT Jungle sent to your inbox every week, subscribe to our newsletter.

Pages

  • About Us
  • Contact
  • Contributors
  • Four Hundred Monitor
  • IBM i PTF Guide
  • Media Kit
  • Subscribe

Search

Copyright © 2023 IT Jungle