3.4. Asynchronous queued I/O (AQIO) routines

The asynchronous queued I/O (AQIO) routines perform asynchronous, queued I/O operations. Asynchronous I/O allows your program to continue executing while an I/O operation is in progress, and it allows several I/O requests to be active concurrently. AQIO further refines asynchronous I/O by allowing a program to queue several I/O requests and to issue one request to the operating system to perform all I/O operations. When queuing I/O requests, the overhead that is associated with calling the operating system is incurred only once per group of I/O requests rather than once per request as with other forms of I/O.

AQIO also offers options for streamlining I/O operations that involve fixed-length records with a fixed-skip increment through the user file and a fixed-skip increment through program memory. A form of this is a read or write that involves contiguous fixed-length records. Such an operation is called a compound AQIO request or a compound AQIO operation. AQIO provides separate calls for compound operations so that a program can specify multiple I/O operations in one call, thus saving I/O time.

Asynchronous I/O has a larger overhead in system CPU time than synchronous I/O; therefore, only large data transfers should be done using asynchronous I/O. To speed up the program, the program must be able to do a significant amount of CPU-intensive work or other I/O while the asynchronous I/O is executing.

The value of the queue argument on the AQWRITE/AQWRITEC(3F) or AQREAD/AQREADC call controls when the operating system is called to process the request. If queue is nonzero, packets are queued in the AQIO buffer and the operating system is not called to start packet processing until the buffer is full (for example, to queue 20 packets, the program would issue 19 AQWRITE calls with queue set to a nonzero value and then set it to 0 on the twentieth call).

On Cray  T3E systems, when a program opens a file with AQOPEN, a file handle is returned. The library associates this handle with information in the processing element's (PE) local memory; therefore, the file handle should not be used by other PEs. More than one PE can open a file with AQOPEN; if coordination between the different PEs is required, the user must do the coordination using synchronization routines.

The following list briefly describes the AQIO routines; for details about the routines discussed in this section, see the individual man pages for each routine.

3.4.1. Error detection by using AQIO

Because of the asynchronous nature of AQIO, error detection and reporting with AQIO may not occur immediately on return from a call to an asynchronous queued I/O subroutine. If one of the queued I/O requests causes an error when the operating system tries to do the I/O, the error is returned in a subsequent AQIO request.

For example, if a program issues an AQWRITE with queue set to 0, I/O is initiated. If no previous errors occurred, a 0 status is returned from this statement even though this request may ultimately fail. If the request fails, for example, because it tried to exceed the maximum allowed file size, the error is returned to the user in the subsequent AQIO statement that coincides with its detection. If the next AQIO statement is AQWAIT, the error is detected and returned to the user. If the next AQIO statement is AQSTAT, the error is detected and reported only if the requested ID failed. When an error is reported to the user, it is not reported again. Checking the status after each AQIO statement ensures that the user program detects all errors.


Example 3-4. AQIO routines: compound read operations

      PROGRAM AQIO1
      IMPLICIT INTEGER(A-Z)
      PARAMETER (TOTREQ=20)
      PARAMETER (AQPSIZE=20)
      INTEGER AQP
      INTEGER BUFFER (TOTREQ*512)
      INTEGER EVNBUF (TOTREQ/2*512)
      INTEGER ODDBUF (TOTREQ/2*512)

      CALL AQOPEN (AQP,AQPSIZE,'FILE4'H,STAT)
      IF (STAT.NE.0) THEN
         PRINT *,'AQOPEN FAILED, STATUS= ',STAT
         CALL ABORT()
      ENDIF

C     INITIALIZE DATA
      DO 10 I=1,TOTREQ*512
         BUFFER(i) = I
10    CONTINUE

      DO 50 RNUM=1,TOTREQ
C       QUEUE THE REQUESTS
C       INITIATE I/O ON THE LAST REQUEST

C       THE DATA FROM BUFFER IS WRITTEN IN A SEQUENTIAL
C       FASHION TO DISK
        QUEUE=1
        IF (RNUM.EQ.TOTREQ) QUEUE=0
           OFFSET= (RNUM-1)*512+1
          CALL AQWRITE(
         '    AQP,
         '    BUFFER(OFFSET),   !start address
         '    RNUM-1,           !block address
         '    1,                !number of blocks
         '    RNUM,             !request id
         '    QUEUE,            !queue request or start I/O
         '    STAT)             !return status
        IF (STAT.NE.0)THEN
           PRINT*,'AQWRITE FAILED, STATUS= ',STAT
           CALL ABORT()
        ENDIF
50    CONTINUE

C     WAIT FOR I/O TO COMPLETE
      CALL AQWAIT (AQP,STAT)
      IF (STAT.LT.0) THEN
         PRINT*,'AQWAIT AFTER AQWRITE FAILED, STATUS=',STAT
         CALL ABORT()
      ENDIF

C     NOW ISSUE TWO COMPOUND READS.  THE FIRST READ
C     GETS THE ODD SECTORS AND THE SECOND GETS THE
C     EVEN SECTORS.
C
      INCS=TOTREQ/2-1
      CALL AQREADC(
      '    AQP,
      '    ODDBUF(1),         ! start address
      '    512,               ! mem stride
      '    1,                 ! block number
      '    1,                 ! number of blocks
      '    2,                 ! disk stride
      '    INCS,              ! incs
      '    1,                 ! request id
      '    1,                 ! queue request
      '    STAT1)             ! return status
      CALL AQREADC(
      '    AQP,
      '    EVNBUF(1),         ! start address
      '    512,               ! mem stride
      '    0,                 ! block number
      '    1,                 ! number of blocks
      '    2,                 ! disk stride
      '    INCS,              ! incs
      '    2,                 ! request id
      '    0,                 ! start request
      '    STAT2)             ! return status
      IF ((STAT1.NE.0). OR. (STAT2.NE.0)) THEN
         PRINT *,'AQREADC FAILED, STATUS= ',STAT1,STAT2
         CALL ABORT()
      ENDIF

      CALL AQWAIT (AQP,STAT)
      IF (STAT.LT.0) THEN
         PRINT *,'AQWAIT FAILED, STATUS= ',STAT
         CALL ABORT()
      ENDIF

C     VERIFY THAT THE DATA READ WAS CORRECT
      K = 1
      DO 90 I = 1,TOTREQ,2
          DO 80 J = 1,512
            IF (EVNBUF (J+(K-1)*512).NE.J+(I-1)*512)THEN
               PRINT *,'BAD DATA EVN',EVNBUF(J+(K-1)*512),J,I,K
               CALL ABORT()
            ENDIF
80        CONTINUE
          K=K+1
90    CONTINUE
      K = 1
      DO 99 I = 2,TOTREQ,2
          DO 95 J = 1,512
             IF (ODDBUF(J+(K-1)*512).NE.J+(I-1)*512)
                PRINT *,'BAD DATA ODD',ODDBUF(J+(K-1)*512),J,I,K
                CALL ABORT()
             ENDIF
95        CONTINUE
          K=K+1
99    CONTINUE
      CALL AQCLOSE(AQP,STAT)
      IF(STAT.NE.0) THEN
              PRINT *,'AQCLOSE FAILED, STATUS= ',STAT
              CALL ABORT()
            ENDIF
       END                                                                   



Example 3-5. AQIO routines: error detection

   PROGRAM AQIO2
   IMPLICIT INTEGER(A-Z)
   PARAMETER (TOTREQ=20)
   PARAMETER (AQPSIZE=20)
   INTEGER AQP
   INTEGER BUFFER (TOTREQ*512)
   INTEGER INBUF (512)

   CALL AQOPEN (AQP,AQPSIZE,'FILE4'H,STAT)
   IF (STAT.NE.0) THEN
      PRINT *,'AQOPEN FAILED, STATUS=',STAT
      CALL ABORT()
   ENDIF

   DO 50 RNUM=1,TOTREQ

C    QUEUE THE REQUESTS
C    INITIATE I/O ON THE LAST REQUEST
C    THE DATA FROM BUFFER WILL BE WRITTEN IN A
C    SEQUENTIAL FASHION TO DISK
     QUEUE=1
     IF (RNUM.EQ.TOTREQ) QUEUE=0
          OFFSET= (RNUM-1)*512+1
          CALL AQWRITE (
          '    AQP,
          '    BUFFER (OFFSET),   ! start address
          '    RNUM-1,            ! block number
          '    1,                 ! number of blocks
          '    RNUM,              ! request id
          '    QUEUE,             ! queue request or start I/O
          '    STAT)              ! return status
      IF (STAT.NE.0) THEN
          PRINT *,'AQWRITE FAILED, STATUS=',STAT
          CALL ABORT ()
      ENDIF
50 CONTINUE

C WAIT FOR I/O TO COMPLETE
   CALL AQWAIT (AQP,STAT)
   IF (STAT.LT.0) THEN
     PRINT *,'AQWAIT AFTER AQWRITE FAILED, STATUS= ',STAT
     CALL ABORT ()
   ENDIF
C  NOW ISSUE A READ. TO ILLUSTRATE ERROR DETECTION
C  ATTEMPT TO READ BEYOND THE END OF THE FILE
   CALL AQREAD (
    '    AQP,
    '    INBUF(1),     ! start address
    '    TOTREQ+1,     ! block number
    '    1,            ! number of blocks
    '    TOTREQ+1,     ! request id
    '    0,            ! start I/O
    '    STAT)         ! return status

   IF (STAT.NE.0)THEN
     PRINT *,'AQREAD FAILED, STATUS=',STAT
     CALL ABORT()
   ENDIF

   CALL AQWAIT (AQP,STAT)
C  BECAUSE WE ATTEMPTED TO READ BEYOND THE END
C  OF THE FILE, AQWAIT WILL RETURN A NEGATIVE
C  VALUE IN "STAT", AND THE PROGRAM WILL ABORT IN
C  THE FOLLOWING STATEMENT

   IF (STAT.LT.0) THEN
     PRINT *,'AQWAIT AFTER AQREAD FAILED, STATUS= ',STAT
     CALL ABORT()
   ENDIF

   CALL AQCLOSE (AQP,STAT)
   IF (STAT.NE.0) THEN
     PRINT *,'AQCLOSE, STATUS= ',STAT
     CALL ABORT()
   ENDIF
   END

The following is the output from running this program:

AQWAIT AFTER AQREAD FAILED, STATUS= -1202