When you start to delve into the wonderful world of ILE and service programs, you quickly come across binding source. You know you should use it, but you're not sure why. It has something to do with Signatures which are like Level Checks. You know that bad things will happen if you don't use binding source; namely, if you recreate the service program you will have to recreate all programs that use the service program.
You put up with maintaining binding source when you need to add procedures to the service program, but it is annoying and you'are still not sure why you have to do it. Here is an explanation of what binding source provides and why you should use it.
Dynamic vs. static
What does a procedure need when it makes a call? It needs the address of the code it is calling, and it needs to provide the addresses of the parameters it is passing.
A Dynamic Call means that these addresses are calculated each time the call is made. A Static Call means that the addresses are calculated when the program is created.
If you have an RPG IV program with a subprocedure coded at the end of the source, what happens when you create the program? CRTPGM generates a pointer with the address of the subprocedure. That is why subprocedure calls are fast; the program has a pointer to where the procedure is in memory.
But what about service programs? They are separate objects where all calls are static with the overhead of one dynamic call (the initial loading of the service program). Also, we can change the service program -- which can change the addresses of procedures -- but we don't have to recompile the programs. How can CRTPGM figure out the addresses of procedures that will be loaded in a separate program? That is why you need binding source.
What is binding source?
Binding source provides control over two functions: signatures and exports.
A signature is the equivalent of a record format identifier on a file. The signature is stored in any program that uses the service program when the program is created. (Use DSPPGM DETAIL(*SRVPGM) to view the signatures embedded in a program.) The service program is loaded when the program is called, at which point the signature of the service program is checked against the signature in the program to ensure they are the same. Unlike files, a service program can have multiple signatures -- you can actually define your own signature. (Use DSPSRVPGM DETAIL(*SIGNATURE) to view the signatures in a service program.) Please note that signatures are shown in hex.
Exports is a list of the procedures that are exported (i.e. can be called) from the service program and, most importantly, the sequence in which they are exported. Remember, the overhead of using a service program is one dynamic call and all other calls are static; this is what the export list helps you achieve.
Binding source is usually stored in a member with the same name as the service program in a source physical file named QSRVSRC; these are the defaults for the SRCFILE and SRCMBR keywords on the CRTSRVPGM command.
Let's look at an example of maintaining binding source when adding procedures to a service program. To reduce possible confusion, in this example all of the procedures will have the same parameter list.
In the beginning
You have a service program named DIRECTIONS that exports two procedures (GOLEFT and GORIGHT); it was created using the binding source shown in Figure 1. The STRPGMEXP instruction identifies that this is the current export list and that 'FIRST' is a supported signature. The EXPORT instructions identify the "callable" procedures in the service program. There may be other procedures in the service program that can be called only from procedures within the service program.
StrPgmExp PgmLvl(*CURRENT) Signature('FIRST') Export Symbol('GOLEFT') Export Symbol('GORIGHT') EndPgmExp
Figure 1: Binding source for service program exporting two procedures
When you create the service program, it will contain two "arrays." The first is an array corresponding to the Export list in the binding source. The second is a corresponding array of the addresses of the procedures in the service program.
You create a program that calls the GORIGHT procedure. Two things happen: The program will store the signature of 'FIRST,' and it will equate that all calls to GORIGHT should call the second procedure exported from the service program, i.e. it does a lookup on the first array to determine that it should be using the procedure pointer in the second element of the second array.
Add a procedure
You decide to add a third procedure (GOBACK) to the service program, so you change the binding source as shown in Figure 2. This indicates that the service program now has two signatures (FIRST and SECOND). Also note that the *PRV does not have an Export list (you do not have to include the list if you are defining your own signatures). That is because the Export list is always taken from the *CURRENT definition.
StrPgmExp PgmLvl(*CURRENT) Signature('SECOND') Export Symbol('GOLEFT') Export Symbol('GORIGHT') Export Symbol('GOBACK') EndPgmExp StrPgmExp PgmLvl(*PRV) Signature('FIRST') EndPgmExp
Figure 2: Adding a third procedure to the binding source
What about your program? It will still work fine because it has a signature of FIRST, so it does not need to be compiled.
Add a procedure incorrectly
Now for a deliberate mistake to highlight what happens with binding source. You decide to add a fourth procedure (GOAHEAD) to the service program, so you change the binding source as sown in Figure 3, with the deliberate mistake of adding the new procedure at the top of the list instead of the bottom. The service program now has three signatures (FIRST, SECOND and THIRD).
StrPgmExp PgmLvl(*CURRENT) Signature('THIRD') Export Symbol('GOAHEAD') Export Symbol('GOLEFT') Export Symbol('GORIGHT') Export Symbol('GOBACK') EndPgmExp StrPgmExp PgmLvl(*PRV) Signature('SECOND') EndPgmExp StrPgmExp PgmLvl(*PRV) Signature('FIRST') EndPgmExp
Figure 3: Adding a fourth procedure to the binding source in the wrong place
Again, your program will not fail when it is called because it has a matching signature with the service program (FIRST). But you will not get what you expect when it calls GORIGHT. Remember, when the program was created this was equated to calling the second procedure exported from the service program, which is now GOLEFT!
Refer to the ILE Concepts manual for an example of making this work to your advantage.
One of the tedious tasks with binding source is getting the original source created. It can be a lot of typing for a large service program. You may want to try the following:
- Create the service program using EXPORT(*ALL).
- Generate the binding source using the RTVBNDSRC command.
- Define your own signature. Although it is not a necessity, I prefer to have control over the signatures.
- If required, make changes to the binding source (rearrange the sequence or remove some export definitions).
- Recreate the service program using EXPORT(*SRCFILE), even if you have not changed the binding source. The binding source generated by the RTVBNDSRC command does not reflect the sequence in which procedures are actually exported from the service program.
- Create the programs that bind to the service program.
Although the use of binding source may at first appear to be an annoying overhead, I hope it is now evident that there is a method to the madness. Others wiser then I may think of better ways to achieve the same result, but I, for one, am willing to make do with binding source.
About the author: Paul Tuohy is CEO of ComCon, an iSeries consulting company. He is the author of Re-Engineering RPG Legacy Applications and is one of the quoted industry experts in the IBM Redbook "Who Knew You Could Do That With RPG IV?"