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

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

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 19-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 10.4 for additional information about global sections.

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

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

You could also use Assembler code for synchronization.

19.3.4.4 RMS Shared Files

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

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 17 for more information about synchronizing access to resources.


Chapter 20
Creating User-Written System Services

This chapter describes how to create user-written system services. It contains the following sections:

Section 20.1 describes privileged routines and privileged shareable images.

Section 20.2 describes how to write a privileged routine.

Section 20.3 describes how to create a privileged shareable image on VAX systems.

Section 20.4 describes how to create a privileged shareable image on Alpha systems.

20.1 Overview

Your application may contain certain routines that perform privileged functions, called user-written system services. To create these routines, put them in a privileged shareable image. User-mode routines in other modules can call the routines in the privileged shareable image to perform functions in a more privileged mode.

You create a privileged shareable image as you would any other shareable image, using the /SHAREABLE qualifier with the linker. (For more information about how to create a shareable image, see the OpenVMS Linker Utility Manual.) However, because a call to a routine in a more privileged mode must be vectored through the system service dispatch routine, you must perform some additional steps. The following steps outline the basic procedure. Section 20.3 provides more detail about requirements specific to VAX systems. Section 20.4 describes the necessary steps for Alpha systems.

  1. Create the source file. The source file for a privileged shareable image contains the routines that perform privileged functions. In addition, because user-written system services are called using the system service dispatcher, you must include a privileged library vector (PLV) in your shareable image. A PLV is an operating-system-defined data structure that communicates the location of the privileged routines to the operating system.
    On VAX systems, the PLV contains the addresses of dispatch routines for each access mode used in the image. You must write these dispatch routines and include them in your shareable image. Section 20.3.1 provides more information.
    On Alpha systems, you list the names of the privileged routines in the PLV, sorted by access mode. You do not need to create dispatch routines; the image activator creates them for you automatically.
    Section 20.2 provides guidelines for creating privileged routines.
  2. Compile or assemble the source file.
  3. Create the shareable image. You create a privileged shareable image as you would any other shareable image: by specifying the /SHAREABLE qualifier to the LINK command. Note, however, that creating privileged shareable images has some additional requirements. The following list summarizes these requirements. See the OpenVMS Linker Utility Manual for additional information about linker qualifiers and options.
    If your privileged application requires that you link against the system executive, see the OpenVMS Linker Utility Manual for more information.
  4. Install the privileged shareable image as a protected permanent global section. Privileged shareable images must be installed to be available to nonprivileged programs. The following procedure is recommended:
    1. Move the privileged shareable image to a protected directory, such as SYS$SHARE.
    2. Invoke the Install utility, specifying the /PROTECT, /OPEN, and /SHARED qualifiers. You can also specify the /HEADER_RESIDENT qualifier. The following entry could be used to install a user-written system service whose image name is MY_PRIV_SHARE:


      $ INSTALL
      INSTALL> ADD SYS$SHARE:MY_PRIV_SHARE/PROTECT/OPEN/SHARED/HEADER_RES
      

To use a privileged shareable image, you include it in a link operation as you would any other shareable image: specifying the shareable image in a linker options file with the /SHAREABLE qualifier appended to the file specification to identify it as a shareable image.

20.2 Writing a Privileged Routine (User-Written System Service)

On both VAX systems and Alpha systems, the routines that implement user-written system services must enable any privileges they need that the nonprivileged user of the user-written system service lacks. The user-written system service must also disable any such privileges before the nonprivileged user receives control again. To enable or disable a set of privileges, use the Set Privileges ($SETPRV) system service. The following example shows the operator (OPER) and physical I/O (PHY_IO) privileges being enabled. (Any code executing in executive or kernel mode is granted an implicit SETPRV privilege so it can enable any privileges it needs.)


PRVMSK:  .LONG   <1@PRV$V_OPER>!<1@PRV$V_PHY_IO> ;OPER and PHY_IO 
         .LONG   0     ;quadword mask required.  No bits set in 
                       ;high-order longword for these privileges. 
           . 
           . 
           . 
        $SETPRV_S  ENBFLG=#1,-       ;1=enable, 0=disable 
                   PRVADR=PRVMSK     ;Identifies the privileges 

When you design your system service, you must carefully define the boundaries between the protected subsystem and the user who calls the service. A protected image has privileges to perform tasks on its own behalf. When your image performs tasks on behalf of the user, you must ensure that your image performs only those tasks the user could not have done on his or her own. Always keep the following coding principles in mind:

On VAX systems, refer to SYS$EXAMPLES:USSDISP.MAR and USSTEST.MAR for listings of modules in a user-written system service and of a module that calls the user-written system service.

On Alpha systems, for C examples refer to SYS$EXAMPLES:UWSS.C and SYS$EXAMPLES:UWSS_TEST.C.

20.3 Creating a Privileged Shareable Image (VAX Only)

On VAX systems, you must create dispatch routines that transfer control to the privileged routines in your shareable image. You then put the addresses of these dispatch routines in a privileged library vector (PLV). Section 20.3.1 describes how to create a dispatch routine. Section 20.3.2 describes how to create a PLV.

20.3.1 Creating User-Written Dispatch Routines on VAX Systems

On VAX systems, you must create kernel-mode and executive-mode dispatching routines that transfer control to the routine entry points. You must supply one dispatch routine for all your kernel mode routines and a separate routine for all the executive mode routines. The dispatcher is usually written using the CASE construct, with each routine identified by a code number. Make sure that the identification code you use in the dispatch routine and the code specified in the transfer vector identify the same routine.

The image activator, when it activates a privileged shareable image, obtains the addresses of the dispatch routines from the PLV and stores these addresses at a location known to the system service dispatcher. When a call to a privileged routine is initiated by a CHME or CHMK instruction, the system service dispatcher attempts to match the code number with a system service code. If there is no match, it transfers control to the location where the image activator has stored the address of your dispatch routines.

A dispatch routine must validate the CHMK or CHME operand identification code number, handling any invalid operands. In addition, the dispatching routine must transfer control to the appropriate routine for each identification code if the user-written system service contains functionally separate coding segments. The CASE instruction in VAX MACRO or a computed GOTO-type statement in a high-level language provides a convenient mechanism for determining where to transfer control.

Note

Users of your privileged shareable image must specify the same code number to identify a privileged routine as you used to identify it in the dispatch routine. Users specify the code number in their CHMK or CHME instruction. See Section 20.3.3 for information about transfer vectors.

In your source file, a dispatch routine must precede the routines that implement the user-written system service.

Example 20-1 illustrates a sample dispatching routine, taken from the sample privileged shareable image in SYS$EXAMPLES named USSDISP.MAR.

Example 20-1 Sample Dispatching Routine

KERNEL_DISPATCH::                       ; Entry to dispatcher 
        MOVAB   W^-KCODE_BASE(R0),R1    ; Normalize dispatch code value 
        BLSS    KNOTME                  ; Branch if code value too low 
        CMPW    R1,#KERNEL_COUNTER      ; Check high limit 
        BGEQU   KNOTME                  ; Branch if out of range 
; 
; The dispatch code has now been verified as being handled by this dispatcher, 
; now the argument list will be probed and the required number of arguments 
; verified. 
; 
        MOVZBL  W^KERNEL_NARG[R1],R1    ; Get required argument count 
        MOVAL   @#4[R1],R1              ; Compute byte count including argcount 
        IFNORD  R1,(AP),KACCVIO         ; Branch if arglist not readable 
        CMPB    (AP),W^<KERNEL_NARG-KCODE_BASE>[R0] ; Check for required number 
        BLSSU   KINSFARG                ;  of arguments 
        MOVL    FP,SP                   ; Reset stack for service routine 
        CASEW   R0,-                    ; Case on change mode 
        .
        .
        .

20.3.2 Creating a PLV on VAX Systems

On VAX systems, a call to a privileged routine goes to the transfer vector which executes a change mode instruction (CHMx) specifying the identification code of the privileged routine as the operand to the instruction. The operating system routes the change mode instruction to the system service dispatch routine, which attempts to locate the system service with the code specified. Because the code is a negative number, the system service dispatcher drops through its list of known services and transfers control to a user-written dispatch routine, if any have been specified.

The image activator has already placed at this location the address of whatever user-written dispatch routines it found in the privileged shareable image's PLV when it activated the PLV. The dispatch routine transfers control to the routine in the shareable image identified by the code. (You must ensure that the code used in the transfer vector and the code specified in the dispatch routine both identify the same routine.) Figure 20-1 illustrates this flow of control.

Figure 20-1 Flow of Control Accessing a Privileged Routine on VAX Systems


Figure 20-2 shows the components of the PLV in VAX shareable images.

Figure 20-2 Components of the Privileged Library Vector on VAX Systems


Table 20-1 describes each field in the PLV on a VAX processor, including the symbolic names the operating system defines to access each field. These names are defined by the $PLVDEF macro in SYS$LIBRARY:STARLET.MLB.

Table 20-1 Components of the VAX Privileged Library Vector
Component Symbol Description
Vector type code PLV$L_TYPE Identifies the type of vector. For PLVs, you must specify the symbolic constant defined by the operating system, PLV$C_TYP_CMOD, which identifies a privileged library vector.
Kernel-mode dispatcher PLV$L_KERNEL Contains the address of the user-supplied kernel-mode dispatching routine if your privileged library contains routines that run in kernel mode. The address is expressed as an offset relative to the start of the data structure (self-relative pointer). A value of 0 indicates that a kernel-mode dispatcher does not exist.
Executive-mode dispatcher PLV$L_EXEC Contains the address of the user-supplied executive-mode dispatching routine if your privileged library contains routines that run in executive mode. The address is expressed as an offset relative to the start of the data structure (self-relative pointer). A value of 0 indicates that a kernel-mode dispatcher does not exist.
User-supplied rundown routine PLV$L_USRUNDWN Contains the address of a user-supplied rundown routine that performs image-specific cleanup and resource deallocation if your privileged library contains such a routine. When the image linked against the user-written system service is run down by the system, this run-time routine is invoked. Unlike exit handlers, the routine is always called when a process or image exits. (The image rundown code calls this routine with a JSB instruction; it returns with an RSB instruction called in kernel mode at IPL 0.)
RMS dispatcher PLV$L_RMS Contains the address of a user-supplied dispatcher for OpenVMS RMS services. A value of 0 indicates that a user-supplied OpenVMS RMS dispatcher does not exist. Only one user-written system service should specify the OpenVMS RMS vector, because only the last value is used. This field is intended for use only by Compaq.
Address check PLV$L_CHECK Contains a value to verify that a user-written system service that is not position independent is located at the proper virtual address. If the image is position independent, this field should contain a zero. If the image is not position independent, this field should contain its own address.

Example 20-2 illustrates how the sample privileged shareable image in SYS$EXAMPLES assigns values to the PLV.

Example 20-2 Assigning Values to a PLV on a VAX System

        .PAGE 
        $PLVDEF                         ; Define PLV fields 
        .SBTTL  Change Mode Dispatcher Vector Block 
(1)      .PSECT  USER_SERVICES,PAGE,VEC,PIC,NOWRT,EXE 
 
(2)    .LONG   PLV$C_TYP_CMOD          ; Set type of vector to change mode 
        .LONG   0                       ; Reserved 
        .LONG   KERNEL_DISPATCH-.       ; Offset to kernel mode dispatcher 
        .LONG   EXEC_DISPATCH-.         ; Offset to executive mode dispatcher 
        .LONG   USER_RUNDOWN-.          ; Offset to user rundown service 
        .LONG   0                       ; Reserved. 
        .LONG   0                       ; No RMS dispatcher 
        .LONG   0                       ; Address check - PIC image 


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