• 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
    ARCAD Software

    Embrace VS Code for IBM i Development

    The IBM i development landscape is evolving with modern tools that enhance efficiency and collaboration. Ready to make the move to VS Code for IBM i?

    Join us for this webinar where we’ll showcase how VS Code can serve as a powerful editor for native IBM i code and explore the essential extensions that make it possible.

    In this session, you’ll discover:

    • How ARCAD’s integration with VS Code provides deep metadata insights, allowing developers to assess the impact of their changes upfront.
    • The role of Git in enabling seamless collaboration between developers using tools like SEU, RDi, and VS Code.
    • Powerful extensions for code quality, security, impact analysis, smart build, and automated RPG conversion to Free Form.
    • How non-IBM i developers can now contribute to IBM i projects without prior knowledge of its specifics, while ensuring full control over their changes.

    The future of IBM i development is here. Let ARCAD be your guide!

    Watch Now

    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

Volume 4, Number 38 -- November 10, 2004
THIS ISSUE
SPONSORED BY:

Linoma Software
ProData Computer Svcs
WorksRight Software

Table of Contents

  • Executing Dynamic Calculations with Embedded SQL
  • Let Me Out of Here!
  • More Conditional Sorting with SQL

Content archive

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

Recent Posts

  • Meet The Next Gen Of IBMers Helping To Build IBM i
  • Looks Like IBM Is Building A Linux-Like PASE For IBM i After All
  • Will Independent IBM i Clouds Survive PowerVS?
  • Now, IBM Is Jacking Up Hardware Maintenance Prices
  • IBM i PTF Guide, Volume 27, Number 24
  • Big Blue Raises IBM i License Transfer Fees, Other Prices
  • Keep The IBM i Youth Movement Going With More Training, Better Tools
  • Remain Begins Migrating DevOps Tools To VS Code
  • IBM Readies LTO-10 Tape Drives And Libraries
  • IBM i PTF Guide, Volume 27, Number 23

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 © 2025 IT Jungle