|
HP OpenVMS systems documentation |
Previous | Contents | Index |
A mailbox is a virtual device used for communication between processes. A channel is the communication path that a process uses to perform I/O operations to a particular device. The LIB$ASN_WTH_MBX routine assigns a channel to a device and associates a mailbox with the device.
Normally, a process calls the SYS$CREMBX system service to create a mailbox and assign a channel and logical name to it. In the case of a temporary mailbox, this service places the logical name corresponding to the mailbox in the job logical name table. This implies that any process running in the same job and using the same logical name uses the same mailbox.
Sometimes it is not desirable to have more than one process use the same mailbox. For example, when a program connects explicitly with another process across a network, the program uses a mailbox both to obtain the data confirming the connection and to store the asynchronous messages from the other process. If that mailbox is shared with other processes in the same group, there is no way to determine which messages are intended for which processes; the processes read each other's messages, and the original program does not receive the correct information from the cooperating process across the network link.
The LIB$ASN_WTH_MBX routine avoids this situation by associating the physical mailbox name with the channel assigned to the device. To create a temporary mailbox for itself and other processes cooperating with it, your program calls LIB$ASN_WTH_MBX. The run-time library routine assigns the channel and creates the temporary mailbox by using the system services $GETDVI, $ASSIGN, and $CREMBX. Instead of a logical name, the mailbox is identified by a physical device name of the form MBcu. The elements that make up this device name are as follows:
MB | indicates that the device is a mailbox. |
c | is the controller. |
u | is the unit number. |
The routine returns this device name to the calling program, which then must pass the mailbox channel to the other programs with which it cooperates. In this way, the cooperating processes access the mailbox by its physical name instead of by its jobwide logical name.
The calling program passes the routine a device name, which specifies the device to which the channel is to be assigned. For this argument (called dev-nam), you can use a logical name. If you do so, the routine attempts one level of logical name translation.
The privilege restrictions and process quotas required for using this
routine are those required by the $GETDVI, $CREMBX, and $ASSIGN system
services.
3.2.2.4 Reading and Writing Data to a Mailbox
The following list describes the three ways you can read and write to a mailbox:
Chapter 23 describes the SYS$QIO and SYS$QIOW system services and
provides further discussion of mailbox I/O. See the HP OpenVMS System Services Reference Manual for
more information. HP recommends that you supply the optional I/O status
block parameter when you use these two system services. The contents of
the status block varies depending on the QIO function code; refer to
the function code descriptions in the HP OpenVMS I/O User's Reference Manual for a description
of the appropriate status block.
3.2.2.5 Using Synchronous Mailbox I/O
Use synchronous I/O when you read or write information to another image and cannot continue until that image responds.
The program segment shown in Example 3-2 opens a mailbox for the first time. To open a mailbox for Fortran I/O, use the OPEN statement with the following specifiers: UNIT, FILE, CARRIAGECONTROL, and STATUS. The value for the keyword FILE should be the logical name of a mailbox (SYS$CREMBX allows you to associate a logical name with a mailbox when the mailbox is created). The value for the keyword CARRIAGECONTROL should be 'LIST'. The value for the keyword STATUS should be 'NEW' for the first OPEN statement and 'OLD' for subsequent OPEN statements.
Example 3-2 Opening a Mailbox |
---|
! Status variable and values INTEGER STATUS ! Logical unit and name for mailbox INTEGER MBX_LUN CHARACTER(*) MBX_NAME PARAMETER (MBX_NAME = MAIL_BOX) ! Create mailbox STATUS = SYS$CREMBX (, 2 MBX_CHAN, ! Channel 2 ,,,, 2 MBX_NAME) ! Logical name IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) ! Get logical unit for mailbox and open mailbox STATUS = LIB$GET_LUN (MBX_LUN) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) OPEN (UNIT = MBX_LUN, 2 FILE = MBX_NAME, 2 CARRIAGECONTROL = 'LIST', 2 STATUS = 'NEW') |
In Example 3-3, one image passes device names to a second image. The second image returns the process name and the terminal associated with the process that allocated each device. A WRITE statement in the first image does not complete until the cooperating process issues a READ statement. (The variable declarations are not shown in the second program because they are very similar to those in the first program.)
Example 3-3 Synchronous I/O Using a Mailbox |
---|
! DEVICE.FOR PROGRAM PROCESS_DEVICE ! Status variable INTEGER STATUS ! Name and I/O channel for mailbox CHARACTER*(*) MBX_NAME PARAMETER (MBX_NAME = 'MAIL_BOX') INTEGER*2 MBX_CHAN ! Logical unit number for FORTRAN I/O INTEGER MBX_LUN ! Character string format CHARACTER*(*) CHAR_FMT PARAMETER (CHAR_FMT = '(A50)') ! Mailbox message CHARACTER*50 MBX_MESSAGE . . . ! Create the mailbox STATUS = SYS$CREMBX (, 2 MBX_CHAN, ! Channel 2 ,,,, 2 MBX_NAME) ! Logical name IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) ! Get logical unit for mailbox and open mailbox STATUS = LIB$GET_LUN (MBX_LUN) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) OPEN (UNIT = MBX_LUN, 2 FILE = MBX_NAME, 2 CARRIAGECONTROL = 'LIST', 2 STATUS = 'NEW') ! Create subprocess to execute GETDEVINF.EXE STATUS = SYS$CREPRC (, 2 'GETDEVINF', ! Image 2 ,,,,, 2 'GET_DEVICE', ! Process name 2 %VAL(4),,,) ! Priority IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) ! Pass device names to GETDEFINF WRITE (UNIT=MBX_LUN, 2 FMT=CHAR_FMT) 'SYS$DRIVE0' ! Read device information from GETDEFINF READ (UNIT=MBX_LUN, 2 FMT=CHAR_FMT) MBX_MESSAGE . . . END |
GETDEVINF.FOR
. . . ! Create mailbox STATUS = SYS$CREMBX (, 2 MBX_CHAN, ! I/O channel 2 ,,,, 2 MBX_NAME) ! Mailbox name IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) ! Get logical unit for mailbox and open mailbox STATUS = LIB$GET_LUN (MBX_LUN) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) OPEN (UNIT=MBX_LUN, 2 FILE=MBX_NAME, 2 CARRIAGECONTROL='LIST', 2 STATUS = 'OLD') ! Read device names from mailbox READ (UNIT=MBX_LUN, 2 FMT=CHAR_FMT) MBX_MESSAGE ! Use SYS$GETJPI to find process and terminal ! Process name: PROC_NAME (1:P_LEN) ! Terminal name: TERM (1:T_LEN) . . . MBX_MESSAGE = MBX_MESSAGE//' '// 2 PROC_NAME(1:P_LEN)//' '// 2 TERM(1:T_LEN) ! Write device information to DEVICE WRITE (UNIT=MBX_LUN, 2 FMT=CHAR_FMT) MBX_MESSAGE END |
Use immediate I/O to send or receive a message from another process without waiting for a response from that process. To ensure that the other process receives the information that you write, either do not exit until the other process has a channel to the mailbox, or use a permanent mailbox.
Queueing an Immmediate I/O Request
To queue an immediate I/O request, invoke the SYS$QIOW system service. See the HP OpenVMS System Services Reference Manual for more information.
Since immediate I/O is asynchronous, a mailbox may contain more than one message or no message when it is read. If the mailbox contains more than one message, the read operation retrieves the messages one at a time in the order in which they were written. If the mailbox contains no message, the read operation generates an end-of-file error.
To allow a cooperating program to differentiate between an empty mailbox and the end of the data being transferred, the process writing the messages should use the IO$_WRITEOF function code to write an end-of-file message to the mailbox as the last piece of data. When the cooperating program reads an empty mailbox, the end-of-file message is returned and the second longword of the I/O status block is 0. When the cooperating program reads an end-of-file message explicitly written to the mailbox, the end-of-file message is returned and the second longword of the I/O status block contains the process identification number of the process that wrote the message to the mailbox.
In Example 3-4, the first program creates a mailbox named MAIL_BOX, writes data to it, and then indicates the end of the data by writing an end-of-file message. The second program creates a mailbox with the same logical name, reads the messages from the mailbox into an array, and stops the read operations when a read operation generates an end-of-file message and the second longword of the I/O status block is nonzero, confirming that the writing process sent the end-of-file message. The processes use common event flag 64 to ensure that SEND.FOR does not exit until RECEIVE.FOR has established a channel to the mailbox. (If RECEIVE.FOR executes first, an error occurs because SYS$ASSIGN cannot find the mailbox.)
Example 3-4 Immediate I/O Using a Mailbox |
---|
!SEND.FOR . . . INTEGER*4 STATUS ! Name and channel number for mailbox CHARACTER*(*) MBX_NAME PARAMETER (MBX_NAME = 'MAIL_BOX') INTEGER*2 MBX_CHAN ! Mailbox message CHARACTER*80 MBX_MESSAGE INTEGER LEN CHARACTER*80 MESSAGES (255) INTEGER MESSAGE_LEN (255) INTEGER MAX_MESSAGE PARAMETER (MAX_MESSAGE = 255) ! I/O function codes and status block INCLUDE '($IODEF)' INTEGER*4 WRITE_CODE STRUCTURE /STATUS_BLOCK/ INTEGER*2 IOSTAT, 2 MSG_LEN INTEGER*4 READER_PID END STRUCTURE RECORD /STATUS_BLOCK/ IOSTATUS ! System routines INTEGER SYS$CREMBX, 2 SYS$ASCEFC, 2 SYS$WAITFR, 2 SYS$QIOW ! Create the mailbox STATUS = SYS$CREMBX (, 2 MBX_CHAN, 2 ,,,, 2 MBX_NAME) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) ! Fill MESSAGES array . . . ! Write the messages DO I = 1, MAX_MESSAGE WRITE_CODE = IO$_WRITEVBLK .OR. IO$M_NOW MBX_MESSAGE = MESSAGES(I) LEN = MESSAGE_LEN(I) STATUS = SYS$QIOW (, 2 %VAL(MBX_CHAN), ! Channel 2 %VAL(WRITE_CODE), ! I/O code 2 IOSTATUS, ! Status block 2 ,, 2 %REF(MBX_MESSAGE), ! P1 2 %VAL(LEN),,,,) ! P2 IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) IF (.NOT. IOSTATUS.IOSTAT) 2 CALL LIB$SIGNAL (%VAL(IOSTATUS.STATUS)) END DO ! Write end-of-file WRITE_CODE = IO$_WRITEOF .OR. IO$M_NOW STATUS = SYS$QIOW (, 2 %VAL(MBX_CHAN), ! Channel 2 %VAL(WRITE_CODE), ! End-of-file code 2 IOSTATUS, ! Status block 2 ,,,,,,,) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) IF (.NOT. IOSTATUS.IOSTAT) 2 CALL LIB$SIGNAL (%VAL(IOSTATUS.IOSTAT)) . . . ! Make sure cooperating process can read the information ! by waiting for it to assign a channel to the mailbox STATUS = SYS$ASCEFC (%VAL(64), 2 'CLUSTER',,) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) STATUS = SYS$WAITFR (%VAL(64)) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) END |
RECEIVE.FOR
INTEGER STATUS INCLUDE '($IODEF)' INCLUDE '($SSDEF)' ! Name and channel number for mailbox CHARACTER*(*) MBX_NAME PARAMETER (MBX_NAME = 'MAIL_BOX') INTEGER*2 MBX_CHAN ! QIO function code INTEGER READ_CODE ! Mailbox message CHARACTER*80 MBX_MESSAGE INTEGER*4 LEN ! Message arrays CHARACTER*80 MESSAGES (255) INTEGER*4 MESSAGE_LEN (255) ! I/O status block STRUCTURE /STATUS_BLOCK/ INTEGER*2 IOSTAT, 2 MSG_LEN INTEGER*4 READER_PID END STRUCTURE RECORD /STATUS_BLOCK/ IOSTATUS ! System routines INTEGER SYS$ASSIGN, 2 SYS$ASCEFC, 2 SYS$SETEF, 2 SYS$QIOW ! Create the mailbox and let the other process know STATUS = SYS$ASSIGN (MBX_NAME, 2 MBX_CHAN,,,) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) STATUS = SYS$ASCEFC (%VAL(64), 2 'CLUSTER',,) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) STATUS = SYS$SETEF (%VAL(64)) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) ! Read first message READ_CODE = IO$_READVBLK .OR. IO$M_NOW LEN = 80 STATUS = SYS$QIOW (, 2 %VAL(MBX_CHAN), ! Channel 2 %VAL(READ_CODE), ! Function code 2 IOSTATUS, ! Status block 2 ,, 2 %REF(MBX_MESSAGE), ! P1 2 %VAL(LEN),,,,) ! P2 IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) IF ((.NOT. IOSTATUS.IOSTAT) .AND. 2 (IOSTATUS.IOSTAT .NE. SS$_ENDOFFILE)) THEN CALL LIB$SIGNAL (%VAL(IOSTATUS.IOSTAT)) ELSE IF (IOSTATUS.IOSTAT .NE. SS$_ENDOFFILE) THEN I = 1 MESSAGES(I) = MBX_MESSAGE MESSAGE_LEN(I) = IOSTATUS.MSG_LEN END IF ! Read messages until cooperating process writes end-of-file DO WHILE (.NOT. ((IOSTATUS.IOSTAT .EQ. SS$_ENDOFFILE) .AND. 2 (IOSTATUS.READER_PID .NE. 0))) STATUS = SYS$QIOW (, 2 %VAL(MBX_CHAN), ! Channel 2 %VAL(READ_CODE), ! Function code 2 IOSTATUS, ! Status block 2 ,, 2 %REF(MBX_MESSAGE), ! P1 2 %VAL(LEN),,,,) ! P2 IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) IF ((.NOT. IOSTATUS.IOSTAT) .AND. 2 (IOSTATUS.IOSTAT .NE. SS$_ENDOFFILE)) THEN CALL LIB$SIGNAL (%VAL(IOSTATUS.IOSTAT)) ELSE IF (IOSTATUS.IOSTAT .NE. SS$_ENDOFFILE) THEN I = I + 1 MESSAGES(I) = MBX_MESSAGE MESSAGE_LEN(I) = IOSTATUS.MSG_LEN END IF END DO . . . |
Use asynchronous I/O to queue a read or write request to a mailbox. To ensure that the other process receives the information you write, either do not exit the other process until the other process has a channel to the mailbox, or use a permanent mailbox.
To queue an asynchronous I/O request, invoke the SYS$QIO system service; however, when specifying the function codes, do not specify the IO$M_NOW modifier. The SYS$QIO system service allows you to specify either an AST to be executed or an event flag to be set when the I/O operation completes.
Example 3-5 calculates gross income and taxes and then uses the results to calculate net income. INCOME.FOR uses SYS$CREPRC, specifying a termination mailbox, to create a subprocess to calculate taxes (CALC_TAXES) while INCOME calculates gross income. INCOME issues an asynchronous read to the termination mailbox, specifying an event flag to be set when the read completes. (The read completes when CALC_TAXES completes, terminating the created process and causing the system to write to the termination mailbox.) After finishing its own gross income calculations, INCOME.FOR waits for the flag that indicates CALC_TAXES has completed and then figures net income.
CALC_TAXES.FOR passes the tax information to INCOME.FOR using the installed common block created from INSTALLED.FOR.
Example 3-5 Asynchronous I/O Using a Mailbox |
---|
!INSTALLED.FOR ! Installed common block to be linked with INCOME.FOR and ! CALC_TAXES.FOR. ! Unless the shareable image created from this file is ! in SYS$SHARE, you must define a group logical name ! INSTALLED and equivalence it to the full file specification ! of the shareable image. INTEGER*4 INCOME (200), 2 TAXES (200), 2 NET (200) COMMON /CALC/ INCOME, 2 TAXES, 2 NET END |
!INCOME.FOR ! Status and system routines . . . INCLUDE '($SSDEF)' INCLUDE '($IODEF)' INTEGER STATUS, 2 LIB$GET_LUN, 2 LIB$GET_EF, 2 SYS$CLREF, 2 SYS$CREMBX, 2 SYS$CREPRC, 2 SYS$GETDVIW, 2 SYS$QIO, 2 SYS$WAITFR ! Set up for SYS$GETDVI ! Define itmlst structure STRUCTURE /ITMLST/ UNION MAP INTEGER*2 BUFLEN INTEGER*2 CODE INTEGER*4 BUFADR INTEGER*4 RETLENADR END MAP MAP INTEGER*4 END_LIST END MAP END UNION END STRUCTURE ! Declare itmlst RECORD /ITMLST/ DVILIST (2) INTEGER*4 UNIT_BUF, 2 UNIT_LEN EXTERNAL DVI$_UNIT ! Name and I/O channel for mailbox CHARACTER*(*) MBX_NAME PARAMETER (MBX_NAME = 'MAIL_BOX') INTEGER*2 MBX_CHAN INTEGER*4 MBX_LUN ! Logical unit number for I/O CHARACTER*84 MBX_MESSAGE ! Mailbox message INTEGER*4 READ_CODE, 2 LENGTH ! I/O status block STRUCTURE /STATUS_BLOCK/ INTEGER*2 IOSTAT, 2 MSG_LEN INTEGER*4 READER_PID END STRUCTURE RECORD /STATUS_BLOCK/ IOSTATUS ! Declare calculation variables in installed common INTEGER*4 INCOME (200), 2 TAXES (200), 2 NET (200) COMMON /CALC/ INCOME, 2 TAXES, 2 NET ! Flag to indicate taxes calculated INTEGER*4 TAX_DONE ! Get and clear an event flag STATUS = LIB$GET_EF (TAX_DONE) IF (.NOT. STATUS) CALL LIB$SIGNAL(%VAL(STATUS)) STATUS = SYS$CLREF (%VAL(TAX_DONE)) IF (.NOT. STATUS) CALL LIB$SIGNAL(%VAL(STATUS)) ! Create the mailbox STATUS = SYS$CREMBX (, 2 MBX_CHAN, 2 ,,,, 2 MBX_NAME) IF (.NOT. STATUS) CALL LIB$SIGNAL(%VAL(STATUS)) ! Get unit number of the mailbox DVILIST(1).BUFLEN = 4 DVILIST(1).CODE = %LOC(DVI$_UNIT) DVILIST(1).BUFADR = %LOC(UNIT_BUF) DVILIST(1).RETLENADR = %LOC(UNIT_LEN) DVILIST(2).END_LIST = 0 STATUS = SYS$GETDVIW (, 2 %VAL(MBX_CHAN), ! Channel 2 MBX_NAME, ! Device 2 DVILIST, ! Item list 2 ,,,) IF (.NOT. STATUS) CALL LIB$SIGNAL(%VAL(STATUS)) ! Create subprocess to calculate taxes STATUS = SYS$CREPRC (, 2 'CALC_TAXES', ! Image 2 ,,,,, 2 'CALC_TAXES', ! Process name 2 %VAL(4), ! Priority 2 , 2 %VAL(UNIT_BUF),) IF (.NOT. STATUS) CALL LIB$SIGNAL(%VAL(STATUS)) ! Asynchronous read to termination mailbox ! sets flag when tax calculations complete READ_CODE = IO$_READVBLK LENGTH = 84 STATUS = SYS$QIO (%VAL(TAX_DONE), ! Indicates read complete 2 %VAL(MBX_CHAN), ! Channel 2 %VAL(READ_CODE), ! Function code 2 IOSTATUS,,, ! Status block 2 %REF(MBX_MESSAGE),! P1 2 %VAL(LENGTH),,,,) ! P2 IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) ! Calculate incomes . . . ! Wait until taxes are calculated STATUS = SYS$WAITFR (%VAL(TAX_DONE)) IF (.NOT. STATUS) CALL LIB$SIGNAL(%VAL(STATUS)) ! Check mailbox I/O IF (.NOT. IOSTATUS.IOSTAT) 2 CALL LIB$SIGNAL (%VAL(IOSTATUS.IOSTAT)) ! Calculate net income after taxes . . . END |
CALC_TAXES.FOR
! Declare calculation variables in installed common INTEGER*4 INCOME (200), 2 TAXES (200), 2 NET (200) COMMON /CALC/ INCOME, 2 TAXES, 2 NET ! Calculate taxes . . . END |
Intracluster communication (ICC), available through ICC system services, forms an application program interface (API) for process-to-process communications. For large data transfers, intracluster communication is the highest performance OpenVMS application communication mechanism, better than standard network transports and mailboxes.
Intracluster communication enables application program developers to create distributed applications with connections between different processes on a single system or between processes on different systems within a single OpenVMS Cluster system. Intracluster communication does not require a network product. It uses memory or System Communication Services (SCS).
The intracluster system services used to implement intracluster communication do the following:
Intracluster system services provide the following benefits when implementing ICC:
The intracluster communication system services are as follows:
See the HP OpenVMS System Services Reference Manual: GETUTC--Z for additional information about the ICC system services.
Previous | Next | Contents | Index |