 |
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.
|
|