  | 
		
Guide to Creating OpenVMS Modular Procedures
 
 
2.4.2 Using Event Flags
Event flags allow modular procedures to communicate with each other and
to synchronize their operations. Because they can be allocated at run
time, event flags allow one procedure to run independently of other
procedures existing in the same process.
 
Event flags are allocated and deallocated by the run-time library
procedures LIB$GET_EF and LIB$FREE_EF. (For more information, see the
descriptions of the LIB$GET_EF and LIB$FREE_EF procedures in the
OpenVMS Programming Concepts Manual and the OpenVMS RTL Library (LIB$) Manual.)
2.4.3 Using Logical Unit Numbers
 
A logical unit number is used to define either the device or file a
program uses to perform input and output. Modular procedures do not
need to know the unit numbers of other procedures running at the same
time.
 
Logical unit numbers are used only in BASIC and FORTRAN.
 
Logical unit numbers should be allocated and deallocated using the
LIB$GET_LUN and LIB$FREE_LUN RTL procedures. (For more information
about using logical unit numbers, see the descriptions of the
LIB$GET_LUN and LIB$FREE_LUN procedures in the OpenVMS Programming Concepts Manual and the
OpenVMS RTL Library (LIB$) Manual.)
2.5 Using Input/Output
 
In general, your procedure's input/output (I/O) is directed to either
the terminal or a file. (In some cases, you may need to use mailbox I/O
and network operations. For information about these areas, see the
DECnet for OpenVMS Networking Manual.)
Regardless of whether you are directing input/output to the terminal
screen or to a file, you must follow two rules to maintain modularity:
 
  - 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.)
  
 - A procedure should use device-independent services and procedures
  for input/output.
  
2.5.1 Terminal Input/Output
The methods available for performing input/output to the terminal
include the following:
 
  - Queue I/O Request system service ($QIO) 
 Using a $QIO to perform
  terminal I/O is very efficient. However, $QIOs use device-dependent
  services and are the most difficult to use from high-level languages of
  all methods discussed here, because there are more steps involved and
  because the calling interface requires more knowledge from the caller
  than RMS services. Using a $QIO in your procedure may require
  additional steps, such as constructing item lists, writing AST
  routines, assigning an I/O channel, queueing an I/O request, testing to
  ensure that the request was successfully queued and completed, and
  deassigning the I/O channel. (For more information about $QIOs, see the
  OpenVMS System Services Reference Manual.)
   - OpenVMS Record Management Services (RMS) 
 The RMS facility
  provides device-independent and general-purpose services that are
  easier to call than $QIOs. However, it is often not convenient to
  construct the access control blocks (FAB, RAB, and so forth) required
  by RMS from a high-level language. (For more information about RMS, see
  the OpenVMS Record Management Services  Reference Manual.)
   - Language I/O statements 
 Language I/O statements are provided
  for all high-level languages. These statements are easy to use and
  provide simple I/O and data formatting for the high-level language
  user. Native language I/O statements make it unnecessary for the
  high-level language user to call $QIO or RMS directly; these calls are
  made by the compiled code on your behalf. However, low-level and
  medium-level languages (VAX MACRO and BLISS-32) have no built-in
  language I/O statements and must use $QIO and RMS for terminal and file
  I/O. (For more information, see the appropriate language reference
  manual.)
   - Screen Management Procedures in the run-time library (SMG$)
  
 SMG$ procedures provide an easy-to-call interface for high-level
  languages. They are device independent and aid in the composition of
  complex screen images. The SMG$ facility in the run-time library
  provides screen composition operations; that is, SMG$ makes it easy for
  an application to divide its screen into multiple regions and provides
  functions for manipulating those regions. Other features provided by
  SMG$ procedures are as follows:
  
    - Output to virtual displays
    
 - Input from a virtual keyboard or locator device
    
 - The ability to perform asynchronous input
    
 - Built-in minimal screen updating
    
 - Optional buffering and batching to optimize performance
    
 - The ability to trap broadcast messages
    
 - The option of performing output to a file or a hardcopy device
    
 - Support for foreign (not Compaq) terminals
    
 - Subprocess manipulation
  
  
     For more information about SMG$ procedures, see the OpenVMS RTL Screen Management (SMG$) Manual
    and the OpenVMS Programming Concepts Manual.
  
During I/O to the terminal, it is important that the procedure and the
main program cooperate in controlling the terminal screen. For example,
an I/O procedure may write something to the terminal screen that the
calling program wants to erase. To erase it, the calling program must
know both what and where that information is. The calling program and
the called procedure must communicate by passing arguments that define
which part of the screen will be accessed by each. The run-time library
contains Screen Management (SMG$) procedures for this purpose.
 
Do not combine different methods of I/O within your application.
Problems can arise if the calling program and the called procedure use
different methods of I/O. Each method of performing input/output
maintains some knowledge of what is on the terminal screen. At the very
least, the current cursor position is remembered. If another type of
I/O is performed, that information is not updated and, therefore,
becomes incorrect. The results of any subsequent I/O would be
unpredictable. If you must combine other methods with uses of SMG$
procedures, use the SMG$ procedures that aid such an integration.
2.5.2 File Input/Output
 
File I/O can be performed by the following methods:
 
  - Block I/O 
 Uses system services to map a section of the file to
  the process virtual address space. No notion of records.
   - OpenVMS Record Management Services (RMS) 
 RMS provides a variety
  of file organizations and access modes from which you can select the
  processing techniques best suited to your application. RMS supports the
  sequential, relative, and indexed-sequential file organizations. These
  modes allow you to access records within these files sequentially,
  randomly by key value or relative record number, or randomly by the
  records file address (RFA). It is not usually necessary to call RMS
  directly from high-level languages. For specific information about
  performing record management operations in the language you are using,
  consult your language reference manual. (For more information about
  RMS, see the OpenVMS Record Management Services  Reference Manual.)
   - Language I/O 
 The compiled code in most high-level languages
  calls a run-time library language support procedure for file
  operations. The run-time library procedures normally call RMS.
  Therefore, most RMS features are available to the high-level language
  user without calling RMS directly. Language I/O statements are suitable
  for either data files or output files. Low- and medium-level languages
  (VAX MACRO and BLISS-32) do not have any language I/O statements and
  must call RMS directly. (For more information, see the appropriate
  language reference manual.)
  
2.6 Documenting Modules
You should document every module you create so that you and others know
what the procedure does. Each module should include:
 
  - A preface that identifies the procedure
  
 - A description of the procedure
  
In most cases, a module should contain only one procedure.
2.6.1 Writing a Module Preface
 
At the beginning of every module, include a preface that contains the
following information:
 
  
    | 
      Title:
     | 
    
      Module name followed by a one-line functional description.
     | 
   
  
    | 
      Version:
     | 
    
      Version and a three-digit edit number. Generally 1-001 is the original
      version.
     | 
   
  
    | 
      Facility:
     | 
    
      Description of the library facility, such as general utility library
      (LIB).
     | 
   
  
    | 
      Abstract:
     | 
    
      Short (three to six lines) functional description of the module.
     | 
   
  
    | 
      Environment:
     | 
    
      Describe any special environmental assumptions that the module can
      make. These include assumptions made at both compilation and execution
      time that could affect either the hardware or software environments.
        Describes situations that the module assumes during execution time
      and optional modular programming elements that your module does not
      follow.
        Indicates the reentrancy characteristics of the procedures in this
      module. Each procedure is either fully reentrant, AST reentrant, or
      nonreentrant.
      | 
   
  
    | 
      Author:
     | 
    
      Your name and date the module was created.
     | 
   
  
    | 
      Modified by:
     | 
    
      Modification number, name of modifying programmer, modification date,
      and a list of the modifications.
     | 
   
 
End the preface with a page delimiter. After the preface, include the
code for the procedure.
 
Example 2-4 shows a sample module description.
 
 
  
    | Example 2-4 Sample Module Description | 
   
  
    
       
      
        PROGRAM GRA_CUBE                ! Create representation of a cube
!+
! VERSION:      1-002
!
! FACILITY:     User Graphics Computation Library
!
! ABSTRACT:     This module contains a procedure to create a mathematical
!               representation of a cube, GRA_CUBE.
!
! ENVIRONMENT:  User Mode, AST-reentrant
!
! AUTHOR:       John Smith                CREATION DATE:  14-Sep-1993
!
! MODIFIED BY:
! 1-001 - Original.  DWS 14-Sep-1993
! 1-002 - Fix a minor bug in cube volume computation.  MDL 15-Mar-1993
!-
 |   
2.6.2 Writing a Procedure Description
At the beginning of every procedure in a module, describe the procedure
by including the information in this section. Include all the
description elements, even if they are not in the procedure. For
example, if a procedure has no implicit inputs, write the following:
 
 
  
    
       
      
!
!  Implicit Inputs:
!
!       NONE
!
 
 |   
Every procedure description should include the following information:
 
  
    | 
      Functional description:
     | 
    
      Describes a procedure's purpose and completely documents its interfaces.
        Includes the basis for any critical algorithms used, including
      literature references where applicable, and explains why a particular
      algorithm was chosen.
        Indicates the reentrancy characteristics of this procedure if they
      differ from those given in the module description.
      | 
   
  
    | 
      Calling sequence:
     | 
    
      Includes these elements in the following order:
      
      - A return status, value argument, or CALL statement
      
 - The procedure name
      
 - The argument list (typically a list of registers or arguments)
      
  
                In VAX MACRO, each argument is symbolically defined as the offset
               relative to the argument pointer (AP).
        Lists the arguments in the order they will appear in a high-level
      language. Each argument characteristic should also be included, using
      the procedure argument notation described in OpenVMS Programming Interfaces:  Calling a System Routine. Note that
      this manual has been archived but is available on the OpenVMS
      Documentation CD-ROM.
      | 
   
  
    | 
      Formal arguments:
     | 
    
      Lists any explicit input, input/output, or output arguments. Includes a
      qualifying description with each argument. The arguments should be
      listed in the order they are listed in the calling sequence.
     | 
   
  
    | 
      Implicit inputs:
     | 
    
      Lists any inputs from storage, internal or external to the module, that
      are not specified in the argument list. Usually all that will appear
      here is NONE. See Section 2.2.2.
     | 
   
  
    | 
      Implicit outputs:
     | 
    
      Lists any outputs to internal or external storage that are not
      specified in the argument list.
     | 
   
  
    
      Completion status or
        routine value:
      
     | 
    
      Lists the success or failure condition value symbols that could be
      returned. If your procedure returns a function value other than a
      condition value, change the heading to "Routine value."
     | 
   
  
    | 
      Side effects:
     | 
    
      Describes any functional side effects not evident from a procedure's
      calling sequence. This includes changes in storage allocation, process
      status, file operations, and possible signaled conditions. In general,
      you should document anything out of the ordinary that the procedure
      does to the environment. If a side effect modifies local or global
      storage locations, document it in the implicit output description
      instead.
     | 
   
 
Example 2-5 shows a sample procedure description.
 
 
  
    | Example 2-5 Sample Procedure Description | 
   
  
    
       
      
!++
! FUNCTIONAL DESCRIPTION:
!
!       Return the system date and time, using the caller's
!       semantics for his/her string.
!
!       Non-reentrant; uses static storage.
!
! FORMAL ARGUMENT(S):
!
!       RESULT_ADDR
!       VMS USAGE : char_string
!       TYPE      : character string
!       ACCESS    : write only
!       MECHANISM : by descriptor
!
!      Address of the descriptor into which the
!      system date and time is written.
!
! IMPLICIT INPUTS:
!
!       NONE
!
! IMPLICIT OUTPUTS:
!
!       NONE
!
! COMPLETION CODES:
!
!       SS$_NORMAL      Procedure successfully completed
!       LIB$_STRTRU     Success, but source string truncated
!
! SIDE EFFECTS:
!
!       Requests the current date and time from OpenVMS.
!
!--
 
 |   
2.7 Planning for Signaling and Condition Handling
Two methods are available to a procedure for indicating to its caller
whether it completed successfully. One method is to return a condition
value. The other method is to signal an error condition.
 
To provide a better user interface, all procedures in a facility should
either return condition values or signal error conditions. Regardless
of which method you choose, you should be consistent within the
facility to make the procedures easier for the user to call.
2.7.1 Guidelines for Signaling Error Conditions
 
The signaling of an error condition is, in some instances, mandatory.
 
Procedures that return a function value cannot also return a condition
value and therefore must signal any error conditions encountered.
 
However, to maintain efficiency, you might want other procedures to
signal error conditions also. Checking the return status of a called
procedure for repetitive calls can be time consuming and adversely
affect the performance of the calling program. For example, if you are
going to call a procedure 100 times within a loop and the chances of
that procedure's failure are small, you may not want to take the time
to check the return status after each call to make sure that the
condition value returned was SS$_NORMAL. Signaling error conditions is
far more efficient in this type of application.
 
From the point of view of the calling program, handling a signaled
condition is slightly more difficult than checking a returned condition
value because it involves writing a condition handler to be invoked in
the event that an error condition is signaled. However, handling a
signaled condition allows the calling program to execute more
efficiently.
 
To signal an error condition, your procedure uses either a
condition-handling mechanism provided by the source language, or it
calls the Run-Time Library procedure LIB$SIGNAL. To use LIB$SIGNAL,
your procedure calls LIB$SIGNAL and specifies the condition code and
zero or more arguments specifying the environment of the condition. For
more information about using LIB$SIGNAL, see the OpenVMS RTL Library (LIB$) Manual.
2.7.2 Guidelines for Returning Condition Values
 
From the point of view of the calling program, it is much easier to
check returned condition values than to handle signaled error
conditions. When the condition value is being returned, the calling
program does not need to include a condition handler. The calling
program needs only to check the status of the returned value.
 
However, if you return condition values rather than signal error
conditions, you return less information about the error condition to
the calling program. Compaq recommends that you return condition values
when the explanation of the error condition is simple and
self-contained. For example, LIB$GET_VM returns a condition value,
because the possible status conditions are self-contained and simple
(for example, insufficient virtual memory).
 
According to the OpenVMS Calling Standard, the status returned must be a condition
value. (For more information, see OpenVMS Programming Interfaces:  Calling a System Routine1.
2.7.3 When to Signal or Return Condition Values
 
To some degree, whether you decide to signal an error condition or
return a condition value depends on the language you are using for your
procedure. In some high-level languages, it is difficult to write a
condition handler to be invoked in the event that an error condition is
signaled. (For more information about condition handling in your
language, consult the appropriate language reference manual.)
 
Regardless of which language you are using, there are general
guidelines for when to return a condition value and when to signal an
error condition.
 
You should signal an error condition in the following situations:
 
  - Your procedure returns a value in R0 and cannot return a condition
  value.
  
 - Your procedure must execute quickly, and checking the return status
  of a condition value would be inefficient.
  
 - Your procedure will be executed repetitively; therefore, checking
  the condition value returned would adversely affect your procedure's
  performance.
  
 - The amount of information you want to return about the error
  condition cannot be contained in a condition value.
  
 - A useful error message requires information that cannot be
  determined until run time. For example, the FDL$PARSE procedure must
  tell you which line of the FDL file was the cause of an error. Because
  the line number of the line containing the error cannot be determined
  until run time, the signal mechanism is preferred.
  
 - You want to execute a specific condition handler in the event that
  an error condition is signaled.
  
You should return a condition value in the following situations:
 
  - You want to keep the error-handling mechanism simple.
  
 - The speed of the error-checking mechanism is not of great concern.
  
 - The total possible errors that may be returned is a small number,
  and sufficient information about those errors can be contained in the
  condition value returned.
  
 - The functions provided by the procedure are so general that the
  procedure will be used in various levels and environments.
  
 
  
    
      Note 
         
        
        1  This manual has been archived but is
        available on the OpenVMS Documentation CD-ROM.
    
     | 
   
 
 
  
  
		
	
 
  
  |