|
HP OpenVMS systems documentation |
Previous | Contents | Index |
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 HP 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 |
PSECT_ATTR = DATA, PAGE |
! 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)) . . . |
! 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 and I64 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 and I64 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 and I64 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.
On Alpha systems, accessing data items less than four bytes slows run-time performance. In this case you might want to consider 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.
26.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 7 for more information about synchronizing access to resources.
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:
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-MMM-yyyy hh:mm:ss.cc |
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) |
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 hh:mm:ss.cc |
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:
Table 27-1 shows time conversion run-time and system service routines.
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.
27.2.1.1 Calculating and Displaying Time with SYS$GETTIM and LIB$SUBX
Example 27-1 calculates differences between the current time and a time input in absolute format, and then displays the result as delta time. If the input time is later than the current time, the difference is a negative value (delta time) and can be displayed directly. If the input time is an earlier time, the difference is a positive value (absolute time) and must be converted to delta time before being displayed. To change an absolute time to a delta time, negate the time array by subtracting it from 0 (specified as an integer array) using the LIB$SUBX routine, which performs subtraction on signed two's complement integers of arbitrary length. For the absolute or delta time format, see Section 27.1.1 and Section 27.1.2.
Example 27-1 Calculating and Displaying the Time |
---|
. . . ! Internal times ! Input time in absolute format, dd-mmm-yyyy hh:mm:ss.ss ! INTEGER*4 CURRENT_TIME (2), 2 PAST_TIME (2), 2 TIME_DIFFERENCE (2), 2 ZERO (2) DATA ZERO /0,0/ ! Formatted times CHARACTER*23 PAST_TIME_F CHARACTER*16 TIME_DIFFERENCE_F ! Status INTEGER*4 STATUS ! Integer functions INTEGER*4 SYS$GETTIM, 2 LIB$GET_INPUT, 2 SYS$BINTIM, 2 LIB$SUBX, 2 SYS$ASCTIM ! Get current time STATUS = SYS$GETTIM (CURRENT_TIME) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Get past time and convert to internal format STATUS = LIB$GET_INPUT (PAST_TIME_F, 2 'Past time (in absolute format): ') IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) STATUS = SYS$BINTIM (PAST_TIME_F, 2 PAST_TIME) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Subtract past time from current time STATUS = LIB$SUBX (CURRENT_TIME, 2 PAST_TIME, 2 TIME_DIFFERENCE) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! If resultant time is in absolute format (positive value means ! most significant bit is not set), convert it to delta time IF (.NOT. (BTEST (TIME_DIFFERENCE(2),31))) THEN STATUS = LIB$SUBX (ZERO, 2 TIME_DIFFERENCE, 2 TIME_DIFFERENCE) END IF ! Format time difference and display STATUS = SYS$ASCTIM (, TIME_DIFFERENCE_F, 2 TIME_DIFFERENCE,) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) TYPE *, 'Time difference = ', TIME_DIFFERENCE_F END |
If you are ignoring the time portion of date/time (that is, working
just at the date level), the LIB$DAY routine might simplify your
calculations. LIB$DAY returns to you the number of days from the base
system date to a given date.
27.2.1.2 Obtaining Absolute Time with SYS$ASCTIM and SYS$BINTIM
The Convert Binary Time to ASCII String (SYS$ASCTIM) system service is the converse of the Convert ASCII String to Binary Time (SYS$BINTIM) system service. You provide the service with the time in the ASCII format shown in Section 27.3.2. The service then converts the string to a time value in 64-bit format. You can use this returned value as input to a timer scheduling service.
When you specify the ASCII string buffer, you can omit any of the fields, and the service uses the current date or time value for the field. Thus, if you want a timer request to be date independent, you could format the input buffer for the SYS$BINTIM service as shown in the following example. The two hyphens that are normally embedded in the date field must be included, and at least one blank must precede the time field.
#include <stdio.h> #include <descrip.h> /* Buffer to receive binary time */ struct { unsigned int buff1, buff2; }binary_noon; main() { unsigned int status; $DESCRIPTOR(ascii_noon,"-- 12:00:00.00"); /* noon (absolute time) */ /* Convert time */ status = SYS$BINTIM(&ascii_noon, /* timbuf - ASCII time */ &binary_noon); /* timadr - binary time */ } |
When the SYS$BINTIM service completes, a 64-bit time value representing "noon today" is returned in the quadword at BINARY_NOON.
Previous | Next | Contents | Index |