Document revision date: 19 July 1999
[Compaq] [Go to the documentation home page] [How to order documentation] [Help on this site] [How to contact us]
[OpenVMS documentation]

OpenVMS Programming Concepts Manual


Previous Contents Index

  1. When you specify an event flag number as an argument, SYS$QIO clears the event flag when it queues the I/O request. When the I/O completes, the flag is set.
  2. In this example, the program issues two Queue I/O requests. A different event flag is specified for each request.
  3. The Wait for Logical AND of Event Flags (SYS$WFLAND) system service places the process in a wait state until both I/O operations are complete. The efn argument indicates that the event flags are both in cluster 0; the mask argument indicates the flags for which the process is to wait.
  4. Note that the SYS$WFLAND system service (and the other wait system services) wait for the event flag to be set; they do not wait for the I/O operation to complete. If some other event were to set the required event flags, the wait for event flag would complete too soon. You must coordinate the use of event flags carefully. (See Section 11.8 for a discussion of the recommended method for testing I/O completion.)

Example 11-2 shows specifying an AST routine.

Example 11-2 AST Routine

 
#include <lib$routines.h> 
#include <starlet.h> 
#include <stsdef.h> 
        unsigned int status, astprm=1; 
   .
   .
   .
        status = SYS$QIO(...&ttast,   /* I/O request with AST */ (1) 
                        astprm...); 
        if (!$VMS_STATUS_SUCCESS( status ))   /* Queued successfully? */ 
                LIB$SIGNAL( status ); 
   .
   .
   .
} 
                                    
void ttast ( int astprm ) {                   /* AST service routine */ (2)
 
/* Handle I/O completion */ 
   .
   .
   .
 
        return; 
}                              /* End of AST routine */                        
 

  1. When you specify the astadr argument to the SYS$QIO system service, the system interrupts the process when the I/O completes and passes control to the specified AST service routine.
    The SYS$QIO system service call specifies the address of the AST routine, TTAST, and a parameter to pass as an argument to the AST service routine. When $QIO returns control, the process continues execution.
  2. When the I/O completes, the AST routine TTAST is called, and it responds to the I/O completion. By examining the AST parameter, TTAST can determine the origin of the I/O request.
    When this routine is finished executing, control returns to the process at the point at which it was interrupted. If you specify the astadr argument in your call to SYS$QIO, you should also specify the iosb argument so that the AST routine can evaluate whether the I/O completed successfully.

Example 11-3 shows specifying an I/O status block.

Example 11-3 I/O Status Block

#include <lib$routines.h> 
#include <stdio.h> 
#include <ssdef.h> 
#include <starlet.h> 
#include <stsdef.h> 
 
   .
   .
   .
/* I/O  status block */ 
        struct { 
                 unsigned short iostat, iolen; 
                 unsigned int dev_info; 
}ttiosb;                                                        (1)
 
        unsigned int status; 
   .
   .
   .
        status = SYS$QIO(,..., &ttiosb, ...);   (2)  
        if( !$VMS_STATUS_SUCCESS( status )) /* Queued successfully? */ 
                LIB$SIGNAL( status ); 
   .
   .
   .
        while(ttiosb.iostat == 0) { 
        /* Loop -- with delay -- until done */                  (3)
 
        } 
 
        if( !$VMS_STATUS_SUCCESS( ttiosb.iostat )) { 
        /* Perform error handling */ 
   .
   .
   .
        } 
 

  1. An I/O status block is a quadword structure that the system uses to post the status of an I/O operation. You must define the quadword area in your program. TTIOSB defines the I/O status block for this I/O operation. The iosb argument in the SYS$QIO system service refers to this quadword.
  2. Instead of polling the low-order word of the I/O status block for the completion status, the program uses the preferred method of using an event flag and calling SYS$SYNCH to determine I/O completion.
  3. The process polls the I/O status block. If the low-order word still contains zero, the I/O operation has not yet completed. In this example, the program loops until the request is complete.

11.8 Recommended Method for Testing Asynchronous Completion

Compaq recommends that you use the Synchronize (SYS$SYNCH) system service to wait for completion of an asynchronous event. The SYS$SYNCH service correctly waits for the actual completion of an asynchronous event, even if some other event sets the event flag.

To use the SYS$SYNCH service to wait for the completion of an asynchronous event, you must specify both an event flag number and the address of an I/O status block (IOSB) in your call to the asynchronous system service. The asynchronous service queues the request and returns control to your program. When the asynchronous service completes, it sets the event flag and places the final status of the request in the IOSB.

In your call to SYS$SYNCH, you must specify the same efn and I/O status block that you specified in your call to the asynchronous service. The SYS$SYNCH service waits for the event flag to be set by means of the SYS$WAITFR system service. When the specified event flag is set, SYS$SYNCH checks the specified I/O status block. If the I/O status block is nonzero, the system service has completed and SYS$SYNCH returns control to your program. If the I/O status block is zero, SYS$SYNCH clears the event flag by means of the SYS$CLREF service and calls the $WAITFR service to wait for the event flag to be set.

The SYS$SYNCH service sets the event flag before returning control to your program. This ensures that the call to SYS$SYNCH does not interfere with testing for completion of another asynchronous event that completes at approximately the same time and uses the same event flag to signal completion.

The following call to the Queue I/O Request (SYS$QIO) system service demonstrates how the SYS$SYNCH service is used:


 
   .
   .
   .
#include <lib$routines.h> 
#include <starlet.h> 
        unsigned int status, event_flag = 1; 
        struct { 
                        short int iostat, iolen; 
                        unsigned int dev_info; 
}ttiosb; 
   .
   .
   .
/* Request I/O */ 
        status = SYS$QIO (event_flag, ..., &ttiosb ...); 
        if (!$VMS_STATUS_SUCCESS(status)) 
                LIB$SIGNAL( status ); 
   .
   .
   .
/* Wait until I/O completes */ 
        status = SYS$SYNCH (event_flag, &ttiosb ); 
        if (!$VMS_STATUS_SUCCESS(status)) 
                LIB$SIGNAL( status ); 
   .
   .
   .
 
 
 

Note

The SYS$QIOW service provides a combination of SYS$QIO and SYS$SYNCH.

11.9 Synchronous and Asynchronous Forms of Input/Output Services

You can execute some input/output services either synchronously or asynchronously. A "W" at the end of a system service name indicates the synchronous version of the system service.

The synchronous version of a system service combines the functions of the asynchronous version of the service and the Synchronize (SYS$SYNCH) system service. The synchronous version acts exactly as if you had used the asynchronous version of the system service followed immediately by a call to SYS$SYNCH; it queues the I/O request, and then places the program in a wait state until the I/O request completes. The synchronous version takes the same arguments as the asynchronous version.

Table 11-2 lists the asynchronous and synchronous names of input/output services that have synchronous versions.

Table 11-2 Asynchronous Input/Output Services and Their Synchronous Versions
Asynchronous Name Synchronous Name Description
$BRKTHRU $BRKTHRUW Breakthrough
$GETDVI $GETDVIW Get Device/Volume Information
$GETJPI $GETJPIW Get Job/Process Information
$GETLKI $GETLKIW Get Lock Information
$GETQUI $GETQUIW Get Queue Information
$GETSYI $GETSYIW Get Systemwide Information
$QIO $QIOW Queue I/O Request
$SNDJBC $SNDJBCW Send to Job Controller
$UPDSEC $UPDSECW Update Section File on Disk

11.9.1 Reading Operations with SYS$QIOW

The SYS$QIO and SYS$QIOW system services move one record of data from a terminal to a variable. For synchronous I/O, use SYS$QIOW. Complete information about the SYS$QIO and SYS$QIOW system services is presented in the OpenVMS System Services Reference Manual.

Note

Do not use the SYS$QIO and SYS$QIOW system services for input from a file or nonterminal device.

The SYS$QIO and SYS$QIOW system services place the data read in the variable specified in the 1 argument. The second word of the status block contains the offset from the beginning of the buffer to the terminator---hence, it equals the size of the data read. Always reference the data as a substring, using the offset to the terminator as the position of the last character (that is, the size of the substring). If you reference the entire buffer, your data will include the terminator for the operation (for example, the CR character) and any excess characters from a previous operation using the buffer. (The only exception to the substring guideline is if you deliberately overflow the buffer to terminate the I/O operation.)

Example 11-4 shows use of the SYS$QIOW system service and reads a line of data from the terminal and waits for the I/O to complete.

Example 11-4 Reading Data from the Terminal Synchronously

   .
   .
   .
INTEGER STATUS 
! QIOW structures 
INTEGER*2 INPUT_CHAN             ! I/O channel 
INTEGER CODE,                    ! Type of I/O operation 
2       INPUT_BUFF_SIZE,         ! Size of input buffer 
2       PROMPT_SIZE,             ! Size of prompt 
2       INPUT_SIZE               ! Size of input line as read 
PARAMETER (PROMPT_SIZE = 13, 
2          INPUT_BUFF_SIZE = 132) 
CHARACTER*132 INPUT 
CHARACTER*(*) PROMPT 
PARAMETER (PROMPT = 'Input value: ') 
! Define symbols used in I/O operations 
INCLUDE '($IODEF)' 
! Status block for QIOW 
STRUCTURE /IOSTAT_BLOCK/ 
  INTEGER*2 IOSTAT,              ! Return status 
2           TERM_OFFSET,         ! Location of line terminator 
2           TERMINATOR,          ! Value of terminator 
2           TERM_SIZE            ! Size of terminator 
END STRUCTURE 
RECORD /IOSTAT_BLOCK/ IOSB 
! Subprograms 
INTEGER*4 SYS$ASSIGN, 
2         SYS$QIOW 
   .
   .
   .
! Assign an I/O channel to SYS$INPUT 
STATUS = SYS$ASSIGN ('SYS$INPUT', 
2                    INPUT_CHAN,,) 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) 
! Read with prompt 
CODE = IO$_READPROMPT 
STATUS = SYS$QIOW (, 
2                  %VAL (INPUT_CHAN), 
2                  %VAL (CODE), 
2                  IOSB, 
2                  ,, 
2                  %REF (INPUT), 
2                  %VAL (INPUT_BUFF_SIZE), 
2                  ,, 
2                  %REF (PROMPT), 
2                  %VAL (PROMPT_SIZE)) 
! Check QIOW status 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) 
! Check status of I/O operation 
IF (.NOT. IOSB.IOSTAT) CALL LIB$SIGNAL (%VAL (IOSB.IOSTAT)) 
! Set size of input string 
INPUT_SIZE = IOSB.TERM_OFFSET 
   .
   .
   .

11.9.2 Reading Operations with SYS$QIO

To perform an asynchronous read operation, use the SYS$QIO system service and specify an event flag (the first argument, which must be passed by value). Your program continues while the I/O is taking place. When you need the input from the I/O operation, invoke the SYS$SYNCH system service to wait for the event flag and status block specified in the SYS$QIO system service. If the I/O is not complete, your program pauses until it is. In this manner, you can overlap processing within your program. Naturally, you must take care not to assume data has been returned by the I/O operation before you call SYS$SYNCH and it returns successfully. Example 11-5 demonstrates an asynchronous read operation.

Example 11-5 Reading Data from the Terminal Asynchronously

   .
   .
   .
INTEGER STATUS 
! QIO structures 
INTEGER*2 INPUT_CHAN     ! I/O channel 
INTEGER CODE,            ! Type of I/O operation 
2       INPUT_BUFF_SIZE, ! Size of input buffer 
2       PROMPT_SIZE,     ! Size of prompt 
2       INPUT_SIZE       ! Size of input line as read 
PARAMETER (INPUT_BUFF_SIZE = 132, 
2          PROMPT = 13) 
CHARACTER*132 INPUT 
CHARACTER*(*) PROMPT 
PARAMETER (PROMPT = 'Input value: ') 
INCLUDE '($IODEF)'        ! Symbols used in I/O operations 
! Status block for QIO 
STRUCTURE /IOSTAT_BLOCK/ 
  INTEGER*2 IOSTAT,       ! Return status 
2           TERM_OFFSET,  ! Location of line terminator 
2           TERMINATOR,   ! Value of terminator 
2           TERM_SIZE     ! Size of terminator 
END STRUCTURE 
RECORD /IOSTAT_BLOCK/ IOSB 
! Event flag for I/O 
INTEGER INPUT_EF 
! Subprograms 
INTEGER*4 SYS$ASSIGN, 
2         SYS$QIO, 
2         SYS$SYNCH, 
2         LIB$GET_EF 
   .
   .
   .
! Assign an I/O channel to SYS$INPUT 
STATUS = SYS$ASSIGN ('SYS$INPUT', 
2                    INPUT_CHAN,,) 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) 
! Get an event flag 
STATUS = LIB$GET_EF (INPUT_EF) 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) 
! Read with prompt 
CODE = IO$_READPROMPT 
STATUS = SYS$QIO (%VAL (INPUT_EF), 
2                 %VAL (INPUT_CHAN), 
2                 %VAL (CODE), 
2                 IOSB, 
2                 ,, 
2                 %REF (INPUT), 
2                 %VAL (INPUT_BUFF_SIZE), 
2                 ,, 
2                 %REF (PROMPT), 
2                 %VAL (PROMPT_SIZE)) 
! Check status of QIO 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) 
   .
   .
   .
STATUS = SYS$SYNCH (%VAL (INPUT_EF), 
2                   IOSB) 
! Check status of SYNCH 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) 
! Check status of I/O operation 
IF (.NOT. IOSB.IOSTAT) CALL LIB$SIGNAL (%VAL (IOSB.IOSTAT)) 
! Set size of input string 
INPUT_SIZE = IOSB.TERM_OFFSET 
   .
   .
   .

Be sure to check the status of the I/O operation as returned in the I/O status block. In an asynchronous operation, you can check this status only after the I/O operation is complete (that is, after the call to SYS$SYNCH).

11.9.3 Write Operations with SYS$QIOW

The SYS$QIO and SYS$QIOW system services move one record of data from a character value to the terminal. Do not use these system services, as described here, for output to a file or nonterminal device.

For synchronous I/O, use SYS$QIOW and omit the first argument (the event flag number). For complete information about SYS$QIO and SYS$QIOW, refer to the OpenVMS System Services Reference Manual.

Example 11-6 writes a line of character data to the terminal.

Example 11-6 Writing Character Data to a Terminal

INTEGER STATUS, 
2       ANSWER_SIZE 
CHARACTER*31 ANSWER 
INTEGER*2 OUT_CHAN 
! Status block for QIO 
STRUCTURE /IOSTAT_BLOCK/ 
  INTEGER*2 IOSTAT, 
2           BYTE_COUNT, 
2           LINES_OUTPUT 
  BYTE      COLUMN, 
2           LINE 
END STRUCTURE 
RECORD /IOSTAT_BLOCK/ IOSB 
! Routines 
INTEGER SYS$ASSIGN, 
2       SYS$QIOW 
! IO$ symbol definitions 
INCLUDE '($IODEF)' 
   .
   .
   .
STATUS = SYS$ASSIGN ('SYS$OUTPUT', 
2                    OUT_CHAN,,) 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) 
STATUS = SYS$QIOW (, 
2                  %VAL (OUT_CHAN), 
2                  %VAL (IO$_WRITEVBLK), 
2                  IOSB, 
2                  , 
2                  , 
2                  %REF ('Answer: '//ANSWER(1:ANSWER_SIZE)),               
2                  %VAL (8+ANSWER_SIZE), 
2                  , 
2                  %VAL (32),,) ! Single spacing 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) 
IF (.NOT. IOSB.IOSTAT) CALL LIB$SIGNAL (%VAL (IOSB.IOSTAT)) 
END 

11.10 I/O Completion Status

When an I/O operation completes, the system posts the completion status in the I/O status block, if one is specified. The completion status indicates whether the operation completed successfully, the number of bytes that were transferred, and additional device-dependent return information.

Figure 11-7 illustrates the format for the SYS$QIO system service of the information written in the IOSB.

Figure 11-7 I/O Status Block


The first word contains a system status code indicating the success or failure of the operation. The status codes used are the same as for all returns from system services; for example, SS$_NORMAL indicates successful completion.

The second word contains the number of bytes actually transferred in the I/O operation. Note that for some devices this word contains only the low-order word of the count. For information about specific devices, see the OpenVMS I/O User's Reference Manual.

The second longword contains device-dependent return information.

System services other than SYS$QIO use the quadword I/O status block, but the format is different. See the description of each system service in the OpenVMS System Services Reference Manual for the format of the information written in the IOSB for that service.

To ensure successful I/O completion and the integrity of data transfers, you should check the IOSB following I/O requests, particularly for device-dependent I/O functions. For complete details about how to use the I/O status block, see the OpenVMS I/O User's Reference Manual.

11.11 Deassigning I/O Channels

When a process no longer needs access to an I/O device, it should release the channel assigned to the device by calling the Deassign I/O Channel (SYS$DASSGN) system service:


$DASSGN_S CHAN=TTCHAN 

This service call releases the terminal channel assignment acquired in the SYS$ASSIGN example shown in Section 11.5. The system automatically deassigns channels for a process when the image that assigned the channel exits.

11.12 Using Complete Terminal I/O

The following example shows a complete sequence of input and output operations using the $QIOW macro to read and write lines to the current default SYS$INPUT device. Because the input/output of this program must be to the current terminal, it functions correctly only if you execute it interactively.


#include <descrip.h> 
#include <iodef.h> 
#include <lib$routines.h> 
#include <ssdef.h> 
#include <starlet.h> 
#include <stdio.h> 
#include <string.h> 
#define BUFSIZ 80 
/* I/O status block */ 
struct {                                                          (1)
        unsigned short iostat, ttiolen; 
        unsigned int dev_info; 
}ttiosb; 
 
main() { 
        unsigned int status ,outlen, inlen = BUFSIZ; 
        unsigned short ttchan; 
        char buffer[BUFSIZ];                                         (2)
        $DESCRIPTOR(ttname,"SYS$INPUT");                         (3)
 
/* Assign a channel */ 
        status = SYS$ASSIGN(&ttname,    /* devnam - device number */ (4)
                        &ttchan,        /* chan - channel number */ 
                        0, 0, 0); 
        if (!$VMS_STATUS_SUCCESS(status)) 
                LIB$SIGNAL( status ); 
 
/* Request I/O */ 
        status = SYS$QIOW(0,                    /* efn - event flag */ 
                        ttchan,                 /* chan - channel number */ 
                        IO$_READVBLK,           /* func - function modifier */ 
                        &ttiosb,                /* iosb - I/O status block */ 
                        0,                      /* astadr - AST routine */ 
                        0,                      /* astprm - AST parameter */ 
                        buffer,                 /* p1 - buffer */ 
                        inlen,                  /* p2 - length of buffer */ 
                        0, 0, 0, 0);    (5)
        if (!$VMS_STATUS_SUCCESS( status )) (6)
                LIB$SIGNAL( status ); 
 
/* Get length from IOSB */ 
        outlen = ttiosb.ttiolen;        (7)
 
status = SYS$QIOW(0, ttchan, IO$_WRITEVBLK, &ttiosb, 0, 0, buffer, outlen, 
                0, 0, 0, 0); 
        if (!$VMS_STATUS_SUCCESS( status )) 
                LIB$SIGNAL( status );   (8)
 
/* Deassign the channel */ 
        status = SYS$DASSGN( ttchan ); /* chan - channel */  (9)
        if (!$VMS_STATUS_SUCCESS( status )) 
                LIB$SIGNAL( status ); 
 
} 
 


Previous Next Contents Index

  [Go to the documentation home page] [How to order documentation] [Help on this site] [How to contact us]  
  privacy and legal statement  
5841PRO_030.HTML