Document revision date: 30 March 2001 | |
Previous | Contents | Index |
Set attention AST functions specify that an asynchronous system trap (AST) be delivered to the requesting process in the following cases:
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:
These function codes take the following device- or function-dependent arguments:
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:
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:
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
This section contains the following programming examples:
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:
Example 4-3 is a writer to the mailbox. It performs the following functions:
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 |