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.
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:
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:
- 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.
- 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.
Here is the source for the examples
crtsrvpgm mylib/test1
module(mylib/srvpgm_inz
mylib/test1)
srcfile(mylib/mysrcfile)
srcmbr(TEST1_BND)
Test: Use program TEST1_CALL to test it.
- 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
-
- 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'
-
- 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
-
- 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
- Use CRTRPGMOD to compile the module,
- 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
- Use CRTRPGMOD to compile the module,
- 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
Was this topic helpful?
Document Information
Modified date:
06 May 2025
UID
nas8N1015374