IBM Support

Initializing Context During Service Program Activation

Troubleshooting


Problem

This document provides information about how to have an initialization procedure called when a service program is activated, before any of its procedures are called by your application.
A service program is activated into an activation group the first time it is needed due to being bound to a program or other service program that is being activated.

For example, service program SRV1 is bound to program PGM1. When you call PGM1, PGM1 is activated, and the service programs that PGM1 uses are also activated, if they have not already been activated into that activation group.

Resolving The Problem

This document explains how you can have an initialization procedure called in a service program before any of its procedures get called during the normal flow of your application.

If you have a service program that needs some initialization code to run before the other procedures get called normally, you can take advantage of a C++ initialization feature.

For this technique, you need two extra modules for your service program:
  1. A C++ module that you can bind to any service program that needs this type of early initialization. This module calls a procedure called "INIT_SRVPGM". You can use the same C++ module for all your service programs.
  2. An ILE RPG module that has an exported procedure called "INIT_SRVPGM". This procedure calls the specific module-initialization procedures that your service program needs. 
One-time step to create the C++ module.

Module name: SRVPGM_INZ. Compile this source using CRTCPPMOD.
                    
   // c++ source starts here    
   extern "C" void INIT_SRVPGM(void);    
    class InitClass {                    
     public:                              
     InitClass() {      
       // Call the initialization procedure for this service program                   
       INIT_SRVPGM();  
     };                                  
   };                                    
   InitClass doInit;        
   // c++ source ends here     
         

Example 1: A service program with only one RPG module.
  • In this case, you can just add the INIT_SRVPGM procedure to the source for that module.
  • RPG module TEST1 for service program TEST1. It has three source files (see the source at the end of this discussion)
    • TEST1 with the code for the procedures
    • Copy file TEST1_H with the prototypes for the exported procedures
    • Binder source TEST1_BND for CRTSRVPGM
After you have compiled the C++ module above and you have compiled the TEST1 module, create your service program.
crtsrvpgm mylib/test1 
      module(mylib/srvpgm_inz
             mylib/test1)
      srcfile(mylib/mysrcfile)
      srcmbr(TEST1_BND)
Test: Use program TEST1_CALL to test it. 
  1. Call it first with a parameter of 'n'. This causes the program and its service program to be activated. The initialization procedure is called, but it does not call any other procedures.
    • 5 > call test1_call 'n'
          DSPLY  INIT_SRVPGM was called
  2. Call it again with a parameter of 'n'. Since it was already activated, the initialization procedure is not called. (And due to the parameter of 'n', it does not call any other procedures either.)
    • 5 > call test1_call 'n'
  3. Call it again with a parameter of 'y'. This time, the other procedure is called.
    • 5 > call test1_call 'y'
          DSPLY  fn1 was called with parameter 5
  4. From another session, call it for the first time with a parameter of 'y'. In this case, both the initialization procedure and the "ordinary" procedure are called.
    • 5 > call test1_call 'y'
          DSPLY  INIT_SRVPGM was called
          DSPLY  fn1 was called with parameter 5
Example 2: A service program with two modules that need this kind of initialization
  • In this case, it is convenient to have one module that just calls the initialization procedures from any other modules that need this kind of initialization.
  • Service program TEST2 has two "ordinary modules" TEST2A and TEST2B plus an initialization module TEST2INIT (See the source at the end of this discussion.) It has the following source files:
    • TEST2A
    • Copy file TEST2A_H
    • TEST2B
    • Copy file TEST2B_H
    • TEST2INIT
    • Binder source TEST2_BND for CRTSRVPGM
After you have compiled the C++ module above and you have compiled the TEST2A, TEST2B and TEST2INIT modules, create your service program.
crtsrvpgm mylib/test2 
      module(mylib/srvpgm_inz
             mylib/test2a
             mylib/test2b
             mylib/test2init)
      srcfile(mylib/mysrcfile)
      srcmbr(TEST2_BND)
Test: Use program TEST2_CALL to test it. 
When the program is first called, the initialization procedures are called and then the "real" procedure test2b() is called.
5 > call test2_call
    DSPLY  INIT_SRVPGM was called
    DSPLY  test2a_init was called
    DSPLY  test2b_init was called
    DSPLY  fn2b was called with parameter 25
When the program is called again, only the "real" procedure test2b() is called.
5 > call test2_call
    DSPLY  fn2b was called with parameter 25

Here is the source for the examples

For TEST1:
 
Copy file TEST1_H. For this example, it is in source file MODINIT. If you use a different source file, change the /COPY statements in your other RPG modules.
           dcl-pr fn1;
              num int(10) value;
           end-pr;
Module source file TEST1. Compile this using CRTRPGMOD.
       ctl-opt nomain;

       /copy MODINIT,TEST1_H

       dcl-proc INIT_SRVPGM export;
          // This procedure is called during service-program activation
          // by the C++ module SRVPGM_INZ

          dsply ('INIT_SRVPGM was called');

          // Do module-initialization tasks here

       end-proc;

       dcl-proc fn1 export;
          dcl-pi *n;
             num int(10) value;
          end-pi;

          dsply ('fn1 was called with parameter ' + %char(num));
       end-proc;
Binder source file TEST1_BND. List the exported procedures that are normally called by your applications. (It does not list the procedure INIT_SRVPGM that is called by the C++ module.)
 
STRPGMEXP PGMLVL( *CURRENT ) SIGNATURE("TEST1")
  EXPORT SYMBOL( "FN1" )
ENDPGMEXP
Source for test program TEST1_CALL
  1. Use CRTRPGMOD to compile the module, 
  2. Then use CRTPGM BNDSRVPGM(TEST1) to create the program.
        dcl-pi *n;
           call_fn1 char(1) const;
        end-pi;

        /copy MODINIT,TEST1_H

        if call_fn1 = 'y' or call_fn1 = 'Y';
           fn1 (5);
        endif;
        return;
For TEST2:

Copy file TEST2A_H. For this example, it is in source file MODINIT. If you use a different source file, change the /COPY statements in your other RPG modules.
           dcl-pr fn2a;
              num int(10) value;
           end-pr;
Module source file TEST2A. Compile this using CRTRPGMOD.
       ctl-opt nomain;

       /copy MODINIT,TEST2A_H

       dcl-proc test2a_init export;
          // This procedure is called during service-program activation
          // by module TEST2INIT

          dsply ('test2a_init was called');
       end-proc;

       dcl-proc fn2a export;
          dcl-pi *n;
             num int(10) value;
          end-pi;
 
          dsply ('fn2a was called with parameter ' + %char(num));
       end-proc;                                      
Copy file TEST2B_H. For this example, it is in source file MODINIT. If you use a different source file, change the /COPY statements in your other RPG modules.
           dcl-pr fn2b;
              num int(10) value;
           end-pr;
Module source file TEST2B. Compile this using CRTRPGMOD.
       ctl-opt nomain;

       /copy MODINIT,TEST2B_H

       dcl-proc test2b_init export;
          // This procedure is called during service-program activation
          // by module TEST2INIT

          dsply ('test2b_init was called');
       end-proc;

       dcl-proc fn2b export;
          dcl-pi *n;
             num int(10) value;
          end-pi;

          dsply ('fn2b was called with parameter ' + %char(num));
       end-proc;
Module source file TEST2INIT. Compile this using CRTRPGMOD.
Note: While it is usually a good idea to have the prototype for an exported procedure in a /COPY file, in this case, we don't want "ordinary" callers to be calling the "init" procedures. So we put the prototypes for the init procedures directly into this initialization module.
       ctl-opt nomain;

       dcl-pr test2a_init;
       end-pr;
       dcl-pr test2b_init;
       end-pr;            

       dcl-proc INIT_SRVPGM export;
          // This procedure is called during service-program activation
          // by the C++ module SRVPGM_INZ

          dsply ('INIT_SRVPGM was called');

          // Call the initialization procedures for the other modules
          // in this service program that need to be initialized before
          // any "ordinary" calls are done by the application

          test2a_init();
          test2b_init();

       end-proc;                                   
Binder source file TEST2_BND. List the exported procedures that are normally called by your applications. (It does not list the procedure INIT_SRVPGM that is called by the C++ module.)
STRPGMEXP PGMLVL( *CURRENT ) SIGNATURE("TEST2")
  EXPORT SYMBOL( "FN2A" )
  EXPORT SYMBOL( "FN2B" )
ENDPGMEXP
Source for test program TEST2_CALL
  1. Use CRTRPGMOD to compile the module, 
  2. Then use CRTPGM BNDSRVPGM(TEST2) to create the program.
        /copy MODINIT,TEST2A_H 
        /copy MODINIT,TEST2B_H 

        fn2b(25);
        return;
The LAB01.savf attachment is a save of library LAB01 and it contains all the source members and programs.
This savf was created on a V7R4 system. Use RSTLIB cmd to restore.
Library . . . . . . . . . . . . . . . . :   LAB01
 Type  . . . . . . . . . . . . . . . . . :   PROD
 Number of objects . . . . . . . . . . . :           14
 Library ASP number  . . . . . . . . . . :       1
 Library ASP device  . . . . . . . . . . :   *SYSBAS
 Library ASP group   . . . . . . . . . . :   *SYSBAS
 Create authority  . . . . . . . . . . . :   *SYSVAL
 Text description  . . . . . . . . . . . :   Run initialization proc when srvpgm is activated
   Object      Type      Attribute             Size  Description
   TEST1_CALL  *PGM      RPGLE               106496
   TEST2_CALL  *PGM      RPGLE               102400
   TEST1       *SRVPGM                       110592
   TEST2       *SRVPGM                       229376
   SRVPGM_INZ  *MODULE   CPPLE                24576
   TEST1       *MODULE   RPGLE                77824
   TEST1_CALL  *MODULE   RPGLE                81920
   TEST2_CALL  *MODULE   RPGLE                77824
   TEST2A      *MODULE   RPGLE                77824
   TEST2B      *MODULE   RPGLE                77824
   TEST2INIT   *MODULE   RPGLE                73728
   QCSRC       *FILE     PF                   32768
   QRPGLESRC   *FILE     PF                  163840
   QSRVSRC     *FILE     PF                   49152
                     Total size :           1417216

[{"Type":"MASTER","Line of Business":{"code":"LOB68","label":"Power HW"},"Business Unit":{"code":"BU070","label":"IBM Infrastructure"},"Product":{"code":"SWG60","label":"IBM i"},"ARM Category":[{"code":"a8m0z0000000CHtAAM","label":"Programming ILE Languages"}],"ARM Case Number":"","Platform":[{"code":"PF012","label":"IBM i"}],"Version":"All Versions"}]

Historical Number

391188922

Document Information

Modified date:
06 May 2025

UID

nas8N1015374