Kednos PL/I for OpenVMS Systems
User Manual


Previous Contents Index

12.3 Obtaining Definitions for System Global Symbols

Within the OpenVMS system, many global symbol definitions are used and accessed by programs and procedures in many ways. The most common uses are to define symbolic names for the following:

From a PL/I program, you can declare the symbolic names for system global symbols with the GLOBALREF and VALUE attributes. The format of these declarations is as follows:

DECLARE symbol-name GLOBALREF FIXED BINARY(31) VALUE; 

The GLOBALREF attribute indicates to PL/I that the variable is a reference to a global symbol defined in another module. The VALUE attribute indicates that the value of the variable is to be treated as if it were a constant.

The definitions for system global symbols are declared in the default system object module libraries. These libraries are automatically searched when you link a PL/I program. Of particular interest are the global symbols that define symbolic names for system service and file system return status values. Their use is described in Chapter 11.


Chapter 13
Mailboxes

A mailbox is a virtual I/O device that provides a means of communication for images executing in different processes. Mailboxes are used by the operating system to initiate and record system operations; they can also provide communication facilities for user applications.

This chapter provides some general information on using mailboxes, and examples of simple procedures that perform input and output to mailboxes.

Note that this chapter provides only information that is pertinent to mailbox I/O and does not describe mailbox creation. There is a system procedure to create a mailbox, the Create Mailbox and Assign Channel system service (SYS$CREMBX). For an annotated example of a call to this system service, see Chapter 11.

13.1 Using Mailboxes

This section provides information on how the system controls the creation and use of mailboxes, and shows a typical use of mailboxes in an application.

13.1.1 System Information

When a program creates a mailbox, the operating system allocates dynamic memory to store control information about the device and to buffer input and output data. The ability to create mailboxes is controlled by two separate privileges:

In either case, when the system creates a mailbox, it defines a unique device with the name MBn (where n is a unit number) and equates this device name with the logical name specified by the program that created the mailbox.

The logical name of a temporary mailbox is placed in the group logical name table for the group of the creating process. The logical name of a permanent mailbox is placed in the system logical name table.

The process that creates a mailbox can define its protection; that is, it can control which users are allowed to write messages to the mailbox and which users are allowed to read messages from the mailbox.

13.1.2 Applications

A mailbox usually has only one reader and multiple writers. In a typical application, two or more program images would be executed concurrently in separate processes. One program, the controlling program, receives requests or messages from the other cooperating programs by way of the mailbox.

The controlling program takes the following actions:

  1. It creates a temporary mailbox and gives it a logical name.
  2. It associates a PL/I file constant with the mailbox by specifying the mailbox logical name in the TITLE option of an OPEN statement.
  3. It executes a READ statement that initiates a read request.
  4. When the READ statement is completed, it processes the data obtained from the mailbox.
  5. It repeats steps 3 and 4 until no more data is written to the mailbox.
  6. It issues a CLOSE statement to dissociate the file constant and delete the mailbox. The logical name for the mailbox is automatically deassigned when the mailbox is deleted.

Each cooperating program takes the following actions:

  1. It associates a PL/I file constant with the mailbox by specifying the logical name of the mailbox in the TITLE option of an OPEN statement.
  2. It executes WRITE or PUT statements that output data to the mailbox.
  3. It continues to write to the mailbox until it no longer needs to send data or requests.
  4. It executes a CLOSE statement to dissociate the PL/I file from the mailbox.

The following describes a typical application of mailbox communication between processes:

  1. The controlling process creates the mailbox with the logical name PLI_MAILBOX and assigns it device name MBA99.
  2. The controlling process opens the mailbox file with the following statement:


    OPEN FILE (MFILE) INPUT RECORD 
         TITLE('PLI_MAILBOX'); 
    

  3. The controlling process reads and handles information from the mailbox continuously:


    LOOP: READ FILE (MFILE) INTO(M_REC); 
          .
          .
          .
          GOTO LOOP; 
    

The mailbox remains available to other processes until the controlling process deletes the mailbox.

To write to the mailbox, a program does the following:

  1. Opens the mailbox for output:


    OPEN FILE (MAILB) OUTPUT RECORD 
         TITLE('PLI_MAILBOX'); 
    

  2. Writes messages to the mailbox:


    WRITE FILE (MAILB) FROM (M_TEXT); 
    

  3. Closes the file when all messages have been sent:


    CLOSE FILE (MAILB); 
    

All processes writing to the mailbox must specify the TITLE defined by the process that created the mailbox, but it can specify its own file and record names.

13.1.3 Effects of the OPEN Statement

When the TITLE option of an OPEN statement specifies the logical name of a mailbox, the run-time system associates a PL/I file with the mailbox device. The OPEN statement actually assigns an I/O channel to the mailbox; a channel is an I/O path used by the operating system to perform data transfers.

Every OPEN statement executed for the same mailbox assigns another channel to the device. The system counts all channels assigned to a mailbox; therefore, it knows when to delete the mailbox.

13.1.4 Effects of the CLOSE Statement

A CLOSE statement for a mailbox dissociates the PL/I file from the device and deassigns the channel to the device. When the count of channels assigned to a temporary mailbox reaches zero, the system deletes the mailbox and its logical name equivalence, if any. When the count of channels assigned to a permanent mailbox that is marked for deletion reaches zero, the system deletes the permanent mailbox and its logical name equivalence, if any. You must invoke the Delete Mailbox system service (SYS$DELMBX) to mark a permanent mailbox for deletion.

Each time a CLOSE statement is executed for a mailbox, the file system writes an end-of-file to the mailbox. When this end-of-file is encountered during an input operation, the ENDFILE condition is signaled.

Note that in the context of reading a mailbox, an end-of-file does not necessarily mean that there is no more data; it only means that one channel has been deassigned. Thus, a program that is reading a mailbox must take end-of-file records into account and handle the ENDFILE condition accordingly. The manner in which the ENDFILE condition is handled depends on the type of I/O being performed, as described in Section 13.2.

13.2 Mailbox Input/Output

You can use either the stream I/O statements GET and PUT or the record I/O statements READ and WRITE to read from and write to mailboxes. The type of I/O you use depends on your application and the type of data that will be sent.

When you plan an application using mailboxes, you must also determine whether to use synchronous or asynchronous I/O operations. These types of operations are described in the following sections. Each involves special programming considerations.

13.2.1 Synchronous Input/Output

By default, all I/O operations to a mailbox are synchronous. This means that when an image executing in one process performs an output operation to a mailbox, the operation is not completed until an image being executed in another process reads the data from the mailbox. Similarly, when a program requests an input operation from a mailbox, control is not returned until an actual input operation is performed: if there is no data in the mailbox, the process must wait until another process writes data to the mailbox.

Example 13-1 shows a program that reads a mailbox synchronously. This program reads all data sent to a particular mailbox and copies all messages into a central log file. This procedure assumes that the mailbox PLI_MAILBOX already exists. For an example of a procedure that creates this mailbox, see Chapter 11.

The following notes are keyed to Example 13-1:

  1. The procedure LOGGER declares the identifiers MAILFILE and OUTFILE with the FILE attribute.
  2. The structure LOG_MESSAGE depicts the format of messages that are written to the mailbox. By a convention established for the application in this example, all programs in this application write messages with fields of these data types and lengths.
    The first longword in the message is a type code. This is a convention used by OpenVMS system procedures that use mailboxes.
  3. The OPEN statement for the mailbox specifies that it is an input file and that its logical name is PLI_MAILBOX.
  4. LOGGER opens an output log file named MAILTEST.OUT.
  5. This procedure establishes an ENDFILE ON-unit for the mailbox. This ON-unit transfers control to the label LOOP, which is the main input loop of the procedure. This statement ensures that LOGGER will not be accidentally terminated if an ENDFILE condition is signaled when a program executes a CLOSE statement to close the mailbox file.
  6. Each READ statement is followed by a test of the first field in the mailbox record. By application convention, when the value associated with the global symbol END_RUN is written to this field, it indicates that the program is complete. If this field contains any other value, LOGGER writes the record into the log file and loops to read another record.
  7. When the termination value END_RUN is received, control transfers to the label FINISH; LOGGER closes both files and returns.

Example 13-1 Synchronous Mailbox Input/Output

LOGGER: PROCEDURE; 
    DECLARE (MAILFILE,OUTFILE) FILE;    /* (1) */ 
    DECLARE 
        1 LOG_MESSAGE,                        /* (2) */ 
          2 TYPE FIXED BINARY(31), 
          2 SYSTEM_TIME CHARACTER(25), 
          2 REQUESTOR CHARACTER(15), 
          2 STATUS FIXED BINARY(31); 
 
    %REPLACE END_RUN BY -1; 
 
    OPEN FILE(MAILFILE) RECORD INPUT SEQUENTIAL    /* (3) */ 
                TITLE ('PLI_MAILBOX'); 
    OPEN FILE(OUTFILE) PRINT TITLE('MAILTEST.OUT');   /* (4) */ 
 
    ON ENDFILE(MAILFILE) GOTO LOOP; /* Ignore end-of-file */   /* (5) */ 
LOOP: 
    READ FILE(MAILFILE) INTO (LOG_MESSAGE); 
 
    IF LOG_MESSAGE.TYPE = END_RUN     /* (6) */ 
    THEN 
        GOTO FINISH; 
 
    PUT FILE(OUTFILE) SKIP LIST(TYPE, 
                SYSTEM_TIME,REQUESTOR,STATUS); 
    GOTO LOOP; 
FINISH: 
    CLOSE FILE(MAILFILE), FILE(OUTFILE);   /* (7) */ 
 
    END LOGGER; 

13.2.2 Asynchronous Input/Output

It is not always practical for a procedure that is reading a mailbox to wait until the mailbox has been written. To perform an I/O operation that is completed immediately, you must code a call to the Queue I/O Request system service (SYS$QIO). This service permits you to specify I/O functions that are not possible using PL/I statements.

Example 13-2 illustrates a procedure that uses the SYS$QIO system service to perform asynchronous I/O to a mailbox. This procedure, EMPTY_BOX, reads all of the messages in a mailbox. If the mailbox is empty, EMPTY_BOX displays a message to that effect.

The following notes are keyed to Example 13-2:

  1. The system services SYS$ASSIGN, SYS$QIO, and SYS$WAITFR are declared.
  2. The procedure includes $IODEF from PLI$STARLET.TLB, which defines symbol names for the I/O function codes.
  3. The variable MESSAGE is the buffer into which the mailbox messages will be read.
  4. The call to SYS$ASSIGN specifies the logical name of the mailbox, PLI_MAILBOX, and the variable MBXCHAN. SYS$ASSIGN returns the number of the channel.
  5. In the call to SYS$QIO, the procedure specifies an event flag on which to wait for I/O completion and the channel number.
  6. The next argument to SYS$QIO is the function code and its modifier, whose values are added to obtain the correct I/O function. The values of these names have the following meanings:
  7. The I/O status block argument is specified so that the status of the I/O operation can be determined and the length of the message read can be used. The missing arguments in this call are an AST routine address and an AST parameter.
  8. The IO$_READVBLK function code requires the specification of the address of a message buffer and the size of the buffer. These are the last arguments specified in this call to SYS$QIO.
  9. The procedure waits for the I/O to be completed.
  10. EMPTY_BOX checks the status value in the I/O status block. If not successful, and if the unsuccessful status is not SS$_ENDOFFILE, the procedure exits. Otherwise, EMPTY_BOX displays the message and loops back to the beginning of the DO-group. If the status in the I/O status block was SS$_ENDOFFILE, the DO-group is not executed and the program is completed.

Example 13-2 Asynchronous Mailbox Input/Output

EMPTY_BOX: PROCEDURE OPTIONS(MAIN) RETURNS (FIXED BINARY(31)); 
    %INCLUDE LIB$GET_EF; 
    %INCLUDE LIB$FREE_EF; 
    %INCLUDE SYS$ASSIGN;    /* (1) */ 
    %INCLUDE SYS$QIO; 
    %INCLUDE SYS$WAITFR; 
    %INCLUDE $IODEF;        /* (2) */ 
    %INCLUDE $SSDEF; 
    %INCLUDE $STSDEF; 
    DECLARE MBXCHAN FIXED BINARY(15); 
    DECLARE EFN FIXED BIN(31); 
    DECLARE 
        1 IO_STATUS, 
          2 VALUE FIXED (15), 
          2 BYTES_TRANSFERRED FIXED(15), 
          2 NOT_USED FIXED(31), 
        IO_SUCCESS BIT(1) ALIGNED BASED(ADDR(IO_STATUS.VALUE)); 
 
    DECLARE MESSAGE CHARACTER(132);    /* (3) */ 
    STS$VALUE = SYS$ASSIGN('PLI_MAILBOX',MBXCHAN,,);    /* (4) */ 
    IF ^STS$SUCCESS 
    THEN 
        RETURN (STS$VALUE); 
    /* 
     * Get an event flag to use 
     */ 
    STS$VALUE = LIB$GET_EF(EFN); 
    IF ^STS$SUCCESS 
    THEN 
        RETURN (STS$VALUE); 
    /* 
     * Use a DO-loop to read the mailbox; each QIO is followed 
     * by a test of the return status from QIO, then a wait for 
     * the I/O completion. Then the status value in the I/O 
     * status block is checked. If it contains SS$_ENDOFFILE, 
     * return STS$SUCCESS. Otherwise, return error value. 
     */ 
    IO_STATUS.VALUE = 0; 
    DO WHILE(IO_STATUS.VALUE ^= SS$_ENDOFFILE); 
        STS$VALUE = SYS$QIO ( 
                        EFN,                       /* (5) */ 
                        MBXCHAN, 
                        IO$_READVBLK | IO$M_NOW,   /* (6) */ 
                        IO_STATUS,,,               /* (7) */ 
                        MESSAGE,                   /* (8) */ 
                        LENGTH(MESSAGE),,,,); 
        IF ^STS$SUCCESS 
        THEN 
            RETURN(STS$VALUE); 
        STS$VALUE = SYS$WAITFR(EFN);    /* (9) */ 
        IF IO_STATUS.VALUE = SS$_ENDOFFILE 
        THEN DO; 
            PUT SKIP LIST('Mailbox empty');    /* (10) */ 
            RETURN(1); 
            END; 
        IF ^IO_SUCCESS 
        THEN 
            RETURN(IO_STATUS.VALUE); 
        /* 
         *  If successful read, fall through to here 
         */ 
        PUT SKIP LIST(SUBSTR(MESSAGE,1,IO_STATUS.BYTES_TRANSFERRED), 
                'status ',IO_STATUS.VALUE); 
        END; 
 
    /* 
     * Release the event flag 
     */ 
    STS$VALUE = LIB$FREE_EF(EFN); 
    RETURN (STS$VALUE); 
 
    END EMPTY_BOX; 


Previous Next Contents Index