Many RPGers have learned about the joys of service programs, which were designed to collect multiple modules together to simplify object management. But we've found that many shops apparently create all of their service programs with only one module. While there's nothing technically wrong with this approach, it seems a waste of a "collection" object to have only one item in the collection.
Plus, if you have programs that use many of these single-module service programs, it could impact performance, because a connection must be made at start-up between a program and each service program it uses. A program using 10 service programs will take longer to start than a program using two or three service programs, even if the number of procedures is the same.
We don't understand the rationale behind this single-module service program approach, but it may be because of past problems these shops have had with service program signature violation errors. Here, we explain signatures and outline your options for avoiding those errors.
Q: What is a signature?
A: A signature is a value that provides a similar check for service programs that a level check does for files. It helps ensure that changes made to the service program are done in such a way that the programs using them can still function properly. The signature is typically generated by the system when you issue a Create Service Program (CRTSRVPGM) command specifying Export(*ALL). The signature value is generated by an algorithm that uses as input the names of all of the service programs "exports" and their sequence. "Exports" are the names of callable procedures and any exported data items. When you create a program that references that service program, its current signature value is copied into your program. If the export list were to be changed without the programs detection, the program could potentially call the wrong procedure.
Q: What causes a signature to change?
A: A signature changes when the list of exports for the service program changes. The most common cause of a signature change is adding a new procedure to the service program. Despite popular "wisdom" to the contrary, a change in a procedures parameters doesn't change the service program's signature.
Q: What happens when the signature changes?
A: When a program is called, it immediately checks the signature value of any service programs that it uses and produces a signature violation message if the signatures don't match. This happens at program start up not when you actually call a service program procedure.
A: You have a couple of options to correct this situation. You can either re-bind all of the programs that reference the changed service program or you can create binder language to manage the service programs signatures.
Q: How do I re-bind the programs that reference the service program?
A: Use the Update Program (UPDPGM) command. Because you aren't replacing any modules, specify Module(*None). You don't need to specify the service program because the UPDPGM command automatically re-checks the signatures of any bound service programs. If any signatures have changed, it also updates the programs signature values.
Q: Why not re-compile the programs or re-create the programs with the Create Program (CRTPGM) command?
A: It's typically better to make only one change at a time to avoid the possibility of introducing unwanted or unnecessary changes while fixing a problem. Re-compiling or re-creating could potentially introduce changes. For example, if the source has changed, re-compiling the program definitely introduces changes. Even if you re-create the program from some previously compiled modules, you cannot always be sure they represent the exact same code currently in the program. In addition, other program attributes (related to authority, Activation Group, etc.) could change when you re-create it. But perhaps the best reason to use UPDPGM is because it's easier and faster than either of the other options.
Q: How do I know which programs need to be updated?
A: That can be difficult. If you have a cross-reference tool that understands service programs, it should provide the information you need. Otherwise, you can display each program using the Display Program (DSPPGM) command and see (on the fourth display screen) the list of service programs it uses and what signature value it's looking for. Of course, if you know the signature has changed, the fact that the program references the service program tells you it must be updated. This method is tedious to do manually. You could also write a program to automatically perform the updates for you using the appropriate APIs (DSPPGM has no outfile support). This is beyond the scope of this article but we may cover it in the future.
Q: What about binder language?
A: If you don't want to update several programs every time you add a new procedure to your service program, you can create binder language to manage the signature values. Let's examine an example.
Say you have a service program called DateStuff that originally contained two procedures called DayOfWeek and DayName. For purposes of writing binder language, it doesn't matter if both procedures are in the same module or combination of modules. Binder language only cares about the procedure names. When you originally created DateStuff, you specified Export(*All), because you weren't using binder language.
Recently you added a new module to the service program that contains procedures named GetDuration and LastDayOfMonth and specified Export(*All) again. Now your signature is different because you added procedures (exports) that changed the signature value. Programs that were working fine with the old version of the service program now fail with a signature violation.
Let's create some binder language to fix this. Key your binder language into a source file called QSRVSRC with a member name that matches your service program: DateStuff. Member type is BND. The binder language should look like this:
Note that the sequence of the procedure names (called export symbols in binder language) is important. Your previous export list (*PRV) must be in the sequence that the system put it in when the service program was first created with Export(*All). Because the system puts the procedure name exports in alphabetical sequence, that's what we've done here. It's equally critical that the *CURRENT export list maintains the sequence of ALL exports in ALL *PRV lists. That is, DayName must remain in the first position and DayOfWeek in position 2, etc.
Now that you have the binder language created, you can issue an Update Service Program (UPDSRVPGM) command to your DATESTUFF Service Program, this time specifying Export (*SRCFILE). Make sure the source member and file names are specified correctly.
Now your service program has two different signatures-one for each export list in the binder language. The signature generated by the *PRV list should match the service programs original, so all of the old programs will continue to work. New or updated programs will automatically pick up the signature generated by the *CURRENT list.
If you need to add another module in the future, you can create a second *PRV list. Just remember that the sequence of the procedure names is critical. Make a block copy of the *CURRENT list and change PGMLVL in one of them to *PRV. Add any new procedure names to the END of the new *CURRENT list and don't remove or re-sequence the procedure names in any of the export lists. You can apply your binder language on CRTSRVPGM or UPDSRVPGM after it's created.
This technique uses system-generated signature values. It's also possible to hard code your own signature values. We'll take another look at managing service program signatures in a future issue.