Document revision date: 30 March 2001

## OpenVMS I/O User's Reference Manual

Previous | Contents | Index

### 4.3.4 Set Attention AST

Set attention AST functions specify that an asynchronous system trap (AST) be delivered to the requesting process in the following cases:

- When a cooperating process places a read request for which no write request is pending in a designated mailbox. This is called an unsolicited read request.
- When a cooperating process places a write request for which no read request is pending in a designated mailbox. This is called an unsolicited write request.
- When room becomes available in the mailbox.

If a message exists in the mailbox when a request to enable a write attention AST is issued, the AST routine is activated immediately. If no message exists, the AST is delivered when a write request message arrives. Therefore, the requesting process need not repeatedly check the mailbox status. You must have both logical I/O and read access to the mailbox prior to performing a set attention AST function.

The operating system provides the following function codes:

- IO$_SETMODE!IO$M_READATTN---Read attention AST
- IO$_SETMODE!IO$M_WRTATTN---Write attention AST
- IO$_SETMODE!IO$M_MB_ROOM_NOTIFY---Room in the mailbox attention AST

These function codes take the following device- or function-dependent arguments:

- P1---AST address (request notification is disabled if the address is 0)
- P2---AST parameter returned in the argument list when the AST service routine is called
- P3---Access mode to deliver AST; maximized with requester's mode

These functions are enabled only once; they must be explicitly reenabled after the AST has been delivered if you desire repeat notification. All types of enable functions, and more than one of each type, can be set at the same time. The number of enable functions is limited only by the AST quota for the process.

Figure 4-5 shows the write attention AST function. In this figure, an AST is set to notify Process A when Process B sends an unsolicited message.

Figure 4-5 Write Attention AST (Read Unsolicited Data)

Process A uses the IO$_SETMODE!IO$M_WRTATTN function to request an AST. When Process B sends a message to the mailbox, the AST is delivered to Process A. Process A responds to the AST by issuing a read request to the mailbox. The data is then transferred to complete the I/O operation.

If several requesting processes have set ASTs for unsolicited messages at the same mailbox, all ASTs are delivered when the first unsolicited message is placed in the mailbox. However, only the first process to respond to the AST with a read request receives the data. Therefore, when the next process to respond to an AST issues a read request to the mailbox, it might find the mailbox empty. If this request does not include the function modifier IO$M_NOW, it is queued before the next message arrives in the mailbox.

Figure 4-6 shows the read attention AST function. In this figure, an AST is set to notify Process A when Process B issues a read request for which no message is available.

Figure 4-6 Read Attention AST

Process A uses the IO$_SETMODE!IO$M_READATTN function to specify an AST. When Process B issues a read request to the mailbox, the AST is delivered to Process A. Process A responds to the AST by sending a message to the mailbox. The data is then transferred to complete the I/O operation.

If several requesting processes set ASTs for read requests for the same mailbox, all ASTs are delivered when the first read request is placed in the mailbox. Only the first process to respond with a write request is able to transfer data to Process B.

### 4.3.5 Wait for Writer/Reader

The wait for writer/reader mailbox driver function waits until a channel is assigned to the mailbox with the requested access direction. This function returns immediately if a channel is already assigned to the mailbox with the proper access direction. This function always returns immediately if issued on a bidirectional mailbox channel. Any channel assigned bidirectionally to the mailbox satisfies both types of wait requests.

The wait function requires the same synchronization techniques as all other $QIO functions. $QIO Wait should not be issued without any synchronization of its completion. If no synchronization is performed, the program behaves as if no $QIO Wait function had been issued (except for the small delay caused by issuing the $QIO Wait).

The following function codes and modifiers are provided:

- IO$_SETMODE!IO$M_READERWAIT---Waits for a read channel to be assigned to the mailbox.
- IO$_SETMODE!IO$M_WRITERWAIT---Waits for a write channel to be assigned to the mailbox.

These function codes require no function-dependent arguments.

These functions are enabled only once. Once the $QIO operation completes, these functions must be explicitly reenabled.

### 4.3.6 Set Protection

On VAX and Alpha systems, the set protection functions allow the user to set volume protection on a mailbox (see Section 4.1.4). The requester must either be the owner of the mailbox or have BYPASS privilege. The OpenVMS operating system provides the following function code:

> IO$_SETMODE!IO$M_SETPROT---Set protection

This function code takes the following device- or function-dependent argument:

> P2---A volume protection mask

The protection mask specified by P2 is a 16-bit mask with 4 bits for each class of owner: SYSTEM, OWNER, GROUP, and WORLD, as shown in Figure 4-7.

Figure 4-7 Protection Mask

Only logical I/O, read, and write functions have meaning for mailboxes. A clear (0) bit implies that access is allowed. If P2 is 0 or unspecified, the mask is set to allow all read, write, and logical operations.

The I/O status block for the set protection function (see Figure 4-10) returns SS$_NORMAL in the first word if the request was successful. If the request was not successful, the $QIO system service returns SS$_NOPRIV and both longwords of the I/O status block are returned as zeros.

### 4.3.7 Get Mailbox Information

The get mailbox information function allows the user to find out the number of unread messages and bytes in the mailbox. The following function code is provided:

> IO$_SENSEMODE---Get mailbox contents information

The following function codes and modifiers are provided:

- IO$_SENSEMODE!IO$M_READERCHECK---If a $QIO SENSEMODE with IO$M_READERCHECK is issued and no read channels are assigned to the mailbox, then the SS$_NOREADER condition value is returned in the IOSB.
- IO$_SENSEMODE!IO$M_WRITERCHECK---If a $QIO SENSEMODE with IO$M_WRITERCHECK is issued and no write channels are assigned to the mailbox, then the SS$_NOWRITER condition value is returned in the IOSB.

These function codes require no function-dependent arguments.

## 4.4 I/O Status Block

On VAX and Alpha systems, the I/O status blocks (IOSB) for mailbox read, write, set protection, and get mailbox information QIO functions are shown in Figures 4_8, 4_9, 4-10, and 4-11.

Appendix A lists the I/O status returns for these functions. In addition to the IOSB return values, the following statuses can be returned in R0 by the call to the system service:

> SS$_ACCVIO
> SS$_EXQUOTA
> SS$_ILLIOFUNC
> SS$_INSFMEM
> SS$_MBFULL
> SS$_MBTOOSML
> SS$_NOPRIV
> SS$_NORMAL

(The OpenVMS system messages documentation provides explanations and suggested user actions for both types of returns.)

Figure 4-8 IOSB Contents---Read Function

Figure 4-9 IOSB Contents---Write Function

Figure 4-10 IOSB Contents---Set Protection Function

Figure 4-11 IOSB Contents---Get Mailbox Information Function

## 4.5 Mailbox Driver Programming Examples

This section contains the following programming examples:

- Example 4-1 shows a MACRO32 program that creates a mailbox and puts mail into it.
- Example 4-2 assigns a read-only channel to the mailbox.
- Example 4-3 assigns a write-only channel to the mailbox.

Example 4-1 creates a mailbox and puts mail into it; no matching read is pending on the mailbox. First, the program shows that if the function modifier IO$M_NOW is not used when mail is deposited, the write function waits until a read operation is performed. In this case, IO$M_NOW is specified and the program continues after the mail is left in the mailbox.

Next, the mailbox is read. If there is no mail in the mailbox, the program waits because IO$M_NOW is not specified. IO$M_NOW should be specified if there is any doubt about the availability of data in the mailbox, and it is important for the program not to wait.

It is up to the user to coordinate the data that goes into and out of mailboxes. In this example, the process reads its own message. Normally, two mailboxes are used for interprocess communication: one for sending data from process A to process B, and one for sending data from process B to process A. If a program is arranged in this manner, there is no possibility of a process reading its own message.

Example 4_2 and Example 4-3 work together from two separate processes and show the unidirectional mailbox synchronization features. Note that these examples require the /STANDARD=VAXC qualifier when compiled on Alpha systems.

Example 4-2 performs the following functions:

1. Assigns a read-only channel to the mailbox.
2. Waits for another program to assign a writable channel to the mailbox.
3. Reads, using the IO$M_WRITERCHECK function modifier, what has been written to the mailbox.
4. When SS$_NOWRITER is returned from the read operation, goes back to Step 2 and waits for another writer.

Example 4-3 is a writer to the mailbox. It performs the following functions:

1. Assigns a write-only channel to the mailbox.
2. Waits for a reader.
3. Gathers user input until the user enters Ctrl/Z, then writes that input to the mailbox.

Example 4-1 Mailbox Driver Program Example 1

    ; *********************************************************************
    ;

            .TITLE  MAILBOX DRIVER PROGRAM EXAMPLE
            .IDENT  /01/

    ;
    ; Define necessary symbols.
    ;

            $IODEF                          ;Define I/O function codes

    ;
    ; Allocate storage for necessary data structures.
    ;

    ;
    ; Allocate output device name string and descriptor.
    ;

    DEVICE_DESCR:                           ;
            .LONG   20$-10$                 ;Length of name string
            .LONG   10$                     ;Address of name string
    10$:    .ASCII  /SYS$OUTPUT/            ;Name string of output device
    20$:                                    ;Reference label

    ;
    ; Allocate space to store assigned channel number.
    ;

    DEVICE_CHANNEL:                         ;
            .BLKW   1                       ;Channel number

    ;
    ; Allocate mailbox name string and descriptor.
    ;

    MAILBOX_NAME:                           ;
            .LONG   ENDBOX-NAMEBOX          ;Length of name string
            .LONG   NAMEBOX                 ;Address of name string
    NAMEBOX: .ASCII /146_MAIN_ST/           ;Name string
    ENDBOX:                                 ;Reference label

    ;
    ; Allocate space to store assigned channel number.
    ;

    MAILBOX_CHANNEL:                        ;
            .BLKW   1                       ;Channel number

    ;
    ; Allocate space to store the outgoing and incoming messages.
    ;

    IN_BOX_BUFFER:                          ;
            .BLKB   40                      ;Allocate 40 bytes for
                                            ;received message
            IN_LENGTH=.-IN_BOX_BUFFER       ;Define input buffer length

    OUT_BOX_BUFFER:                         ;
            .ASCII  /SHEEP ARE VERY DIM/    ;Message to send
            OUT_LENGTH=.-OUT_BOX_BUFFER     ;Define length of message to
                                            ;send

    ;
    ; Finally, allocate space for the I/O status quadword.
    ;

    STATUS:                                 ;
            .QUAD   1                       ;I/O status quadword
    ;
    ; *********************************************************************
    ;
    ;                      Start Program
    ;
    ; *********************************************************************
    ;

    ;
    ; The program first creates a mailbox and assigns a channel to the
    ; process output device.  Then a message is placed in the mailbox and
    ; a message is received from the mailbox (the same message).  Finally,
    ; the program prints the contents of the mailbox on the process output
    ; device.
    ;

    START:  .WORD   0                       ;Entry mask
            $CREMBX_S CHAN=MAILBOX_CHANNEL,- ;Channel is the mailbox
                    PROMSK=#^X0000,-        ;No protection
                    BUFQUO=#^X0060,-        ;Buffer quota is hex 60
                    LOGNAM=MAILBOX_NAME,-   ;Logical name descriptor
                    MAXMSG=#^X0060          ;Maximum message is hex 60
            CMPW    #SS$_NORMAL,R0          ;Successful mailbox creation?
            BSBW    ERROR_CHECK             ;Find out
            $ASSIGN_S -                     ;Assign channel
                    DEVNAM=DEVICE_DESCR,-   ;Device descriptor
                    CHAN=DEVICE_CHANNEL     ;Channel
            CMPW    #SS$_NORMAL,R0          ;Successful channel assign?
            BSBW    ERROR_CHECK             ;Find out

    ;
    ; The program now writes to the mailbox using a write request that
    ; includes the function modifier IO$M_NOW so that it need not wait for
    ; a read request to the mailbox before continuing to the next step in
    ; the program.
    ;

            $QIOW_S FUNC=#IO$_WRITEVBLK!IO$M_NOW,- ;Write message NOW
                    CHAN=MAILBOX_CHANNEL,-  ;to the mailbox channel
                    P1=OUT_BOX_BUFFER,-     ;Write buffer
                    P2=#OUT_LENGTH          ;Buffer length
            CMPW    #SS$_NORMAL,R0          ;Successful write request?
            BSBW    ERROR_CHECK             ;Find out

    ;
    ; Read the mailbox.
    ;

            $QIOW_S FUNC=#IO$_READVBLK,-    ;Read the message
                    CHAN=MAILBOX_CHANNEL,-  ;in the mailbox channel
                    IOSB=STATUS,-           ;Define status block to
                    -                       ;receive message length
                    P1=IN_BOX_BUFFER,-      ;Read buffer
                    P2=#IN_LENGTH           ;Buffer length
            CMPW    #SS$_NORMAL,R0          ;Successful read request?
            BSBW    ERROR_CHECK             ;Find out

    ;
    ; The program now determines how much mail is in the mailbox (this
    ; information is in STATUS+2) and then prints the mailbox message on
    ; the process output device.
    ;

            MOVZWL  STATUS+2,R2             ;Byte count into R2
            $QIOW_S FUNC=#IO$_WRITEVBLK,-   ;Write function to the
                    CHAN=DEVICE_CHANNEL,-   ;output device channel
                    P1=IN_BOX_BUFFER,-      ;Address of buffer to write
                    P2=R2,-                 ;How much to write
                    P4=#32                  ;Carriage control
    ;
    ; Finally, deassign the channel and exit.
    ;

    EXIT:   $DASSGN_S CHAN=DEVICE_CHANNEL   ;Deassign channel
            RET                             ;Return

    ;
    ; This is the error checking part of the program.  Normally, some kind
    ; of error recovery would be attempted at this point if an error was
    ; detected.  However, this example program simply exits.
    ;

    ERROR_CHECK:                            ;
            BNEQ    EXIT                    ;System service failure, exit
            RSB                             ;Otherwise, return

            .END    START

Example 4-2 assigns a read-only channel to the mailbox.

Example 4-2 Mailbox Driver Program Example 2

    /*
     * C program to demonstrate the new features of the Mailbox driver
     * This program is a Mailbox READER.  It assigns a READ_ONLY channel to the
     * mailbox.  It's partner program is a Mailbox WRITER.
     */

    #include "sys$library:descrip"          /* Descriptor structure definitions  */
    #include "sys$library:libdef"           /* LIB RTL symbol definitions        */
    #include "sys$library:stdio"            /* Standard C symbol definitions     */
    #include "decc$library:[include]ssdef"  /* System Service status code def'ns */
    #include "decc$library:[include]cmbdef" /* CREMBX definitions                */
    #include "decc$library:[include]agndef" /* ASSIGN definitions                */
    #include "decc$library:[include]iodef"  /* I/O definitions                   */

    #define $ARRAY_DESCRIPTOR(name,size,array_name)                    \
        char array_name[ size ];                                       \
        struct dsc$descriptor_s name =                                 \
           { size, DSC$K_DTYPE_T, DSC$K_CLASS_S, array_name }

    main()

    {
    # define max_msg_len 256
    $DESCRIPTOR(mailbox_name_desc,"MAILBOX_EXAMPLE");
    $ARRAY_DESCRIPTOR(read_buffer_desc,max_msg_len,read_buffer);
    int status, mailbox_channel;
    int true=1, false = 0;
    struct io_status_block {                        /*  I/O status block */
        short int condition;
        short int count;
        int dev;
        } iosb;

    /*
     * Create a permanent mailbox with a READONLY channel.  It's logical name
     *  will be entered into the LNM$PERMANENT_MAILBOX logical name table.
     */

        SYS$CREMBX(1,&mailbox_channel,0,0,0,0,&mailbox_name_desc,CMB$M_READONLY);

    /*
     * Mark it for deletion
     */
        SYS$DELMBX(mailbox_channel);

    /*
     * Loop forever, first waiting til a WRITE channel is assigned to the mailbox
     * and then reading data from it until the WRITER deassigns.
     */
        while (TRUE)
        {
           /* First, check to see if there is a WRITER assigned to the mailbox */
            status = SYS$QIOW (
                0,
                mailbox_channel,
                IO$_SENSEMODE|IO$M_WRITERCHECK,
                &iosb,
                0,0,
                0,0,0,0,0,0);

            /* If there was no WRITER, then wait for one.*/
            if (iosb.condition == SS$_NOWRITER)
            status = SYS$QIOW (
                0,
                mailbox_channel,
                IO$_SETMODE|IO$M_WRITERWAIT,
                &iosb,
                0,0,
                0,0,0,0,0,0);

            /*
             * While the status is good, READ from the mailbox, and write it to
             */
            while (status == SS$_NORMAL)
            {
                status = SYS$QIOW(
                    0,
                    mailbox_channel,
                    IO$_READVBLK|IO$M_WRITERCHECK,
                    &iosb,
                    0,0,
                    read_buffer_desc.dsc$a_pointer,max_msg_len,
                    0,0,0,0);
                status=iosb.condition;
                read_buffer_desc.dsc$w_length = iosb.count;
                lib$put_output(&read_buffer_desc);
            }
        }
    }

Example 4-3 assigns a write-only channel to the mailbox.

Example 4-3 Mailbox Driver Program Example 3

    /*
     * C program to demonstrate the new features of the Mailbox driver
     * This program is a Mailbox WRITER.  It assigns a WRITE_ONLY channel to the
     * mailbox.  It's partner program is a Mailbox READER.
     */

    #include "sys$library:descrip"          /* Descriptor structure definitions  */
    #include "sys$library:libdef"           /* LIB RTL symbol definitions        */
    #include "sys$library:rmsdef"           /* RMS status code def'ns            */
    #include "sys$library:stdio"            /* Standard C symbol definitions     */
    #include "decc$library:[include]ssdef"  /* System Service status code def'ns */
    #include "decc$library:[include]cmbdef" /* CREMBX definitions                */
    #include "decc$library:[include]agndef" /* ASSIGN definitions                */
    #include "decc$library:[include]iodef"  /* I/O definitions                   */

    #define $ARRAY_DESCRIPTOR(name,size,array_name)                    \
        char array_name[ size ];                                       \
        struct dsc$descriptor_s name =                                 \
           { size, DSC$K_DTYPE_T, DSC$K_CLASS_S, array_name }

    main()
    {
    #define max_msg_len 256
    $DESCRIPTOR(mailbox_name_desc,"MAILBOX_EXAMPLE");
    $DESCRIPTOR(prompt_string_desc,"DATA TO SEND TO MAILBOX
        (<CTRL Z> to terminate) >>>");
    $ARRAY_DESCRIPTOR(write_buffer_desc,max_msg_len,write_buffer);
    int status, mailbox_channel, wait_efn;
    int true=1, false = 0;
    int MORE_ROOM_AST();
    struct io_status_block {                              /*  I/O status block */
        short int condition;
        short int count;
        int dev;
        } iosb;

    /*
     * Create a permanent mailbox with a WRITEONLY channel.  It's logical name
     *  will be entered into the LNM$PERMANENT_MAILBOX logical name table.
     */

        SYS$CREMBX(1,&mailbox_channel,0,0,0,0,&mailbox_name_desc,CMB$M_WRITEONLY);

    /*
     * Mark it for deletion
     */
        SYS$DELMBX(mailbox_channel);

    /*
     * Loop forever, first waiting til a READ channel is assigned to the mailbox
     * and then write data until there is no more data to write.
     */
        while (TRUE)
        {
            /*
             * Wait for a READER to assign a channel.  If a READER is already
             * assigned, this will return immediatly.
             */
            status = SYS$QIOW (
                0,
                mailbox_channel,
                IO$_SETMODE|IO$M_READERWAIT,
                &iosb,
                0,0,
                0,0,0,0,0,0);
            while (status)
            {
                write_buffer_desc.dsc$w_length = max_msg_len;
                status = lib$get_input(
                    &write_buffer_desc,
                    &prompt_string_desc,
                    &write_buffer_desc.dsc$w_length);
                /*
                 * If at end of file (user typed <CTRL Z>)
                 * then stop here.
                 */
                if (status == RMS$_EOF) SYS$EXIT(SS$_NORMAL);

                /* Keep trying to write the message, until it fits in the mailbox
                 * Note that if the NORSWAIT function modifier had been eliminated
                 * below, then the ROOM_NOTIFY and the retry loop could have been
                 * removed.  ROOM_NOTIFY was used in this example simply to show
                 * its' use. It would be more appropriately used when the program
                 * has other things it can be working on, as opposed to the
                 * example below in which the program is not doing anything except
                 * WAITING for room in the mailbox.
                 */
                status = SS$_NOREADER;                /* Force attempt to WRITE */
                while (status != SS$_NORMAL)
                    {
                    status = SYS$QIOW(
                        0,
                        mailbox_channel,
                        IO$_WRITEVBLK|IO$M_READERCHECK|IO$M_NORSWAIT,
                        &iosb,
                        0,0,
                        write_buffer_desc.dsc$a_pointer, write_buffer_desc.dsc$w_length,
                        0,0,0,0);
                    if (iosb.condition == SS$_NOREADER) SYS$EXIT(SS$_NOREADER);
                    if (status == SS$_MBFULL)
                    {
                        LIB$GET_EF(&wait_efn);
                        SYS$CLREF(wait_efn);
                        SYS$QIOW (
                            0,
                            mailbox_channel,
                            IO$_SETMODE|IO$M_MB_ROOM_NOTIFY,
                            &iosb,
                            0,0,
                            MORE_ROOM_AST,wait_efn,0,0,0,0);
                            SYS$WAITFR(wait_efn);
                    }
                }
            }
        }
    }

    MORE_ROOM_AST(efn_to_set)
    int efn_to_set;
    {
        SYS$SETEF(efn_to_set);
    }

Previous | Next | Contents | Index

| privacy and legal statement |
6136PRO_014.HTML