Document revision date: 19 July 1999
[Compaq] [Go to the documentation home page] [How to order documentation] [Help on this site] [How to contact us]
[OpenVMS documentation]

OpenVMS Programming Concepts Manual


Previous Contents Index

7.3.2 Integer and Floating-Point Routines

Integer and floating-point routines give a high-level language program access to the corresponding machine instructions. For a complete description of these instructions, see the VAX Architecture Reference Manual. Table 7-4 lists the integer and floating-point routines once up front.

Table 7-4 Integer and Floating-Point Routines
Entry Point Function
LIB$EMUL Multiplies integers with extended precision
LIB$EDIV Divides integers with extended precision

7.3.3 Queue Access Routines

A queue is a doubly linked list. A run-time library routine specifies a queue entry by its address. Two longwords, a forward link and a backward link, define the location of the entry in relation to the preceding and succeeding entries. A self-relative queue is a queue in which the links between entries are displacements; the two longwords represent the displacements of the current entry's predecessor and successor. The VAX instructions INSQHI, INSQTI, REMQHI, and REMQTI allow you to insert and remove an entry at the head or tail of a self-relative queue. Each queue instruction has a corresponding RTL routine.

The self-relative queue instructions are interlocked and cannot be interrupted, so that other processes cannot insert or remove queue entries while the current program is doing so. Because the operation requires changing two pointers at the same time, a high-level language cannot perform this operation without calling the RTL queue access routines.

When you use these routines, cooperating processes can communicate without further synchronization and without danger of being interrupted, either on a single processor or in a multiprocessor environment. The queue access routines are also useful in an AST environment; they allow you to add or remove an entry from a queue without being interrupted by an asynchronous system trap.

The remove queue instructions (REMQHI or REMQTI) return the address of the removed entry. Some languages, such as BASIC, COBOL, and Fortran, do not provide a mechanism for accessing an address returned from a routine. Further, BASIC and COBOL do not allow routines to be arguments.

Table 7-5 lists the queue access routines.

Table 7-5 Queue Access Routines
Entry Point Function
LIB$INSQHI Inserts queue entry at head
LIB$INSQTI Inserts queue entry at tail
LIB$REMQHI Removes queue entry at head
LIB$REMQTI Removes queue entry at tail

Examples

LIB$INSQHI

In BASIC and Fortran, queues can be quadword aligned in a named COMMON block by using a linker option file to specify alignment of program sections. The LIB$GET_VM routine returns memory that is quadword aligned. Therefore, you should use LIB$GET_VM to allocate the virtual memory for a queue. For instance, to create a COMMON block called QUEUES, use the LINK command with the FILE/OPTIONS qualifier, where FILE.OPT is a linker option file containing the line:


PSECT = QUEUES, QUAD 

A Fortran application using processor-shared memory follows:


INTEGER*4 FUNCTION INSERT_Q (QENTRY) 
COMMON/QUEUES/QHEADER 
INTEGER*4 QENTRY(10), QHEADER(2) 
INSERT_Q = LIB$INSQHI (QENTRY, QHEADER) 
RETURN 
END 

A BASIC application using processor-shared memory follows:


     COM (QUEUES) QENTRY%(9), QHEADER%(1) 
     EXTERNAL INTEGER FUNCTION LIB$INSQHI 
     IF LIB$INSQHI (QENTRY%() BY REF, QHEADER%() BY REF) AND 1% 
          THEN GOTO 1000 
             . 
             . 
             . 
1000 REM  INSERTED OK 

LIB$REMQHI

In Fortran, the address of the removed queue entry can be passed to another routine as an array using the %VAL built-in function.

In the following example, queue entries are 10 longwords, including the two longword pointers at the beginning of each entry:


COMMON/QUEUES/QHEADER 
INTEGER*4 QHEADER(2), ISTAT 
ISTAT = LIB$REMQHI (QHEADER, ADDR) 
IF (ISTAT) THEN 
        CALL PROC (%VAL (ADDR)) ! Process removed entry 
        GO TO ... 
ELSE IF (ISTAT .EQ. %LOC(LIB$_QUEWASEMP)) THEN 
                GO TO ...       ! Queue was empty 
                ELSE IF 
                        ...     ! Secondary interlock failed 
END IF 
   .
   .
   .
END 
SUBROUTINE PROC (QENTRY) 
INTEGER*4 QENTRY(10) 
   .
   .
   .
RETURN 
END 

7.3.4 Character String Routines

The character string routines listed in Table 7-6 give a high-level language program access to the corresponding VAX machine instructions. For a complete description of these instructions, see the VAX Architecture Reference Manual. For each instruction, the VAX Architecture Reference Manual specifies the contents of all the registers after the instruction executes. The corresponding RTL routines do not make the contents of all the registers available to the calling program.

Table 7-6 lists the LIB$ character string routines and their functions.

Table 7-6 Character String Routines
Entry Point Function
LIB$LOCC Locates a character in a string
LIB$MATCHC Returns the relative position of a substring
LIB$SCANC Scans characters
LIB$SKPC Skips characters
LIB$SPANC Spans characters
LIB$MOVC3 Moves characters
LIB$MOVC5 Moves characters and fills
LIB$MOVTC Moves translated characters
LIB$MOVTUC Move translated characters until specified character is found

The OpenVMS RTL String Manipulation (STR$) Manual describes STR$ string manipulation routines.

Example

This COBOL program uses LIB$LOCC to return the position of a given letter of the alphabet.


 
IDENTIFICATION DIVISION. 
PROGRAM-ID.        LIBLOC. 
 
ENVIRONMENT DIVISION. 
 
DATA DIVISION. 
 
WORKING-STORAGE SECTION. 
 
01   SEARCH-STRING  PIC X(26) 
                    VALUE "ABCDEFGHIJKLMNOPQRSTUVWXYZ". 
01   SEARCH-CHAR    PIC X. 
01   IND-POS        PIC 9(9) USAGE IS COMP. 
01   DISP-IND       PIC 9(9). 
 
ROUTINE DIVISION. 
 
001-MAIN. 
        MOVE SPACE TO SEARCH-CHAR. 
        DISPLAY " ". 
        DISPLAY "ENTER SEARCH CHARACTER: " WITH NO ADVANCING. 
        ACCEPT SEARCH-CHAR. 
        CALL "LIB$LOCC" 
            USING BY DESCRIPTOR SEARCH-CHAR, SEARCH-STRING 
            GIVING IND-POS. 
        IF IND-POS = ZERO 
            DISPLAY 
                "CHAR ENTERED (" SEARCH-CHAR ") NOT A VALID SEARCH CHAR" 
            STOP RUN. 
        MOVE IND-POS TO DISP-IND. 
        DISPLAY 
             "SEARCH CHAR (" SEARCH-CHAR ") WAS FOUND IN POSITION " 
             DISP-IND. 
        GO TO 001-MAIN. 
 
 

7.3.5 Miscellaneous Instruction Routines

Table 7-7 lists additional routines that you can use.

Table 7-7 Miscellaneous Instruction Routines
Entry Point Function
LIB$CALLG Calls a routine using an array argument list
LIB$CRC Computes a cyclic redundancy check
LIB$CRC_TABLE Constructs a table for a cyclic redundancy check

LIB$CALLG

The LIB$CALLG routine gives your program access to the CALLG instruction. This instruction calls a routine using an argument list stored as an array in memory, as opposed to the CALLS instruction, in which the argument list is pushed on the stack.

LIB$CRC

The LIB$CRC routine allows your high-level language program to use the CRC instruction, which calculates the cyclic redundancy check. This instruction checks the integrity of a data stream by comparing its state at the sending point and the receiving point. Each character in the data stream is used to generate a value based on a polynomial. The values for each character are then added together. This operation is performed at both ends of the data transmission, and the two result values are compared. If the results disagree, then an error occurred during the transmission.

LIB$CRC_TABLE

The LIB$CRC_TABLE routine takes a polynomial as its input and builds the table that LIB$CRC uses to calculate the CRC. You must specify the polynomial to be used.

For more details, see the VAX Architecture Reference Manual.

7.4 Processwide Resource Allocation Routines

This section discusses routines that allocate processwide resources to a single operating system process. The processwide resources discussed here are:

The resource allocation routines are provided so that user routines can use the processwide resources without conflicting with one another.

In general, you must use run-time library resource allocation routines when your program needs processwide resources. This allows RTL routines, Compaq-supplied routines, and user routines that you write to perform together within a process.

If your called routine includes a call to any RTL routine that frees a processwide resource, and that called routine fails to execute normally, the resource will not be freed. Thus, your routine should establish a condition handler that frees the allocated resource before resignaling or unwinding. For information about condition handling, see Chapter 15.

Table 7-8 list routines that perform processwide resource allocation.

Table 7-8 Processwide Resource Allocation Routines
Entry Point Function
LIB$FREE_LUN Deallocates a specific logical unit number
LIB$GET_LUN Allocates next arbitrary logical unit number
LIB$FREE_EF Frees a local event flag
LIB$GET_EF Allocates a local event flag
LIB$RESERVE_EF Reserves a local event flag

7.4.1 Allocating Logical Unit Numbers

BASIC and Fortran use a logical unit number (LUN) to define the file or device a program uses to perform input and output. For a routine to be modular, it does not need to know the LUNs being used by other routines that are running at the same time. For this reason, logical units are allocated and deallocated at run time. You can use LIB$GET_LUN and LIB$FREE_LUN to obtain the next available number. This ensures that your BASIC or Fortran routine does not use a logical unit that is already being used by a calling program. Therefore, you should use this routine whenever your program calls or is called by another program that also allocates LUNs. Logical unit numbers 100 to 119 are available to modular routines through these entry points.

To allocate an LUN, call LIB$GET_LUN and use the value returned as the LUN for your I/O statements. If no LUNs are available, an error status is returned and the logical unit is set to -1 . When the program unit exits, it should use LIB$FREE_LUN to free any LUNs that have been allocated by LIB$GET_LUN. If it does not free any LUNs, the available pool of numbers is freed for use.

If your called routine contains a call to LIB$FREE_LUN to free the LUNs upon exit, and your routine fails to execute normally, the LUNs will not be freed. For this reason, you should make sure to establish a condition handler to call LIB$FREE_LUN before resignaling or unwinding. Otherwise, the allocated LUN is lost until the image exits.

7.4.2 Allocating Event Flag Numbers

The LIB$GET_EF and LIB$FREE_EF routines operate in a similar way to LIB$GET_LUN and LIB$FREE_LUN. They cause local event flags to be allocated and deallocated at run time, so that your routine remains independent of other routines executing in the same process.

Local event flags numbered 32 to 63 are available to your program. These event flags allow routines to communicate and synchronize their operations. If you use a specific event flag in your routine, another routine may attempt to use the same flag, and the flag will no longer function as expected. Therefore, you should call LIB$GET_EF to obtain the next arbitrary event flag and LIB$FREE_EF to return it to the storage pool. You can obtain a specific event flag number by calling LIB$RESERVE_EF. This routine takes as its argument the event flag number to be allocated.

For information about using event flags, see Chapter 2 and Chapter 16.

7.5 Performance Measurement Routines

The run-time library timing facility consists of four routines to store count and timing information, display the requested information, and deallocate the storage. Table 7-9 lists these routines and their functions.

Table 7-9 Performance Measurement Routines
Entry Point Function
LIB$INIT_TIMER Stores the values of the specified times and counts in units of static or heap storage, depending on the value of the routine's argument
LIB$SHOW_TIMER Gets and formats for output the specified times and counts that are accumulated since the last call to LIB$INIT_TIMER
LIB$STAT_TIMER Gets one of the times and counts since the last call to LIB$INIT_TIMER and returns it as an unsigned quadword or longword
LIB$FREE_TIMER Frees the storage allocated by LIB$INIT_TIMER

Using these routines, you can access the following statistics:

The LIB$SHOW_TIMER and LIB$STAT_TIMER routine are relatively simple tools for testing the performance of a new application. To obtain more detailed information, use the system services SYS$GETTIM (Get Time) and SYS$GETJPI (Get Job/Process Information).

The simplest way to use the run-time library routines is to call LIB$INIT_TIMER with no arguments at the beginning of the portion of code to be monitored. This causes the statistics to be placed in OWN storage. To get the statistics from OWN storage, call LIB$SHOW_TIMER (with no arguments) at the end of the portion of code to be monitored.

If you want a particular statistic, you must include a code argument with a call to LIB$SHOW_TIMER or LIB$STAT_TIMER. LIB$SHOW_TIMER returns the specified statistic(s) in formatted form and sends them to SYS$OUTPUT. On each call, LIB$STAT_TIMER returns one statistic to the calling program as an unsigned longword or quadword value.

Table 7-10 shows the code argument in LIB$SHOW_TIMER or LIB$STAT_TIMER.

Table 7-10 The Code Argument in LIB$SHOW_TIMER and LIB$STAT_TIMER
Argument Value
Meaning
LIB$SHOW_TIMER Format LIB$STAT_TIMER Format
1 Elapsed real time dddd hh:mm:ss.cc Quadword, in system time format
2 Elapsed CPU time hhhh:mm:ss.cc Longword, in 10-millisecond increments
3 Number of buffered I/O operations nnnn Longword
4 Number of direct I/O operations nnnn Longword
5 Number of page faults nnnn Longword

When you call LIB$INIT_TIMER, you must use the optional handler argument only if you want to keep several sets of statistics simultaneously. This argument points to a block in heap storage where the statistics are to be stored. You need to call LIB$FREE_TIMER only if you have specified handler in LIB$INIT_TIMER and you want to deallocate all heap storage resources. In most cases, the implicit deallocation when the image exits is sufficient.

The LIB$STAT_TIMER routine returns only one of the five statistics for each call, and it returns that statistic in the form of an unsigned quadword or longword. LIB$SHOW_TIMER returns the virtual address of the stored information, which BASIC cannot directly access. Therefore, a BASIC program must call LIB$STAT_TIMER and format the returned statistics, as the following example demonstrates.

Example

The following BASIC example uses the run-time library performance analysis routines to obtain timing statistics. It then calls the $ASCTIM system service to translate the 64-bit binary value returned by LIB$STAT_TIMER into an ASCII text string.


 
100    EXTERNAL INTEGER FUNCTION LIB$INIT_TIMER 
       EXTERNAL INTEGER FUNCTION LIB$STAT_TIMER 
       EXTERNAL INTEGER FUNCTION LIB$FREE_TIMER 
       EXTERNAL INTEGER CONSTANT SS$_NORMAL 
 
200    DECLARE LONG COND_VALUE, RANDOM_SLEEP 
       DECLARE LONG CODE, HANDLE 
       DECLARE STRING TIME_BUFFER 
       HANDLE = 0 
       TIME_BUFFER = SPACE$(50%) 
 
300    MAP (TIMER) LONG ELAPSED_TIME, FILL 
       MAP (TIMER) LONG CPU_TIME 
       MAP (TIMER) LONG BUFIO 
       MAP (TIMER) LONG DIRIO 
       MAP (TIMER) LONG PAGE_FAULTS 
 
400    PRINT "This program returns information about:" 
       PRINT "Elapsed time (1)" 
       PRINT "CPU time (2)" 
       PRINT "Buffered I/O (3)" 
       PRINT "Direct I/O (4)" 
       PRINT "Page faults (5)" 
       PRINT "Enter zero to exit program" 
       PRINT "Enter a number from one to" 
       PRINT "five for performance information" 
       INPUT "One, two, three, four, or five"; CODE 
       PRINT 
 
450    GOTO 32766 IF CODE = 0 
 
500    COND_VALUE = LIB$INIT_TIMER( HANDLE ) 
 
550    IF (COND_VALUE <> SS$_NORMAL) THEN PRINT @ 
         "Error in initialization" 
              GOTO 32767 
 
650    A = 0                ! 
       FOR I = 1 to 100000  ! This code merely uses some CPU time 
       A = A + 1            ! 
       NEXT I               ! 
 
700    COND_VALUE = LIB$STAT_TIMER( CODE, ELAPSED_TIME, HANDLE ) 
 
750    IF (COND_VALUE <> SS$_NORMAL) THEN PRINT @ 
         "Error in statistics routine" 
              GOTO 32767 
 
800    GOTO 810 IF CODE <> 1% 
       CALL SYS$ASCTIM ( , TIME_BUFFER, ELAPSED_TIME, 1% BY VALUE) 
       PRINT "Elapsed time: "; TIME_BUFFER 
 
810    PRINT "CPU time in seconds: "; .01 * CPU_TIME IF CODE = 2% 
       PRINT "Buffered I/O: ";BUFIO IF CODE = 3% 
       PRINT "Direct I/O: ";DIRIO IF CODE = 4% 
       PRINT "Page faults: ";PAGE_FAULTS IF CODE = 5% 
       PRINT 
 
900    GOTO 400 
 
32765  COND_VALUE = LIB$FREE_TIMER( HANDLE ) 
32766  IF (COND_VALUE <> SS$_NORMAL) THEN PRINT @ 
         "Error in LIB$FREE_TIMER" 
                        GOTO 32767 
 
32767  END 
 

For information about using system time, see Chapter 6.

7.6 Output Formatting Control Routines

Table 7-11 lists the run-time library routines that customize output.

Table 7-11 Routines for Customizing Output
Entry Point Function
LIB$CURRENCY Defines the default currency symbol for process
LIB$DIGIT_SEP Defines the default digit separator for process
LIB$LP_LINES Defines the process default size for a printed page
LIB$RADIX_POINT Defines the process default radix point character

The LIB$CURRENCY, LIB$DIGIT_SEP, LIB$LP_LINES, and LIB$RADIX_POINT routines allow you to customize output. Using them, you can define the logical names SYS$CURRENCY, SYS$DIGIT_SEP, SYS$LP_LINES, and SYS$RADIX_POINT to specify your own currency symbol, digit separator, radix point, or number of lines per printed page. Each routine works by attempting to translate the associated logical name as a process, group, or system logical name. If you have redefined a logical name for a specific local application, then the translation succeeds, and the routine returns the value that corresponds to the option you have chosen. If the translation fails, the routine returns a default value provided by the run-time library, as follows:
$ SYS$CURRENCY
, SYS$DIGIT_SEP
. SYS$RADIX_POINT
66 SYS$LP_LINES

For example, if you want to use the British pound sign (£) as the currency symbol within your process, but you want to leave the dollar sign ($) as the system default, define SYS$CURRENCY to be in your process logical name table. Then, any calls to LIB$CURRENCY within your process return "£", while any calls outside your process return "$".

You can use LIB$LP_LINES to monitor the current default length of the line printer page. You can also supply your own default length for the current process. United States standard paper size permits 66 lines on each physical page.

If you are writing programs for a utility that formats a listing file to be printed on a line printer, you can use LIB$LP_LINES to make your utility independent of the default page length. Your program can use LIB$LP_LINES to obtain the current length of the page. It can then calculate the number of lines of text per page by subtracting the lines used for margins and headings.

The following is one suggested format:


Previous Next Contents Index

  [Go to the documentation home page] [How to order documentation] [Help on this site] [How to contact us]  
  privacy and legal statement  
5841PRO_020.HTML