![Content starts here](http://welcome.hp-ww.com/img/s.gif) |
OpenVMS Programming Concepts Manual
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:
- 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
|
- 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.
- 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:
- Include the same variable and common block definitions in the
program.
- 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.
- 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
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:
The source line containing the !DEC$ PSECT directive would be as
follows:
!DEC$ PSECT /INC_COMMON/ SHR
|
- 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
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.
Chapter 27 System Time Operations
This chapter describes the types of system time operations performed by
the operating system and contains the following sections:
Section 27.1 describes the system time format.
Section 27.2 describes time conversion and date/time manipulation.
Section 27.3 describes how to get the current date and time and set
the current time.
Section 27.4 describes how to set and cancel timer requests and how to
schedule and cancel wakeups.
Section 27.5 describes using run-time library (RTL) routines to
collect timer statistics.
Section 27.6 describes using date/time formatting routines.
Section 27.7 describes the Coordinated Universal Time (UTC) system.
27.1 System Time Format
The operating system maintains the current date and time in 64-bit
format. The time value is a binary number in 100-nanosecond (ns) units
offset from the system base date and time, which is 00:00 o'clock,
November 17, 1858 (the Smithsonian base date and time for the
astronomic calendar). Time values must be passed to or returned from
system services as the address of a quadword containing the time in
64-bit format. A time value can be expressed as either of the following:
- An absolute time that is a specific date or time of day, or both.
Absolute times are always positive values (or 0).
- A delta time that is an offset from the current time to a time or
date in the future. Delta times are always expressed as negative values
and cannot be zero. The binary format number for delta time will always
be negative.
If you specify 0 as the address of a time value, the operating system
supplies the current date and time.
27.1.1 Absolute Time Format
The operating system uses the following format for absolute time. The
full date and time require a character string of 23 characters. The
punctuation is required.
dd
|
Day of the month (2 characters)
|
MMM
|
Month (first 3 characters of the month in uppercase)
|
yyyy
|
Year (4 characters)
|
hh
|
Hours of the day in 24-hour format (2 characters)
|
mm
|
Minutes (2 characters)
|
ss.cc
|
Seconds and hundredths of a second (5 characters)
|
27.1.2 Delta Time Format
The operating system uses the following format for delta time. The full
date and time require a character string of 16 characters. The
punctuation is required.
dddd
|
Day of the month (4 characters)
|
hh
|
Hour of the day (2 characters)
|
mm
|
Minutes (2 characters)
|
ss.cc
|
Seconds and hundredths of a second (5 characters)
|
A delta time is maintained as an integer value representing an amount
of time in 100-ns units.
27.2 Time Conversion and Date/Time Manipulation
This section presents information about time conversion and date/time
manipulation features, and the routines available to implement them.
27.2.1 Time Conversion Routines
Since the timer system services require you to specify the time in a
64-bit format, you can use time conversion run-time library and system
service routines to work with time in a different format. Run-time
library and system services do the following:
- Obtain the current date and time in an ASCII string or in system
format
- Convert an ASCII string into the system time format
- Convert a system time value into an ASCII string
- Convert the time from system format to integer values
Table 27-1 shows time conversion run-time and system service
routines.
Table 27-1 Time Conversion Routines and System Services
Routine |
Function |
Time Conversion Run-Time Library (LIB$) Routines |
LIB$CONVERT_DATE_STRING
|
Converts an input date/time string to an operating system internal time.
|
LIB$CVT_FROM_INTERNAL_TIME
|
Converts an operating system standard internal binary time value to an
external integer value. The value is converted according to a selected
unit of time operation.
|
LIB$CVTF_FROM_INTERNAL_TIME
|
Converts an operating system standard internal binary time to an
external F-floating point value. The value is converted according to a
selected unit of time operation.
|
LIB$CVT_TO_INTERNAL_TIME
|
Converts an external integer time value to an operating system standard
internal binary time value. The value is converted according to a
selected unit of time operation.
|
LIB$CVTF_TO_INTERNAL_TIME
|
Converts an F-floating-point time value to an internal binary time
value.
|
LIB$CVT_VECTIM
|
Converts a seven-word array (as returned by the SYS$NUMTIM system
service) to an operating system standard format internal time.
|
LIB$FORMAT_DATE_TIME
|
Allows you to select at run time a specific output language and format
for a date or time, or both.
|
LIB$SYS_ASCTIM
|
Provides a simplified interface between higher-level languages and the
$ASCTIM system service.
|
Time Conversion System Service Routines |
SYS$ASCTIM
|
Converts an absolute or delta time from 64-bit binary time format to an
ASCII string.
|
SYS$ASCUTC
|
Converts an absolute time from 128-bit Coordinated Universal Time (UTC)
format to an ASCII string.
|
SYS$BINTIM
|
Converts an ASCII string to an absolute or delta time value in a binary
time format.
|
SYS$BINUTC
|
Converts an ASCII string to an absolute time value in the 128-bit UTC
format.
|
SYS$FAO
|
Converts a binary value into an ASCII character string in decimal,
hexadecimal, or octal notation and returns the character string in an
output string.
|
SYS$GETUTC
|
Returns the current time in 128-bit UTC format.
|
SYS$NUMTIM
|
Converts an absolute or delta time from 64-bit system time format to
binary integer date and time values.
|
SYS$NUMUTC
|
Converts an absolute 128-bit binary time into its numeric components.
The numeric components are returned in local time.
|
SYS$TIMCON
|
Converts 128-bit UTC to 64-bit system format or 64-bit system format to
128-bit UTC based on the value of the convert flag.
|
You can use the SYS$GETTIM system service to get the current time in
internal format, or you can use SYS$BINTIM to convert a formatted time
to an internal time, as shown in Section 27.3.2. You can also use the
LIB$DATE_TIME routine to obtain the time, LIB$CVT_FROM_INTERNAL_TIME to
convert an internal time to an external time, and LIB$CVT_TO_INTERNAL
to convert from an external time to an internal time.
|