| Document revision date: 19 July 1999 | 
 
  
    | ![[Compaq]](../../images/compaq.gif) | ![[Go to the documentation home page]](../../images/buttons/bn_site_home.gif)  ![[How to order documentation]](../../images/buttons/bn_order_docs.gif)  ![[Help on this site]](../../images/buttons/bn_site_help.gif)  ![[How to contact us]](../../images/buttons/bn_comments.gif)  | 
 
  
    | ![[OpenVMS documentation]](../../images/ovmsdoc_sec_head.gif)  | 
 
 
 
 
Guide to Creating OpenVMS Modular Procedures
4.6 Monitoring Procedures in the Run-Time Library
The run-time library (RTL) contains several procedures for time and 
resource monitoring. These RTL procedures and their functions are as 
follows:
  - LIB$SHOW_VM 
 LIB$SHOW_VM is a resource monitoring procedure that 
  returns the statistics accumulated from calls to LIB$GET_VM and 
  LIB$FREE_VM.
 The following three statistics are returned by default:
    - Number of successful calls to LIB$GET_VM
    
- Number of successful calls to LIB$FREE_VM
    
- Number of bytes allocated by LIB$GET_VM but not yet deallocated by 
    LIB$FREE_VM
  
 
 LIB$SHOW_VM returns these statistics in the formatted form, nnnn.
- LIB$STAT_VM 
 LIB$STAT_VM is a resource monitoring procedure that 
  returns to its caller one of the three statistics available from calls 
  to LIB$GET_VM and LIB$FREE_VM. These are the same statistics that are 
  returned by LIB$SHOW_VM. Unlike LIB$SHOW_VM, which returns the 
  statistics in formatted form to SYS$OUTPUT, LIB$STAT_VM returns the 
  specified statistic in a signed longword integer.
- LIB$SHOW_TIMER 
 LIB$SHOW_TIMER is a time monitoring procedure 
  that returns the times and counts accumulated since the last call to 
  LIB$INIT_TIMER and displays them on SYS$OUTPUT. A user-supplied action 
  routine may alter this default behavior.
 The following statistics 
  are provided by default:
    - Elapsed real time
    
- Elapsed CPU time
    
- Count of buffered I/O operations
    
- Count of direct I/O operations
    
- Count of page faults
  
 
- LIB$STAT_TIMER 
 LIB$STAT_TIMER is a time monitoring procedure 
  that returns the same information as LIB$SHOW_TIMER. The difference is 
  that LIB$STAT_TIMER returns the information as an unsigned longword or 
  quadword, whereas LIB$SHOW_TIMER returns the information in the format 
  hhhh:mm:ss:cc for times and the format nnnn for counts. In addition, 
  LIB$STAT_TIMER returns only one of the five available statistics per 
  call.
For more information about these time and resource monitoring 
procedures, see the OpenVMS RTL Library (LIB$) Manual.
Chapter 5
Integrating Modular Procedures
Modular procedure libraries consist of compiled and assembled object 
code intended to be associated with a calling program at link time. The 
linker resolves references to procedures in these libraries when it 
searches user libraries specified in the LINK command, or when it 
searches the default system libraries. The program can then call 
library procedures at run time.
Digital supplies several procedure libraries, such as the Run-Time 
Library, that support components of the OpenVMS operating system. You 
can use procedures in the Run-Time Library to perform frequently used 
operations by including calls to Run-Time Library procedures in your 
program. The linker automatically searches the default libraries to 
resolve references to Run-Time Library procedures. (For information 
about the procedures available in the Run-Time Library, see the 
OpenVMS Programming Concepts Manual.)
This chapter briefly describes how you can create your own procedure 
libraries and shareable images. For more information about creating 
libraries and shareable images, use the guidelines in the OpenVMS Linker Utility Manual.
5.1 Creating Facility Prefixes
A facility prefix is the group identifier for a set of related 
procedures contained in a library facility. The facility prefix appears 
in the procedure name of every procedure in that library facility. An 
example of a library facility is the Screen Management facility in the 
Run-Time Library. The names of all the procedures in the Screen 
Management facility begin with SMG; for example, SMG$ERASE_CHARS.
To create your own facility prefix, follow these steps:
  - Choose a facility prefix. This prefix can be from 1 to 27 
  characters in length. However, Digital recommends that you choose 
  facility prefixes between 2 and 4 characters.
  
- If your facility will be generating messages, you must specify a 
  unique facility number in the message source file. This number can 
  range from 0 to 4095. Any number within this range, and not being used 
  by someone else on your system, is acceptable. This facility number is 
  used by the message utility in generating the condition value for the 
  message. 
 Bit 27 (STS$V_CUST_DEF) of a condition value indicates 
  whether that value is supplied by the user or by Digital. This bit must 
  be 1 if the facility number is user created. For more information, see 
  the OpenVMS System Messages and Recovery  Procedures Reference Manual.
- Use the facility prefix when naming all procedures within the new 
  facility. Remember to follow the naming conventions described in 
  Section 3.1.1.
5.2 Creating Object Module Libraries
In addition to using the system default object module libraries, you 
can create your own object module libraries. An object module library 
that you create can contain object files produced by any language 
compiler supported by the OpenVMS operating system.
For more information about creating object module libraries, see the 
OpenVMS Linker Utility Manual.
5.3 Creating Shareable Image Libraries 
If you have a collection of procedures you expect a number of users to 
use, you can group these procedures into a shareable image library. A 
shareable image library is similar to an object library, except that it 
has been prelinked so that all references between procedures in the 
library have already been resolved.
A shareable image has the following advantages:
  - Conserves memory space 
 Several processes can share a single 
  copy of a shareable image rather than each process retrieving its own 
  copy from the disk.
- Conserves disk storage space 
 Programs linked to a shareable 
  image share a single disk copy of the library code rather than each 
  program including the code in its own executable image.
- Shortens link time 
 Because the internal references in the 
  library have already been resolved, there is less work for the linker.
- Allows for updates without relinking 
 You can supply a new 
  version of a shareable image that can automatically be used by all 
  programs linked to it without the need for the users to relink their 
  programs.
For more information about creating shareable image libraries, see the 
OpenVMS Linker Utility Manual.
Chapter 6
Maintaining Modular Procedures
This chapter describes important aspects of maintaining modular 
procedures. Specifically, it covers the following topics:
  - Making your procedures upwardly compatible
  
- Regression testing
  
- Adding arguments to existing routines
  
- Updating libraries
6.1 Making Your Procedures Upwardly Compatible
Upward compatibility is very important when maintaining procedures. If 
a procedure is upwardly compatible, changes and updates to the 
procedure do not affect executing and using previous versions of that 
procedure.
For example, imagine a user-written procedure named LIB_TOTAL_BILL. The 
calling sequence for this procedure is as follows:
  
    | 
 
CALL LIB_TOTAL_BILL (sale, tax) 
 | 
Assume that the user who wrote this procedure decided to update the 
procedure so that it could be used to calculate the total bill for 
credit-card customers. To do this, a third argument, 
interest, must be added. To be upwardly compatible, 
adding the argument interest must not conflict with 
the way the procedure was previously run. The new calling sequence 
would be as follows:
  
    | 
 
CALL LIB_TOTAL_BILL (sale, tax [,interest]) 
 | 
The procedure should be written so that the user can still call the 
procedure as it was called before, simply omitting the 
interest argument.
If, in the updated version of this procedure, the user can still follow 
the calling sequence of the previous versions, the procedure is said to 
be upwardly compatible.
To ensure that your procedures are compatible with future versions of a 
shareable image, see the OpenVMS Linker Utility Manual.
6.2 Regression Testing
Regression testing is a method of ensuring that new features added to a 
procedure do not affect the correct execution of previously tested 
features. In regression testing, you run established software tests and 
compare test results with expected results. If the actual results do 
not agree with what you expected, the software being tested may have 
errors. If errors do exist, the software being tested is said to have 
regressed.
Regression testing includes the following steps, as shown in 
Figure 6-1:
  - Create tests by writing command files to test your software.
  
- Organize files to allow easy access to tests as they are needed.
  
- Run tests as follows:
  
    - To run a single test, submit its command file to the batch queue.
    
- To run multiple tests, create a command file that submits each test 
    to the batch queue.
  
 
- Calculate the expected test results either by hand or by using 
  previously tested software.
  
- Compare actual test results to the results you expected. If there 
  are inconsistencies, repeat your calculation in step 4. If the 
  inconsistency still exists, examine the changes you have made to the 
  software to discover the error.
Figure 6-1 Regression Testing
 
It is important to write new tests and repeat the regression testing 
steps every time you add new functionality to the procedure. If you do 
not do so, the procedure may regress while the errors go undetected.
6.3 Adding Arguments to Existing Routines
During the normal course of maintenance, it sometimes becomes necessary 
to pass new or additional information to an existing procedure rather 
than create a new procedure. This new information can be passed to the 
procedure in one of the following two ways:
  - Directly, by adding new arguments to the procedure
  
- Indirectly, using an argument block
6.3.1 Adding New Arguments to the Procedure
There are two rules you must follow when directly adding new arguments 
to a procedure:
  - New arguments must be added at the end of the existing argument 
  list.
  
- New arguments must be optional.
It is important that new arguments be added at the end of the existing 
argument list to maintain upward compatibility. If you change the order 
of the existing arguments by placing the new argument at the beginning 
or middle of the list, all applications written with the previous 
version of the procedure will no longer work.
Your procedure should also treat the new argument as an optional 
argument. If the new argument is required, applications that used the 
previous version of the procedure are invalidated.
Because you cannot assume that all previously written applications will 
be rewritten to include the procedure's new argument, the procedure 
must test for the argument's presence before attempting to access it. 
If the procedure does not verify the presence of the new argument and 
attempts to access that argument when it is not present, the results 
will be unpredictable.
The passing mechanism of the new argument must conform to the 
guidelines in Section 2.2.1.
6.3.2 Using Argument Blocks
By using an argument block, you can avoid adding multiple arguments to 
your procedure. When an argument block is used, the calling program 
passes a single argument to the called procedure. This argument is the 
address of an argument block. The argument block is a block of 
information containing any information agreed on by the calling and 
called procedures. This information is required by the called procedure 
to perform its task.
The argument block is simply a contiguous piece of virtual memory. The 
information contained in the argument block can be numeric or scalar 
data, descriptors, bit vectors, and so on. The format is agreed on by 
the users of the procedure and its writer.
The first longword in the argument block contains the length of the 
block. The length can be in bytes or longwords, but it must be agreed 
on by both the calling program and the called process, and be 
implemented and documented as such.
One example of an argument block is the signal argument vector used in 
condition handling. A condition handler is called with a signal 
argument vector and a mechanism argument vector. Each vector is an 
example of an argument block. The signal argument vector in 
Figure 6-2 is an example of an argument block.
Figure 6-2 One Type of Argument Block, the Signal Argument 
Vector
 
The signal argument vector contains the number of longwords of actual 
information in its first longword. What information actually follows 
depends on the condition value of the signal.
Note that if you lengthen an argument block to provide new information 
to a called procedure, your procedure should check the length of the 
argument block for validity before attempting to access the 
information. As with adding new arguments directly to a procedure, the 
calling program may have been written to pass the previous, shorter 
argument block. If your procedure does not check and attempts to access 
information past the end of the actual argument block, the results will 
be unpredictable.
6.4 Updating Libraries
Any time you make modifications or enhancements to modular procedures 
that are a part of a library, you must update the library containing 
the procedures to reflect the new or changed procedures.
6.4.1 Updating Object Libraries
If the updated procedures are in an object library, the library must be 
updated so that subsequent access to that library by LINK or other 
commands will access the object modules for the new or changed 
procedures.
To update an object library, use the LIBRARY command with the REPLACE 
qualifier, as follows:
  
    | 
 
$ LIBRARY /REPLACE library-name filespec[,...]
 | 
In this example, library-name is the name you have given the library. 
The default file type for library-name is OLB. The name of an object 
module is filespec. The default file type for filespec is OBJ.
6.4.2 Updating Shareable Images
If the updated procedures are part of a shareable image, you must 
relink the shareable image so that it contains the new or changed 
versions of any updated object modules. If you add new procedures, you 
must update and recompile the transfer vector (on VAX systems) or 
symbol vector (on Alpha systems) before relinking the shareable image. 
If you add new modules, you must update the linker options file before 
relinking. If you add new procedures and new modules, you must update 
the transfer vector (on VAX systems) or symbol vector (on Alpha 
systems) and the linker options file. If you change the transfer vector 
(on VAX systems) or symbol vector (on Alpha systems), you must 
increment the minor identification value of the GSMATCH by one. You can 
then relink the shareable image.
For more information about updating shareable images, see the 
OpenVMS Linker Utility Manual.
Appendix A
Summary of Modular Programming Guidelines
This appendix summarizes the modular programming guidelines that are 
described in this manual. References to the appropriate sections appear 
after each guideline. The word Optional appears before the section 
reference if the guideline is not required to maintain modularity.
A.1 Coding Rules
The coding rules in this section pertain to all procedures. These rules 
are grouped in the following categories:
  - Calling interface
  
- Initialization
  
- Reporting exception conditions
  
- AST reentrancy
  
- Resource allocation
  
- Format and content of coded modules
  
- Upward compatibility
Detailed descriptions of the rules for each of these categories are 
presented in the sections that follow.
A.1.1 Calling Interface
  - Calls to procedures must follow the OpenVMS Calling Standard. Some elements of 
  this standard restrict procedures to a subset of the OpenVMS Calling Standard to 
  increase the ability of procedures to call each other. (See 
  OpenVMS Programming Interfaces:  Calling a System Routine.)
  
- A procedure makes no assumptions about its environment other than 
  those of this standard. In particular, to operate as specified, a 
  procedure neither makes assumptions about, or places requirements on, 
  the calling program.
  
- A procedure should not call other procedures or system services if 
  the resulting combination violates this standard from the calling 
  program's viewpoint. A procedure can call other procedures or system 
  services that do not follow optional elements of this standard. 
  However, if the resulting combination (as seen from the calling 
  program) does not follow the optional elements, the calling procedure 
  must indicate such nonconformance in its documentation. (See 
  Section 3.1.3.)
  
- A modular procedure must provide to its callers an interface that 
  allows the callers to follow all required elements of this standard.
  
- Each module should only contain a single public entry point. 
  (Optional.)
  
- On VAX systems, when a procedure uses a JSB entry point, it should 
  also provide an equivalent call entry point to maintain language 
  independence. Although JSB calling sequences may execute faster than 
  procedure calls, an explicit JSB linkage to an external routine may not 
  be provided in some high-level languages. (Optional. See Section 2.3.)
  
- The order of required arguments should be the same as that of the 
  hardware instructions; namely, read, modify, and write. Optional 
  arguments follow in the same order. However, if a function value is 
  large or is of type string, the first argument specifies where to store 
  the function value, and all other arguments are shifted one position to 
  the right. (See Section 2.2.4.)
  
- A procedure's caller should indicate omitted trailing optional 
  arguments either by passing argument list entries that contain zero or 
  by passing a shortened argument list. However, system services require 
  trailing arguments and do not adhere to this guideline. (Optional. See 
  Section 2.2.5.)
  
- String arguments should always be passed by descriptor. (See 
  Section 4.2.)
  
- Procedures must not accept data from, nor return data to, their 
  calling programs by using implicit overlaid PSECTs or implicit global 
  data areas. All arguments accepted from or returned to the calling 
  program must use the argument list and function value registers. (See 
  Section 2.2.2.)
  
- A procedure cannot assume that the implicit outputs of procedures 
  it calls will remain unchanged if subsequently used as implicit inputs 
  to those procedures or to companion procedures. (See Section 2.2.2.)
  
- On VAX systems, position-independent references (in a module) to 
  another PSECT must use longword relative addressing so the linker can 
  correctly allocate the data PSECT anywhere with respect to the code 
  PSECT, no matter how many code modules are included.
  
- On VAX systems, external references must use general-mode 
  addressing to allow the referenced procedures to be put in a shareable 
  image without requiring changes to the calling program.
  
- Procedures cannot require their callers to pass dynamic string 
  descriptors. (See Section 4.2.)
  
- Some procedure interface specifications retain state information 
  from one call to the next, even though the procedures are not resource 
  allocating. The interface specification uses one of the following 
  techniques (in order of decreasing preference) to permit sequences of 
  calls from independent parts of a program by either eliminating the use 
  of static storage or overcoming its limitations:
  
    - The interface specification consists of a sequence of calls to a 
    set of one or more procedures --- the first procedure allocates and 
    returns (as an output argument to the calling program) one of the 
    following:
    
      - The address of heap storage
      
- Another processwide identifying value
    
 
 This argument is passed to the other procedures explicitly by the 
      calling program, and the last procedure deallocates any heap storage or 
      processwide identifying value.
- The procedure's caller allocates all storage and passes the address 
    on each call.
    
- The interface specification consists of a single call, where the 
    calling program passes the address of one or more action routines and 
    arguments to be passed to them. The procedure calls the action routines 
    during its execution. Results are retained by the procedure across 
    calls to the action routines. (No static storage used.)
    
- The interface specification consists of a sequence of calls to a 
    set of one or more procedures. The first procedure saves the contents 
    of any still-active static storage on a push-down stack in heap 
    storage, and the last procedure restores the old contents of static 
    storage. Static storage is made available for implicit arguments to be 
    passed from one procedure to the next in the sequence of calls (unknown 
    to the calling program). However, if an exception can occur anywhere in 
    the sequence, the calling program must establish a condition handler 
    that calls the last procedure in the event of a stack unwind (to 
    restore the old contents of static storage).
  
 
A.1.2 Initializing
  - If a procedure requires initialization once for each image 
  activation, it is done without the caller's knowledge by one of the 
  following:
  
    - Initializing at compile time
    
- Initializing at link time
    
- Adding a dispatch address to PSECT LIB$INITIALIZE
    
- Testing and setting a statically allocated, first-time flag on each 
    call
  
 
- A procedure must not use LIB$INITIALIZE to establish a condition 
  handler before the main program is called if its action can conflict 
  with that of other condition handlers established before the main 
  program. For more information about initializing modular procedures, 
  see Section 3.2.
A.1.3 Reporting Exception Conditions
A procedure must not print error or informational messages either 
directly or by calling the $PUTMSG system service. It must either 
return a condition value in R0 as a function value or call LIB$SIGNAL 
or LIB$STOP to output all messages. (LIB$SIGNAL and LIB$STOP can be 
called either directly or indirectly.) (See Section 2.5.)
A.1.4 AST Reentrancy
  - To be AST reentrant, a procedure must execute correctly while 
  allowing any procedure (including itself) to be called between any two 
  instructions. The other procedure can be an AST-level procedure, a 
  condition handler, or another AST-reentrant procedure. (See 
  Section 3.3.)
  
- A procedure that uses no static storage and calls only 
  AST-reentrant procedures is automatically AST reentrant. (See 
  Section 3.3.3.)
  
- If a procedure uses static storage, it must use one of the 
  following methods to be called from AST and non-AST levels:
  
    - Perform access and modification of the database in a single 
    uninterruptible instruction. This can be done only from VAX MACRO, and 
    emulated instructions are not allowed. (See Section 3.3.4.1.)
    
- Detect concurrency of database access with test and set 
    instructions at each access of the database. (See Section 3.3.4.2.)
    
- Keep a call-in-progress count incremented upon entry to the 
    procedure and decremented upon return. (See Section 3.3.4.3.)
    
- Disable AST interrupts on entry to the procedure and restore the 
    state of the AST enables on return. (See Section 3.3.4.4.)
  
 
- If a procedure performs I/O from the AST level by calling RMS $GET 
  and $PUT system services, it must check for the record stream active 
  error status (RMS$_RSA). If this error is encountered, the procedure 
  issues the $WAIT system service and then retries the $GET or $PUT 
  system service. (See Section 3.3.5.)
  
- A procedure should not depend on AST interrupts being disabled to 
  execute correctly if there are other coding methods available. For 
  example, RMS completion routines are implemented via ASTs and will not 
  work if ASTs are disabled. (See Section 3.3.)