/*
* MAILBOX_WRITER.C
* C program to demonstrate 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.
* Compile with Compaq C on VAX or Alpha systems:
* $ CC MAILBOX_WRITER
* $ LINK MAILBOX_WRITER
*/
#include <stdio.h> /* Standard C I/O */
#include <descrip.h> /* Descriptor structure definitions */
#include <lib$routines.h> /* LIB$ RTL function definitions */
#include <rmsdef.h> /* RMS status code definitions */
#include <starlet.h> /* System service definitions */
#include <ssdef.h> /* System Service status code definitions */
#include <cmbdef.h> /* CREMBX definitions */
#include <efndef.h> /* Event Flag definitions */
#include <iodef.h> /* I/O definitions */
#define $ARRAY_DESCRIPTOR(name,size,array_name) \
static char array_name[ size ]; \
struct dsc$descriptor_s name = \
{ size, DSC$K_DTYPE_T, DSC$K_CLASS_S, array_name }
void enable_room_ast(int mailbox_channel, int efn);
void more_room_ast(int efn);
volatile int ast_enabled = FALSE;
int main(void)
{
/*
* Message limits are intentionally small to facilitate demonstration of
* error conditions.
*/
#define max_msg_len 128 /* Maximum input string size */
#define mailbox_maxmsg 64 /* Maximum mailbox message size */
#define mailbox_bufquo 128 /* Total buffer space in mailbox */
$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);
#pragma member_alignment save
#pragma nomember_alignment LONGWORD
struct io_status_block { /* I/O status block */
unsigned short int condition;
unsigned short int count;
unsigned int dev;
} iosb;
#pragma member_alignment restore
int status, mailbox_channel, wait_efn;
/*
* Create a temporary mailbox with a WRITEONLY channel. Its logical name
* will be entered into the LNM$TEMPORARY_MAILBOX logical name table.
*/
status = sys$crembx(0,&mailbox_channel,mailbox_maxmsg,mailbox_bufquo,
0,0,&mailbox_name_desc,CMB$M_WRITEONLY);
if (status != SS$_NORMAL) (void) lib$signal(status);
/*
* Mark the mailbox for deletion. This step is not necessary for a temporary
* mailbox, but is included as an illustration.
*/
(void) sys$delmbx(mailbox_channel);
/*
* Reserve an event flag to use with "room in malbox" AST notifications.
*/
status = lib$get_ef(&wait_efn);
if (status != SS$_NORMAL)
(void) lib$signal(status);
/*
* Loop forever, first waiting until 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(
EFN$C_ENF,
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 write EOF to
* the mailbox, deassign the channel, and exit.
* The writer should not deassign the channel while the write EOF
* operation is pending, since the write would be cancelled and
* the reader would never receive the EOF. Omitting IO$M_NOW in
* this QIOW insures that it will not complete until the reader
* has actually read the EOF from the mailbox.
*/
if (status == RMS$_EOF)
{ (void) sys$qiow(
EFN$C_ENF,
mailbox_channel,
IO$_WRITEOF|IO$M_READERCHECK,
&iosb,
0,0,0,0,
0,0,0,0);
(void) sys$dassgn(mailbox_channel);
(void) sys$exit(SS$_NORMAL);
}
/* Write the message into the mailbox. If there isn't enough
* room, try again until it fits.
* 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.
*/
do
{
status = sys$qiow(
EFN$C_ENF,
mailbox_channel,
IO$_WRITEVBLK|IO$M_READERCHECK|IO$M_NOW|IO$M_NORSWAIT,
&iosb,
0,0,
write_buffer_desc.dsc$a_pointer,
write_buffer_desc.dsc$w_length,
0,0,0,0);
if (status == SS$_NORMAL)
{
/* If there is no longer a reader, just exit. */
if ((unsigned int) iosb.condition == SS$_NOREADER)
{
(void) sys$dassgn(mailbox_channel);
(void) sys$exit(iosb.condition);
}
}
else if (status == SS$_MBFULL)
{
if (ast_enabled)
/*
* Wait here until the AST routine sets the event
* flag. A read might have already occured, in which
* case the wait will return immediately.
*/
(void) sys$waitfr(wait_efn);
else
/*
* The mailbox was full a moment ago at the time of
* write, but a read might have already occured and
* the mailbox might be empty now. It is possible
* that no more reads will complete (and deliver
* the AST) before the next write. So enable the AST
* and try the write one more time before waiting for
* the event flag.
*/
enable_room_ast(mailbox_channel, wait_efn);
} else /* An unexpected error condition */
(void) lib$signal(status);
}
while (status != SS$_NORMAL);
}
}
}
void enable_room_ast(int mailbox_channel, int efn)
/*
* This routine requests AST delivery when there is room in the mailbox.
* AST delivery may be triggered by a read or a cancelled I/O.
*/
{
int status;
ast_enabled = TRUE;
status = sys$clref(efn);
/*
* This QIOW returns immediately, whether there is room in the mailbox
* or not. Even if there is room in the mailbox now, the AST is
* NOT delivered immediately, but only later when a read or cancel
* I/O occurs on the mailbox.
*/
status = sys$qiow(
EFN$C_ENF,
mailbox_channel,
IO$_SETMODE|IO$M_MB_ROOM_NOTIFY,
0,0,0,
more_room_ast,efn,0,0,0,0);
}
void more_room_ast(int efn)
/*
* This AST routine is called when there is room to write more data into
* the mailbox.
*/
{
ast_enabled = FALSE;
(void) sys$setef(efn);
} |