Document revision date: 30 March 2001

## OpenVMS Programming Concepts Manual

Previous | Contents | Index

#### 26.3.3.1 Explicitly Named Modules and Libraries

You can resolve a global symbol reference by naming the defining object module in the link command. For example, if the program unit INCOME references the subprogram GET_STATS, you can resolve the global symbol reference when you link INCOME by including the file containing the object module for GET_STATS, as follows:

    $ LINK INCOME, GETSTATS

If the modules that define the symbols are in an object library, name the library in the link operation. In the following example, the GET_STATS module resides in the object module library INCOME.OLB:

    $ LINK INCOME,INCOME/LIBRARY

#### 26.3.3.2 System Default Libraries

Link operations automatically check the system object and shareable image libraries for any references to global symbols not resolved by your explicitly named object modules and libraries. The system object and shareable image libraries include the entry points for the RTL routines and system services, condition codes, and other system-defined values. Invocations of these modules do not require any explicit action by you at link time.

#### 26.3.3.3 User Default Libraries

If you write general-purpose procedures or define general-purpose symbols, you can place them in a user default library. (You can also make your development library a user default library.) In this way, you can link to the modules containing these procedures and symbols without explicitly naming the library in the DCL LINK command. To name a single-user library, equate the file name of the library to the logical name LNK$LIBRARY. For subsequent default libraries, use the logical names LNK$LIBRARY_1 through LNK$LIBRARY_999, as described in Section 26.1.1.

#### 26.3.3.4 Making a Library Available for Systemwide Use

To make a library available to everyone using the system, define it at the system level. To restrict use of a library or to override a system library, define the library at the process or group level. The following command line defines the default user library at the system level:

    $ DEFINE/SYSTEM LNK$LIBRARY $DISK1:[DEV]PROCEDURES

#### 26.3.3.5 Macro Libraries

Some system symbols are not defined in the system object and shareable image libraries. In such cases, the OpenVMS System Services Reference Manual notes that the symbols are defined in the system macro library and tells you the name of the macro containing the symbols. To access these symbols, you must first assemble a macro routine with the following source code. The keyword GLOBAL must be in uppercase. The .TITLE directive is optional but recommended.

     .TITLE macro-name
     macro-name      GLOBAL
       .
       .
       .
     .END

The following example is a macro program that includes two system macros:

LBRDEF.MAR

     .TITLE $LBRDEF
     $LBRDEF GLOBAL
     $LHIDEF GLOBAL
     .END

Assemble the routine containing the macros with the MACRO command. You can place the resultant object modules in a default library or in a library that you specify in the LINK command, or you can specify the object modules in the LINK command. The following example places the $LBRDEF and $LHIDEF modules in a library before performing a link operation:

    $ MACRO LBRDEF
    $ LIBRARY/REPLACE INCOME LBRDEF
    $ DELETE LBRDEF.OBJ;*
    $ LINK INCOME,INCOME/LIBRARY

The following LINK command uses the object file directly:

    $ LINK INCOME,LBRDEF,INCOME/LIBRARY

### 26.3.4 Sharing Data

Typically, you use an installed common block either to facilitate interprocess communication or to allow two or more processes to access the same data simultaneously. However, you must have the CMKRNL privilege to install the common block. If you do not have the CMKRNL privilege, global sections allow you to perform the same operations.

#### 26.3.4.1 Installed Common Blocks

To share data among processes by using a common block, you must install the common block as a shared shareable image and link each program that references the common block against that shareable image.

To install a common block as a shared image:

1. Define a common block---Write a program that declares the variables in the common block and defines the common block. This program should not contain executable code. The following Compaq Fortran program defines a common block:

   INC_COMMON.FOR

       INTEGER TOTAL_HOUSES
       REAL PERSONS_HOUSE (2048),
       2    ADULTS_HOUSE (2048),
       2    INCOME_HOUSE (2048)
       COMMON /INCOME_DATA/ TOTAL_HOUSES,
       2                    PERSONS_HOUSE,
       2                    ADULTS_HOUSE,
       2                    INCOME_HOUSE

       END

2. Create the shareable image---Compile the program containing the common block. Use the LINK/SHAREABLE command to create a shareable image containing the common block.

       $ FORTRAN INC_COMMON
       $ LINK/SHAREABLE INC_COMMON

   For Alpha only, you need to specify a Linker options file (shown here as SYS$INPUT to allow typed input) to specify the PSECT attributes of the COMMON block PSECT and include it in the global symbol table:

       $ LINK/SHAREABLE INC_COMMON ,SYS$INPUT/OPTION
       _ SYMBOL_VECTOR=(WORK_AREA=PSECT)
       _ PSECT_ATTR=WORK_AREA,SHR

   With Compaq Fortran 90 on OpenVMS Alpha systems, the default PSECT attribute for a common block is NOSHR. To use a shared installed common block, you must specify one of the following:
   - The SHR attribute in a cDEC$ PSECT directive in the source file
   - The SHR attribute in the Linker options file for the shareable image to be installed and for each executable image that references the installed common block
   If the !DEC$ PSECT (same as cDEC$ PSECT) directive specified the SHR attribute, the LINK command is as follows:

       $ LINK/SHAREABLE INC_COMMON  ,SYS$INPUT/OPTION
       _ SYMBOL_VECTOR=(WORK_AREA=PSECT)

   For Alpha only, copy the shareable image. Once created, you should copy the shareable image into SYS$SHARE before it is installed. The file protection of the .EXE file must allow write access for the processes running programs that will access the shareable image (shown for Group access in the following COPY command):

       $ COPY/LOG DISK$:[INCOME.DEV]INC_COMMON.EXE SYS$SHARE:*.*
       _ /PROTECTION=G:RWE

   On Alpha systems, if you do not copy the installed shareable image to SYS$SHARE, before running executable images that reference the installed shareable common image, you must define a logical name that specifies the location of that image.
   On Alpha systems, when compiling the program that contains the common block declarations, consistently use the same /ALIGNMENT and /GRANULARITY qualifiers used to compile the common block data declaration program that has been installed as a shareable image. For more information, see Section 26.3.4.3.
3. Install the shareable image---Use the DCL command SET PROCESS/PRIVILEGE to give yourself CMKRNL privilege (required for use of the Install utility). Use the DCL command INSTALL to invoke the interactive Install utility. When the INSTALL prompt appears, enter CREATE, followed by the complete file specification of the shareable image that contains the common block (the file type defaults to .EXE) and the qualifiers /WRITEABLE and /SHARED. The Install utility installs your shareable image and reissues the INSTALL prompt. Enter EXIT to exit. Remember to remove CMKRNL privilege. (For complete documentation of the Install utility, see the OpenVMS System Management Utilities Reference Manual.)
   The following example shows how to install a shareable image:

       $ SET PROCESS/PRIVILEGE=CMKRNL
       $ INSTALL
       INSTALL> CREATE DISK$USER:[INCOME.DEV]INC_COMMON -
       _INSTALL> /WRITEABLE/SHARED
       INSTALL> EXIT
       $ SET PROCESS/PRIVILEGE=NOCMKRNL

   Note A disk containing an installed image cannot be dismounted. To remove an installed image, invoke the Install utility and enter DELETE followed by the complete file specification of the image. The DELETE subcommand does not delete the file from the disk; it removes the file from the list of known installed images.

Perform the following steps to write or read the data in an installed common block from within any program:

1. Include the same variable and common block definitions in the program.
2. Compile the program.
   For Alpha only, when compiling the program that contains the common block declarations, consistently use the same /ALIGNMENT and /GRANULARITY qualifiers used to compile the common block data declaration program that has been installed as a shareable image. For more information, see Section 26.3.4.3.
3. Link the program against the shareable image that contains the common block. (Linking against a shareable image requires an options file.)

       $ LINK INCOME, DATA/OPTION
       $ LINK REPORT, DATA/OPTION

   DATA.OPT

       INC_COMMON/SHAREABLE

   For Alpha only, linking is as follows:

       INC_COMMON/SHAREABLE
       PSECT_ATTR=WORK_AREA, SHR

   If a !DEC$ PSECT (cDEC$ PSECT) directive specified the SHR PSECT attribute, the linker options file INCOME.OPT would contain the following line:

       INC_COMMON/SHAREABLE

   The source line containing the !DEC$ PSECT directive would be as follows:

       !DEC$ PSECT /INC_COMMON/ SHR

4. Execute the program.
   For Alpha only, if the installed image is not located in SYS$SHARE, you must define a logical name that specifies the location of that image. The logical name (in this example INC_COMMON) is the name of the installed base.

In the previous series of examples, the two programs INCOME and REPORT access the same area of memory through the installed common block INCOME_DATA (defined in INC_COMMON.FOR).

Typically, programs that access shared data use common event flag clusters to synchronize read and write access to the data. Refer to Chapter 7 for more information about using event flags for program synchronization.

#### 26.3.4.2 Using Global Sections

To share data by using global sections, each process that plans to access the data includes a common block of the same name, which contains the variables for the data. The first process to reference the data declares the common block as a global section and, optionally, maps data to the section. (Data in global sections, as in private sections, must be page aligned.)

To create a global section, invoke SYS$CRMPSC and add the following:

- Additional argument---Specify the name of the global section (argument 5). A program uses this name to access a global section.
- Additional flag---Set the SEC$V_GBL bit of the flags argument to indicate that the section is a global section.

As other programs need to reference the data, each can use either SYS$CRMPSC or SYS$MGBLSC to map data into the global section. If you know that the global section exists, the best practice is to use the SYS$MGBLSC system service.

The format for SYS$MGBLSC is as follows:

`SYS$MGBLSC (inadr ,[retadr] ,[acmode] ,[flags] ,gsdnam ,[ident] ,[relpag])`

Refer to the OpenVMS System Services Reference Manual for complete information about this system service.

In Example 26-1, one image, DEVICE.FOR, passes device names to another image, GETDEVINF.FOR. GETDEVINF.FOR returns the process name and the terminal associated with the process that allocated each device. The two processes use the global section GLOBAL_SEC to communicate. GLOBAL_SEC is mapped to the common block named DATA, which is page aligned by the options file DATA.OPT. Event flags are used to synchronize the exchange of information. UFO_CREATE.FOR, DATA.OPT, and DEVICE.FOR are included here for easy reference. Refer to Section 28.4 for additional information about global sections.

Example 26-1 Interprocess Communication Using Global Sections

    !UFO_CREATE.FOR
       .
       .
       .
    INTEGER FUNCTION UFO_CREATE (FAB,
    2                            RAB,
    2                            LUN)

    ! Include RMS definitions
    INCLUDE '($FABDEF)'
    INCLUDE '($RABDEF)'

    ! Declare dummy arguments
    RECORD /FABDEF/ FAB
    RECORD /RABDEF/ RAB
    INTEGER LUN

    ! Declare channel
    INTEGER*4 CHAN
    COMMON /CHANNEL/ CHAN

    ! Declare status variable
    INTEGER STATUS

    ! Declare system procedures
    INTEGER SYS$CREATE

    ! Set useropen bit in the FAB options longword
    FAB.FAB$L_FOP = FAB.FAB$L_FOP .OR. FAB$M_UFO
    ! Open file
    STATUS = SYS$CREATE (FAB)

    ! Read channel from FAB status word
    CHAN = FAB.FAB$L_STV

    ! Return status of open operation
    UFO_CREATE = STATUS

    END

DATA.OPT

    PSECT_ATTR = DATA, PAGE

DEVICE.FOR

    ! Define global section flags
    INCLUDE '($SECDEF)'
    ! Mask for section flags
    INTEGER SEC_MASK
    ! Logical unit number for section file
    INTEGER INFO_LUN
    ! Channel number for section file
    INTEGER SEC_CHAN
    COMMON /CHANNEL/ SEC_CHAN
    ! Length for the section file
    INTEGER SEC_LEN
    ! Data for the section file
    CHARACTER*12 DEVICE,
    2            PROCESS
    CHARACTER*6 TERMINAL
    COMMON /DATA/ DEVICE,
    2             PROCESS,
    2             TERMINAL
    ! Location of data
    INTEGER PASS_ADDR (2),
    2       RET_ADDR (2)
    ! Two common event flags
    INTEGER REQUEST_FLAG,
    2       INFO_FLAG
    DATA REQUEST_FLAG /70/
    DATA INFO_FLAG /71/
    ! User-open routines
    INTEGER UFO_CREATE
    EXTERNAL UFO_CREATE
       .
       .
       .
    ! Open the section file
    STATUS = LIB$GET_LUN (INFO_LUN)
    IF (.NOT. STATUS) CALL LIB$SIGNAL(%VAL(STATUS))
    SEC_MASK = SEC$M_WRT .OR. SEC$M_DZRO .OR. SEC$M_GBL
    ! (last address -- first address + length of last element + 511)/512
    SEC_LEN = ( (%LOC(TERMINAL) - %LOC(DEVICE) + 6 + 511)/512 )
    OPEN (UNIT=INFO_LUN,
    2     FILE='INFO.TMP',
    2     STATUS='NEW',
    2     INITIALSIZE = SEC_LEN,
    2     USEROPEN = UFO_CREATE)
    ! Free logical unit number and map section
    CLOSE (INFO_LUN)
    ! Get location of data
    PASS_ADDR (1) = %LOC (DEVICE)
    PASS_ADDR (2) = %LOC (TERMINAL)
    STATUS = SYS$CRMPSC (PASS_ADDR,      ! Address of section
    2                    RET_ADDR,       ! Addresses mapped
    2                    ,
    2                    %VAL(SEC_MASK), ! Section mask
    2                    'GLOBAL_SEC',   ! Section name
    2                    ,,
    2                    %VAL(SEC_CHAN), ! I/O channel
    2                    ,,,)
    IF (.NOT. STATUS) CALL LIB$SIGNAL(%VAL(STATUS))
    ! Create the subprocess
    STATUS = SYS$CREPRC (,
    2                    'GETDEVINF',    ! Image
    2                    ,,,,,
    2                    'GET_DEVICE',   ! Process name
    2                    %VAL(4),,,)     ! Priority
    IF (.NOT. STATUS) CALL LIB$SIGNAL(%VAL(STATUS))
    ! Write data to section
    DEVICE = '$FLOPPY1'
    ! Get common event flag cluster and set flag
    STATUS = SYS$ASCEFC (%VAL(REQUEST_FLAG),
    2                    'CLUSTER',,)
    IF (.NOT. STATUS) CALL LIB$SIGNAL(%VAL(STATUS))
    STATUS = SYS$SETEF (%VAL(REQUEST_FLAG))
    IF (.NOT. STATUS) CALL LIB$SIGNAL(%VAL(STATUS))
    ! When GETDEVINF has the information, INFO_FLAG is set
    STATUS = SYS$WAITFR (%VAL(INFO_FLAG))
    IF (.NOT. STATUS) CALL LIB$SIGNAL(%VAL(STATUS))
       .
       .
       .

GETDEVINF.FOR

    ! Define section flags
    INCLUDE '($SECDEF)'
    ! Mask for section flags
    INTEGER SEC_MASK
    ! Data for the section file
    CHARACTER*12 DEVICE,
    2            PROCESS
    CHARACTER*6  TERMINAL
    COMMON /DATA/ DEVICE,
    2             PROCESS,
    2             TERMINAL
    ! Location of data
    INTEGER PASS_ADDR (2),
    2       RET_ADDR (2)
    ! Two common event flags
    INTEGER REQUEST_FLAG,
    2       INFO_FLAG
    DATA REQUEST_FLAG /70/
    DATA INFO_FLAG /71/
       .
       .
       .
    ! Get common event flag cluster and wait
    ! for GBL1.FOR to set REQUEST_FLAG
    STATUS = SYS$ASCEFC (%VAL(REQUEST_FLAG),
    2                    'CLUSTER',,)
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS))
    STATUS = SYS$WAITFR (%VAL(REQUEST_FLAG))
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS))
    ! Get location of data
    PASS_ADDR (1) = %LOC (DEVICE)
    PASS_ADDR (2) = %LOC (TERMINAL)
    ! Set write flag
    SEC_MASK = SEC$M_WRT
    ! Map the section
    STATUS = SYS$MGBLSC (PASS_ADDR,      ! Address of section
    2                    RET_ADDR,       ! Address mapped
    2                    ,
    2                    %VAL(SEC_MASK), ! Section mask
    2                    'GLOBAL_SEC',,) ! Section name
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS))
    ! Call GETDVI to get the process ID of the
    ! process that allocated the device, then
    ! call GETJPI to get the process name and terminal
    ! name associated with that process ID.
    ! Set PROCESS equal to the process name and
    ! set TERMINAL equal to the terminal name.
       .
       .
       .
    ! After information is in GLOBAL_SEC
    STATUS = SYS$SETEF (%VAL(INFO_FLAG))
    IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS))

    END

By default, a global section is deleted when no image is mapped to it. Such global sections are called temporary global sections. If you have the PRMGBL privilege, you can create a permanent global section (set the SEC$V_PERM bit of the flags argument when you invoke SYS$CRMPSC). A permanent global section is not deleted until after it is marked for deletion with the SYS$DGBLSC system service (requires PRMGBL). Once a permanent section is marked for deletion, it is like a temporary section; when no image is mapped to it, the section is deleted.

#### 26.3.4.3 Synchronizing Access to Global Sections

On Alpha systems, if more than one process or thread will write to a shared global section containing COMMON block data, the user program may need to synchronize access to COMMON block variables.

On Alpha systems, compile all programs referencing the shared common area with the same value for the /ALIGNMENT and /GRANULARITY qualifiers, as shown in the following:

    $ F90 /ALIGN=COMMONS=NATURAL /GRANULARITY=LONGWORD INC_COMMON

On Alpha systems, using /GRANULARITY=LONGWORD for 4-byte variables or /GRANULARITY=QUADWORD for 8-byte variables ensures that adjacent data is not accidentally effected. To ensure access to 1-byte variables, specify /GRANULARITY=BYTE. Because accessing data items less than four bytes slows run-time performance, you might want to considering synchronizing read and write access to the data on the same node.

One way for programs accessing shared data is to use common event flag clusters to synchronize read and write access to the data on the same node. In the simplest case, one event flag in a common event flag cluster might indicate that a program is writing data, and a second event flag in the cluster might indicate that a program is reading data. Before accessing the shared data, a program must examine the common event flag cluster to ensure that accessing the data does not conflict with an operation already in progress.

Other ways of synchronizing access on a single node include using the following OpenVMS system services:

- The lock manager system services (SYS$ENQ and SYS$DEQ)
- The hibernate and wake system services (SYS$HIBER and SYS$WAKE)

You could also use Assembler code for synchronization.

#### 26.3.4.4 RMS Shared Files

RMS allows concurrent access to a file. Shared files can be one of the following formats:

- Indexed files
- Relative files
- Sequential files with 512-byte fixed-length records

To coordinate access to a file, RMS uses the lock manager. You can override the RMS lock manager by controlling access yourself. Refer to Chapter 7 for more information about synchronizing access to resources.

Previous | Next | Contents | Index

| privacy and legal statement |
5841PRO_071.HTML