 |
OpenVMS Programming Concepts Manual
- FAOSTR provides the FAO control string. !AS
is an example of an FAO directive: it requires an input parameter that
specifies the address of a character string descriptor. When SYS$FAO is
called to format this control string, !AS will be substituted with the
string whose descriptor address is specified.
- FAODESC is a character string descriptor for
the output buffer; SYS$FAO writes the string into the buffer, and
writes the length of the final formatted string in the low-order word
of FAOLEN. (A longword is reserved so that it can be used for an input
argument to the SYS$QIOW macro.)
- FILESPEC is a character string descriptor
defining an input string for the FAO directive !AS.
- The call to SYS$FAO specifies the control
string, the output buffer and length fields, and the parameter P1,
which is the address of the string descriptor for the string to be
substituted.
- When SYS$FAO completes successfully,
SYS$QIOW writes the following output string:
FILE DISK$USER:MYFILE.DAT DOES NOT EXIST
|
23.20 Mailboxes
Mailboxes are virtual devices that can be used for communication among
processes. You accomplish actual data transfer by using OpenVMS RMS or
I/O services. When the Create Mailbox and Assign Channel (SYS$CREMBX)
system service creates a mailbox, it also assigns a channel to it for
use by the creating process. Other processes can then assign channels
to the mailbox using either the SYS$CREMBX or SYS$ASSIGN system service.
The SYS$CREMBX system service creates the mailbox. The SYS$CREMBX
system service identifies a mailbox by a user-specified logical name
and assigns it an equivalence name. The equivalence name is a physical
device name in the format MBAn, where n is a unit
number. The equivalence name has the terminal attribute.
When another process assigns a channel to the mailbox with the
SYS$CREMBX or SYS$ASSIGN system service, it can identify the mailbox by
its logical name. The service automatically translates the logical
name. The process can obtain the MBAn name either by
translating the logical name (with the SYS$TRNLNM system service), or
by calling the Get Device/Volume Information (SYS$GETDVI) system
service to obtain the unit number and the physical device name.
On VAX systems, channels assigned to mailboxes can be either
bidirectional or unidirectional. Bidirectional channels (read/write)
allow both SYS$QIO read and SYS$QIO write requests to be issued to the
channel. Unidirectional channels (read-only or write-only) allow only a
read request or a write request to the channel. The unidirectional
channels and unidirectional $QIO function modifiers provide for greater
synchronization between users of the mailbox.
On VAX systems, the Create Mailbox and Assign Channel (SYS$CREMBX) and
Assign I/O Channel (SYS$ASSIGN) system services use the
flags argument to enable unidirectional channels. If
the flags argument is not specified or is zero, then
the channel assigned to the mailbox is bidirectional (read/write). For
more information, see the discussion and programming examples in the
mailbox driver chapter in the OpenVMS I/O User's Reference Manual. Chapter 3 of this
manual also discusses the use of mailboxes.
Mailboxes are either temporary or permanent. You need the user
privileges TMPMBX and PRMMBX to create temporary and permanent
mailboxes, respectively.
For a temporary mailbox, the SYS$CREMBX service enters the logical name
and equivalence name in the logical name table LNM$TEMPORARY_MAILBOX.
This logical name table name usually specifies the LNM$JOB logical name
table name. The system deletes a temporary mailbox when no more
channels are assigned to it.
For a permanent mailbox, the SYS$CREMBX service enters the logical name
and equivalence name in the logical name table LNM$PERMANENT_MAILBOX.
This logical name table name usually specifies the LNM$SYSTEM logical
name table name. Permanent mailboxes continue to exist until they are
specifically marked for deletion with the Delete Mailbox (SYS$DELMBX)
system service.
The following example shows how processes can communicate by means of a
mailbox:
/* Process ORION */
#include <descrip.h>
#include <iodef.h>
#include <lib$routines.h>
#include <ssdef.h>
#include <starlet.h>
#include <stdio.h>
#define MBXBUFSIZ 128
#define MBXBUFQUO 384
/* I/O status block */
struct {
unsigned short iostat, iolen;
unsigned int remainder;
}mbxiosb;
main() {
void *p1, mbxast();
char mbuffer[MBXBUFSIZ], prmflg=0;
unsigned short mbxchan, mbxiosb;
unsigned int status, outlen;
unsigned int mbuflen=MBXBUFSIZ, bufquo=MBXBUFQUO, promsk=0;
$DESCRIPTOR(mblognam,"GROUP100_MAILBOX");
/* Create a mailbox */
status = SYS$CREMBX( prmflg, /* Permanent or temporary */ (1)
&mbxchan, /* chan - channel number */
mbuflen, /* maxmsg - buffer length */
bufquo, /* bufquo - quota */
promsk, /* promsk - protection mask */
0, /* acmode - access mode */
&mblognam, /* lognam - mailbox logical name */
0); /* flags - options */
if (!$VMS_STATUS_SUCCESS(status))
LIB$SIGNAL(status);
.
.
.
/* Request I/O */
status = SYS$QIO(0, /* efn - event flag */ (2)
mbxchan, /* chan - channel number */
IO$_READVBLK, /* func - function modifier */
&mbxiosb, /* iosb - I/O status block */
&mbxast, /* astadr - AST routine */
&mbuffer, /* p1 - output buffer */
mbuflen); /* p2 - length of buffer */
if (!$VMS_STATUS_SUCCESS(status))
LIB$SIGNAL(status);
.
.
.
}
void mbxast(void) { (3)
if (mbxiosb.iostat != SS$_NORMAL)
status = SYS$QIOW(..., &mbuffer, &outlen,...)
if (!$VMS_STATUS_SUCCESS(status))
LIB$SIGNAL(status);
return;
}
/* Process Cygnus */
#include <descrip.h>
#include <iodef.h>
#include <lib$routines.h>
#include <ssdef.h>
#include <starlet.h>
#include <stdio.h>
#include <stsdef.h>
#define MBXBUFSIZ 128
main() {
unsigned short int mailchan;
unsigned int status, outlen;
char outbuf[MBXBUFSIZ];
$DESCRIPTOR(mailbox,"GROUP100_MAILBOX");
status = SYS$ASSIGN(&mailbox, &mailchan, 0, 0, 0); (4)
if (!$VMS_STATUS_SUCCESS(status))
LIB$SIGNAL(status);
.
.
.
status = SYS$QIOW(0, mailchan, 0, 0, 0, 0, &outbuf, outlen, 0, 0, 0, 0)
if (!$VMS_STATUS_SUCCESS(status))
LIB$SIGNAL(status);
.
.
.
}
|
- Process ORION creates the mailbox and
receives the channel number at MBXCHAN.
The prmflg
argument indicates that the mailbox is a temporary mailbox. The logical
name is entered in the LNM$TEMPORARY_MAILBOX logical name table.
The maxmsg argument limits the size of messages
that the mailbox can receive. Note that the size indicated in this
example is the same size as the buffer (MBUFFER) provided for the
SYS$QIO request. A buffer for mailbox I/O must be at least as large as
the size specified in the maxmsg argument. When a
process creates a temporary mailbox, the amount of system memory
allocated for buffering messages is subtracted from the process's
buffer quota. Use the bufquo argument to specify how
much of the process quota should be used for mailbox message buffering.
Mailboxes are protected devices. By specifying a protection mask
with the promsk argument, you can restrict access to
the mailbox. (In this example, all bits in the mask are clear,
indicating unlimited read and write access.)
- After creating the mailbox, process ORION
calls the SYS$QIO system service, requesting that it be notified when
I/O completes (that is, when the mailbox receives a message) by means
of an AST interrupt. The process can continue executing, but the AST
service routine at MBXAST will interrupt and begin executing when a
message is received.
- When a message is sent to the mailbox (by
CYGNUS), the AST is delivered and ORION responds to the message.
Process ORION gets the length of the message from the first word of the
I/O status block at MBXIOSB and places it in the longword OUTLEN so it
can pass the length to SYS$QIOW_S.
- Process CYGNUS assigns a channel to the
mailbox, specifying the logical name the process ORION gave the
mailbox. The SYS$QIOW system service writes a message from the output
buffer provided at OUTBUF.
Note that on a write operation to a
mailbox, the I/O is not complete until the message is read, unless you
specify the IO$M_NOW function modifier. Therefore, if SYS$QIOW (without
the IO$M_NOW function modifier) is used to write the message, the
process will not continue executing until another process reads the
message.
23.20.1 Mailbox Name
The lognam argument to the SYS$CREMBX service
specifies a descriptor that points to a character string for the
mailbox name.
Translation of the lognam argument proceeds as follows:
- The current name string is prefixed with MBX$ and the result is
subject to logical name translation.
- If the result is a logical name, step 1 is repeated until
translation does not succeed or until the number of translations
performed exceeds the number specified by the SYSGEN parameter
LNM$C_MAXDEPTH.
- The MBX$ prefix is stripped from the current name string that could
not be translated. This current string is made a logical name with an
equivalence name MBAn (n is a number assigned by the
system).
For example, assume that you have made the following logical name
assignment:
$ DEFINE MBX$CHKPNT CHKPNT_001
|
Assume also that your program contains the following statements:
$DESCRIPTOR(mbxdesc,"CHKPNT");
.
.
.
status = SYS$CREMBX(...,&mbxdesc,...);
|
The following logical name translation takes place:
- MBX$ is prefixed to CHKPNT.
- MBX$CHKPNT is translated to CHKPNT_001.
Because further translation is unsuccessful, the logical name
CHKPNT_001 is created with the equivalence name MBAn
(n is a number assigned by the system).
There are two exceptions to the logical name translation method
discussed in this section:
- If the name string starts with an underscore (_), the operating
system strips the underscore and considers the resultant string to be
the actual name (that is, further translation is not performed).
- If the name string is the result of a logical name translation,
then the name string is checked to see whether it has the
terminal attribute. If the name string is marked with
the terminal attribute, the operating system considers
the resultant string to be the actual name (that is, further
translation is not performed).
23.20.2 System Mailboxes
The system uses mailboxes for communication among system processes. All
system mailbox messages contain, in the first word of the message, a
constant that identifies the sender of the message. These constants
have symbolic names (defined in the $MSGDEF macro) in the following
format:
The symbolic names included in the $MSGDEF macro and their meanings are
as follows:
Symbolic Name |
Meaning |
MSG$_TRMUNSOLIC
|
Unsolicited terminal data
|
MSG$_CRUNSOLIC
|
Unsolicited card reader data
|
MSG$_ABORT
|
Network partner aborted link
|
MSG$_CONFIRM
|
Network connect confirm
|
MSG$_CONNECT
|
Network inbound connect initiate
|
MSG$_DISCON
|
Network partner disconnected
|
MSG$_EXIT
|
Network partner exited prematurely
|
MSG$_INTMSG
|
Network interrupt message; unsolicited data
|
MSG$_PATHLOST
|
Network path lost to partner
|
MSG$_PROTOCOL
|
Network protocol error
|
MSG$_REJECT
|
Network connect reject
|
MSG$_THIRDPARTY
|
Network third-party disconnect
|
MSG$_TIMEOUT
|
Network connect timeout
|
MSG$_NETSHUT
|
Network shutting down
|
MSG$_NODEACC
|
Node has become accessible
|
MSG$_NODEINACC
|
Node has become inaccessible
|
MSG$_EVTAVL
|
Events available to DECnet Event Logger
|
MSG$_EVTRCVCHG
|
Event receiver database change
|
MSG$_INCDAT
|
Unsolicited incoming data available
|
MSG$_RESET
|
Request to reset the virtual circuit
|
MSG$_LINUP
|
PVC line up
|
MSG$_LINDWN
|
PVC line down
|
MSG$_EVTXMTCHG
|
Event transmitter database change
|
The remainder of the message contains variable information, depending
on the system component that is sending the message.
The format of the variable information for each message type is
documented with the system function that uses the mailbox.
23.20.3 Mailboxes for Process Termination Messages
When a process creates another process, it can specify the unit number
of a mailbox as an argument to the Create Process ($CREPRC) system
service. When you delete the created process, the system sends a
message to the specified termination mailbox.
You cannot use a mailbox in memory shared by multiple processors as a
process termination mailbox.
23.21 Example of Using I/O Services
In the following Fortran example, the first program, SEND.FOR, 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, RECEIVE.FOR, creates a mailbox with the same
logical name, MAIL_BOX. It reads the messages from the mailbox into an
array. It 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. By checking that the I/O status block is nonzero, the second
program confirms that the writing process sent the end-of-file message.
The processes use common event flag number 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.)
SEND.FOR
INTEGER 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
INTEGER*2 IOSTAT,
2 MSG_LEN
INTEGER READER_PID
COMMON /IOBLOCK/ IOSTAT,
2 MSG_LEN,
2 READER_PID
! 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 IOSTAT, ! Status block
2 ,,
2 %REF(MBX_MESSAGE), ! P1
2 %VAL(LEN),,,,) ! P2
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS))
IF (.NOT. IOSTAT) CALL LIB$SIGNAL (%VAL(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 IOSTAT, ! Status block
2 ,,,,,,,)
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS))
IF (.NOT. IOSTAT) CALL LIB$SIGNAL (%VAL(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
INTEGER*2 IOSTAT,
2 MSG_LEN
INTEGER READER_PID
COMMON /IOBLOCK/ IOSTAT,
2 MSG_LEN,
2 READER_PID
! 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 IOSTAT, ! Status block
2 ,,
2 %REF(MBX_MESSAGE), ! P1
2 %VAL(LEN),,,,) ! P2
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS))
IF ((.NOT. IOSTAT) .AND.
2 (IOSTAT .NE. SS$_ENDOFFILE)) THEN
CALL LIB$SIGNAL (%VAL(IOSTAT))
ELSE IF (IOSTAT .NE. SS$_ENDOFFILE) THEN
I = 1
MESSAGES(I) = MBX_MESSAGE
MESSAGE_LEN(I) = MSG_LEN
END IF
! Read messages until cooperating process writes end-of-file
DO WHILE (.NOT. ((IOSTAT .EQ. SS$_ENDOFFILE) .AND.
2 (READER_PID .NE. 0)))
STATUS = SYS$QIOW (,
2 %VAL(MBX_CHAN), ! Channel
2 %VAL(READ_CODE), ! Function code
2 IOSTAT, ! Status block
2 ,,
2 %REF(MBX_MESSAGE), ! P1
2 %VAL(LEN),,,,) ! P2
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS))
IF ((.NOT. IOSTAT) .AND.
2 (IOSTAT .NE. SS$_ENDOFFILE)) THEN
CALL LIB$SIGNAL (%VAL(IOSTAT))
ELSE IF (IOSTAT .NE. SS$_ENDOFFILE) THEN
I = I + 1
MESSAGES(I) = MBX_MESSAGE
MESSAGE_LEN(I) = MSG_LEN
END IF
END DO
.
.
.
|
23.22 Fast I/O and Fast Path Features (Alpha Only)
Fast I/O and Fast Path are two optional features that can provide
improved I/O performance. Performance improvement is achieved by
reducing the CPU cost per I/O request, and improving symmetric
multiprocessing (SMP) scaling of I/O operations. The CPU cost per I/O
is reduced by optimizing code for high-volume I/O and by using better
SMP CPU memory cache. SMP scaling of I/O is increased by reducing the
number of spinlocks taken per I/O and by substituting finer-granularity
spinlocks for global spinlocks.
The improvements follow a division that already exists between the
device-independent and device-dependent layers in the OpenVMS I/O
subsystem. The device-independent overhead is addressed by Fast I/O,
which is a set of system services that can substitute for certain $QIO
operations. Using these services requires some coding changes in
existing applications, but the changes are usually modest and well
contained. The device-dependent overhead is addressed by Fast Path,
which is an optional performance feature that creates a "fast
path" to the device. It requires no application changes.
Fast I/O and Fast Path can be used independently. However, together
they can provide a reduction in CPU cost per I/O on uniprocessor and on
multiprocessor systems.
23.22.1 Fast I/O (Alpha Only)
Fast I/O is a set of three system services, SYS$IO_SETUP,
SYS$IO_PERFORM, and SYS$IO_CLEANUP, that were developed as an
alternative to $QIO. These services are not a $QIO replacement; $QIO is
unchanged, and $QIO interoperation with these services is fully
supported. Rather, the services substitute for a subset of $QIO
operations, namely, only the high-volume read/write I/O requests.
The Fast I/O services support 64-bit addresses for data transfers to
and from disk and tape devices.
While Fast I/O services are available on OpenVMS VAX, the performance
advantage applies only to OpenVMS Alpha. OpenVMS VAX has a run-time
library (RTL) compatibility package that translates the Fast I/O
service requests to $QIO system service requests, so one set of source
code can be used on both VAX and Alpha systems.
|