|
HP OpenVMS systems documentation |
Previous | Contents | Index |
When you are preparing output strings for a program, you may need to insert variable information into a string prior to output, or you may need to convert a numeric value to an ASCII string. The Formatted ASCII Output (SYS$FAO) system service performs these functions.
Input to the SYS$FAO system service consists of the following:
The following example shows a call to the SYS$FAO system service to format an output string for a SYS$QIOW macro. Complete details on how to use SYS$FAO, with additional examples, are provided in the description of the SYS$FAO system service in the HP OpenVMS System Services Reference Manual.
#include <descrip.h> #include <lib$routines.h> #include <ssdef.h> #include <starlet.h> #include <stdio.h> #include <stsdef.h> main() { unsigned int status, faolen; char faobuf[80]; $DESCRIPTOR(faostr,"FILE !AS DOES NOT EXIST"); (1) $DESCRIPTOR(outbuf, faobuf); (2) $DESCRIPTOR(filespec,"DISK$USER:MYFILE.DAT"); (3) status = SYS$FAO( &faostr, &outlen, &outbuf, &filespec ); (4) if (!$VMS_STATUS_SUCCESS(status)) LIB$SIGNAL(status); . . . status = SYS$QIOW( ...faobuf, outlen, ... ); (5) if (!$VMS_STATUS_SUCCESS(status)) LIB$SIGNAL(status); . . . } |
FILE DISK$USER:MYFILE.DAT DOES NOT EXIST |
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 HP 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); . . . } |
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:
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:
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:
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:
MSG$_sender |
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 . . . |
Previous | Next | Contents | Index |