.PAPER SIZE 54,60 .RIGHT MARGIN 60 .NO NUMBER .TITLE The QIO Interface to F11ACP .AUTOPARAGRAPH # .BLANK 4 .CENTER;Using ACP QIOs from .CENTER;High Level Languages .CENTER;under RSX .BLANK 4 .CENTER;- DA120A - .BLANK 4 .CENTER;Thomas R. Wyant, III .CENTER;E. I. DuPont de Nemours .CENTER;Richmond, Virginia .BLANK 4 .CENTER;December 11, 1991 .BLANK 4;.CENTER;Abstract .BLANK;.LEFT MARGIN +10;.RIGHT MARGIN -10 This paper presents an introduction to the Files-11 Ancillary Control Program's Queue I/O (F11ACP QIO) calls, and a case study of their use from a high level language. The intent is not to present an exhaustive summary of the QIO calls, but rather to present and demystify a useful subset of them. .LEFT MARGIN -10;.RIGHT MARGIN +10 .PAGE .HEADER LEVEL 1 Purpose .AUTOPARAGRAPH The purpose of this article is to introduce the QIO interface to F11ACP. This is not an exhaustive paper, but covers those portions of the interface which the author has found useful, and which presumably might be of interest to others. .HEADER LEVEL What Is an ACP QIO? RSX provides a general-purpose low-level I/O mechanism called the QIO, which is available from both high and low level languages. The QIO is an executive service, with both synchronous and asynchronous forms, and the general format is documented in the Executive Reference Manual. Although a QIO can be executed completely by the RSX executive, it need not be, and in fact usually isn't. When we think of doing I/O by direct use of the QIO mechanism, we usually think of communicating directly with a device driver, as documented in the I/O Drivers Reference Manual. Whether a QIO is handled by the executive or the driver depends on the I/O function code specified in the QIO request, and is controlled by a table in the Device Control Block for the device in question. File structured volumes are a special case. It is not really desirable to embed knowledge about the file structure in a driver or the executive. Embedding it in user programs would allow one bug to wipe out an entire volume. Thus, RSX associates each mounted file-structured volume with an Ancillary Control Processor, which maintains the file structure of the volume, and controls access to it. Access to the ACP is through the QIO interface, hence the term "ACP QIO". QIO requests are dispatched to the ACP using the table in the Device Control Block which has already been mentioned. The ACP is a privileged task which translates the QIO requests it receives (such as "Access File", "Read Virtual Block", "Extend File", and others) into driver QIOs (typically Read or Write Logical Block), and maintains the in-memory data structures necessary to support the volume structure (such as Volume Control Blocks, File Control Blocks, and Window Blocks). There are two ACPs normally present on an RSX system. F11ACP is responsible for creating files and managing space on a Files-11 direct access device (such as a disk). MTAACP maintains the ANSI standard file format on sequential access devices such as tape. This paper will deal with the F11ACP functions. The MTAACP functions are similar in some ways but different in others (for example, file name conventions, and the absence of directories). .HEADER LEVEL Why Bother? Normally, a user task need not worry about ACP QIOs - they are generated by the task's record access routines (FCS or RMS), which are often driven in turn by the Object Time System of a high level language such as FORTRAN. So the person who is interested in a file only for the data it contains has no real need to know anything about the ACP QIOs. But sometimes, one may be have an interest in a file other than as a repository of data. One may wish to manipulate the attributes of the file; for example, to change its ownership or protection, or to duplicate its attributes in a new file. A program may need to force access to a locked file, or to change its creation or revision date, or simply to find out some things about it which the high-level interface does not support. For this type of operation the ACP QIOs can be useful, or even essential. .HEADER LEVEL But Is It Safe? The whole purpose of the ACP is to protect the integrity of the volume. It should be no more possible to clobber a volume using an ACP QIO than to crash RSX using a normal QIO. That is to say, it doesn't normally happen, but some caution is recommended, especially in the early stages of program development. It is certainly possible to clobber a file using the ACP QIOs; the contents of a file are the responsibility of the program that accesses it, and under RSX the record overhead and attributes come under that responsibility. You should not, for example, normally expect to access a file in any reasonable fashion after changing its record attribute from "variable length" to "fixed length"; nor should you necessarily expect PIP or SRD to perform nicely on a "select by date" operation if you have replaced the creation date of a file with your mother's maiden name. .HEADER LEVEL Who Can Use the ACP QIO Interface? RSX does not restrict access to this interface - indeed it cannot, as any task that does file I/O uses it. And unlike the FCS and RMS interfaces, the data structures required by the ACP QIOs are simple enough to be supportable by most high-level language; typically all that's needed is a few arrays for data buffers. .HEADER LEVEL Available Functions As mentioned above, the ACP QIOs provide all the functionality necessary to maintain and use the files on a volume. For the F11ACP, these functions fall into four classes. The first class is file operations such as creating, opening, extending, closing, and deleting. The second class is represented by directory operations such as creating and removing directory entries and looking up a file in a directory. The third class is made up of the data I/O operations: reading and writing blocks. The fourth class is file attribute maintenance. Since this article is intended to be practical rather than exhaustive, not all classes of ACP QIO will be dealt with in equal depth of detail. The first two classes of operation are handled adequately (for the most part) by any high level language, and deficiencies can generally be fixed by manipulating file attributes after the fact. The only operation out of these classes that the author has used in over ten years of experience with RSX is the "extend file" operation. This will be covered; the rest will be omitted except for a hint or two on how to avoid the need for them. .HEADER LEVEL QIO Review A quick review of the structure of a QIO call is in order here, to establish naming conventions for the discussion which follows. In MACRO-11 assembler, a synchronous QIO call looks like this: .BLANK;.LEFT MARGIN +10;.INDENT -5 QIOW$ Function, LUN, Event Flag, , Status, AST, .BLANK;.LEFT MARGIN -10 In FORTRAN, the corresponding call is: .BLANK;.LEFT MARGIN +5;.NOFILL INTEGER*2 P(6) CALL WTQIO (Function, LUN, Event Flag, , Status, P) .BLANK;.LEFT MARGIN -5;.FILL All arguments are words (INTEGER*2 or LOGICAL*2 in FORTRAN), and the six elements of the FORTRAN array P correspond to the six function-specific arguments of the MACRO-11 call, P1 through P6. Unlike many QIO calls, where most of the function-specific parameters are ignored, in ACP QIOs they are typically all at least looked at. If a given function does not employ a given parameter, it is generally NOT safe to have it be a non-zero value. If you're programming in FORTRAN, be aware that whenever an ACP QIO takes a long integer as an argument, it expects that argument to be passed with the most significant word first. This is the exact opposite of the FORTRAN INTEGER*4 convention, which stores the least significant word first. I found it very convenient to write a function which takes one INTEGER*4 argument, swaps the high and low words, and returns the resulting value. For example: .BLANK;.LEFT MARGIN +5;.NOFILL FUNCTION JSWAP (ARG) INTEGER*4 JSWAP,ARG,J1,J2 INTEGER*2 I1(2),I2(2) EQUIVALENCE (I1, I2) J1 _= ARG I2(1) _= I1(2) I2(2) _= I1(1) JSWAP _= J2 RETURN END .BLANK;.LEFT MARGIN -5;.FILL when JSWAP is mentioned in the discussion below, this is the function referred to. .HEADER LEVEL Accessing Files Unless you need to do a directory search or access a file by file ID, a high level language like FORTRAN normally has all you need in this area. Even the exceptional cases are probably better handled in FORTRAN with a USEROPEN routine, for then you can do normal READs and WRITEs on the file, which you can't do if you open it using an ACP QIO. Even if you wish for some reason to prevent FORTRAN READs and WRITEs, you still don't need the ACP QIOs. Simply specify BUFFERCOUNT=-1 in the OPEN statement, and FORTRAN will open the file without allocating any I/O buffers to it. The open file will still count against the task's FILES quota (if you're using FCS), but the buffers can be used to multibuffer another file. .HEADER LEVEL Extending Files If you take the above recommendation, however, you must extend the opened file explicitly if it is too small. It is not extended implicitly by a write as it is by an FCS or RMS write operation. In order to extend a file, you use the IO.EXT function (11400 octal). The function specific arguments are as follows: .LIST '*' .LE;P1 is zero if a file is accessed on the LUN specified in the QIO call; otherwise it is the address of a three-word file ID block. The first word of the file ID block is the file ID number, the second is the file sequence number, and the third is zero. .LE;P2 is the address of a placement control attributes list, or zero. We won't deal with placement control here. .LE;P3 is a "hybrid" - it contains the most significant word of the number of blocks to extend the file, but the high byte is a flags byte which must be set to 200 octal. .LE;P4 is the least significant word of the number of blocks to extend the file. .LE;P5 is zero. .LE;P6 is zero. .END LIST If you're building this parameter block in FORTRAN, a reasonable way to proceed is to declare the parameter array like this: .BLANK;.LEFT MARGIN +5;.NOFILL INTEGER*2 PARAMS (6) ! QIO Parameters LOGICAL*1 BYTPRM (12) ! For funny stuff. INTEGER*4 EXTEND ! Blocks to extend file. .BLANK EQUIVALENCE (PARAMS, BYTPRM) EQUIVALENCE (PARAMS (5), EXTEND) .BLANK;.LEFT MARGIN -5;.FILL given the above finagle, you can load the parameter block with the following code fragment: .BLANK;.LEFT MARGIN +5;.NOFILL PARAMS(1) = 0 ! Or pointer to File ID PARAMS(2) = 0 PARAMS(5) = 0 PARAMS(6) = 0 EXTEND = JSWAP (number of blocks to extend) BYTPRM(3) = '200'O .BLANK;.LEFT MARGIN -5;.FILL All this done, what remains is simply to issue the QIO: .BLANK;.INDENT +5 CALL WTQIO (IOEXT, LUN, EF, , IOSTAT, PARAMS, IDSW) .BLANK Like any QIO call, both the executive status (IDSW) and the I/O status (IOSTAT) must be checked to insure successful completion. .HEADER LEVEL File I/O Actual I/O to the file is analogous to I/O to any other device. It is accomplished by the Virtual Block I/O functions: IO.RVB, which reads virtual blocks, and IO.WVB, which writes them. Of the six function-specific parameters in a QIO call, P1 is the I/O buffer address and P2 is its size in bytes, just as in any I/O call. The starting virtual block number is passed in P4 and P5, with the high word in P4 and the low word in P5. This is the opposite of the normal FORTRAN storage order for an INTEGER*4 variable, so you'll have to remember to swap the words if you're programming in FORTRAN. The number of blocks read is determined by P2. It is possible to read fractional blocks, but reads must be in multiples of two bytes (four if you're still cursed with working RP02 or RP03 disks), and must start at the beginning of a block. Virtual block I/O is insensitive to the end-of-file position as recorded in the file header; any block allocated to the file can be read, regardless of the position of the end of the file. Neither is the end-of-file marker updated by virtual block writes; you must do it yourself using the attribute manipulation functions described below. You may also wish to bear in mind that a virtual block I/O operation to an unmounted (or mounted-foreign) mass storage device is translated to the equivalent logical block operation, so the same code will handle both cases. Logical block I/O to a mounted volume is illegal for a non-privileged task. .HEADER LEVEL Attribute Manipulation The ability to manipulate file attributes is probably the greatest single reason to use the ACP QIO functions. This is the functionality that allows you to read or alter such characteristics as the location of the end-of-file marker, the creation or revision date, the record type, size, and attributes, and so on. The QIO calls for reading and writing file attributes have generally the same structure. In order to read attributes, the IO.RAT function code (13000 octal) is used; IO.WAT (13400 octal) writes attributes. In either case, the function specific arguments are as follows: .LIST '*' .LE;P1 is zero if a file is accessed on the LUN specified in the QIO call; otherwise it is the address of a three-word file ID block. The first word of the file ID block is the file ID number, the second is the file sequence number, and the third is zero. .LE;P2 is the address of the list of attributes to be read or written. The format of this list is discussed further below. .LE;P3 is zero. .LE;P4 is zero. .LE;P5 is zero. .LE;P6 is zero. .END LIST The attributes to be read or written are encoded in a list whose address is passed in P2 of the QIO call. Each attribute requires two words to encode it. The first byte is the attribute code, defined in the table below; IF THE ATTRIBUTE IS BEING READ, THE CODE IS NEGATED. The second byte is the length of the attribute buffer provided, in bytes (except in the case of reading the entire file header, when this byte must be zero). Bytes three and four contain the address of the attribute buffer. The attribute list is terminated by a word whose value is zero. The defined attribute codes and their associated buffer sizes are as follows: .BLANK;.LEFT MARGIN +5;.NOFILL Useful Maximum Code Size Size File Attribute (Octal) (Decimal) (Decimal) -------------------- ------- --------- --------- File Owner 1 2 6 File Protection 2 2 4 File Characteristics 3 1 2 User File Attributes 4 32 32 File Name/Type/Versn 5 10 10 File Type 6 2 4 File Version Number 7 2 2 File Expiration Date 10 7 7 Statistics Block 11 10 10 Entire File Header 12 512 512 File Revision number +Creation/Revision/ Expiration Dates 15 16 35 .BLANK;.LEFT MARGIN -5;.FILL The File Header buffer must be 512 bytes long, but its length must be given in the attributes list as 0. The other buffers may (according to the documentation) be specified at any size from 1 byte to the maximum given; information that won't fit in the buffer is simply dropped. The author makes no guarantee of what will happen if you ask for a 1-byte file version number. Not all the buffer is used in some cases; the column "Useful Size" gives the amount of each buffer which the author considers to contain information worth knowing. The only thing knowingly not covered by this is the expiration date in function 15 - and RSX doesn't support expiration dates anyway. Data is generally stored in the attribute buffers the same way it is stored in the file header itself. The write-up on ACP QIOs in Appendix C of the RSX-11M/M-PLUS I/O Drivers Reference Manual covers this in some detail, but for the complete scoop see Appendices A and F of the I/O Operations Reference Manual. The more obscure attribute blocks are as follows: .LIST '*' .LE;File Characteristics: .BREAK Bit 7 (Sign bit): Set to mark file contiguous. .BREAK Bit 6: Set if the file is locked. .LE;User File Attributes: .BREAK Byte 0: Record type. .BREAK Byte 1: Record attributes. .BREAK Word 1: Record size. .BREAK Words 2-3: Number of blocks allocated to file. .BREAK Words 4-5: End of file block. .BREAK Word 6: End of file byte. .END LIST At this point a couple examples appear to be in order. In the first, the entire file header is read. The various attributes are picked out by equivalencing their buffers across the header block buffer. In FORTRAN, the buffers would be declared like this: .BLANK;.LEFT MARGIN +5;.NOFILL INTEGER*2 PARAMS (6) ! QIO Parameters INTEGER*2 HDRATR (2,2) ! Attribute list. INTEGER*2 HDRBUF (256) ! File header buffer. INTEGER*2 HDRFID (2) ! File ID, Sequence. LOGICAL*1 HDRFCH (2) ! File characteristics. INTEGER*2 HDRUFA (16) ! User File Attributes. INTEGER*2 HDRPRO ! File Protection. .BLANK EQUIVALENCE (HDRBUF (2), HDRFID (1)) EQUIVALENCE (HDRBUF (6), HDRPRO) EQUIVALENCE (HDRBUF (7), HDRFCH (1)) EQUIVALENCE (HDRBUF (8), HDRUFA (1)) .BLANK;.LEFT MARGIN -5;.FILL Given the above declarations, you can load the parameter block and attribute list with the following code fragment: .BLANK;.LEFT MARGIN +5;.NOFILL PARAMS(1) = 0 ! Or pointer to File ID CALL GETADR (PARAMS (2), HDRATR) PARAMS(3) = 0 PARAMS(4) = 0 PARAMS(5) = 0 PARAMS(6) = 0 HDRATR (1,1) = -'12'O .AND. '377'O CALL GETADR (HDRATR (2,1), HDRBUF) HDRATR (1,2) = 0 .BLANK;.LEFT MARGIN -5;.FILL Given this, the QIO call is: .BLANK CALL WTQIO (IORAT, LUN, EF, , IOSTAT, PARAMS, IDSW) The second example writes the User File Attributes, the File Protection, and the Creation and Revision Dates: .BLANK;.LEFT MARGIN +5;.NOFILL INTEGER*2 PARAMS (6) ! QIO Parameters INTEGER*2 ATRLST (2,4) ! Attribute list. INTEGER*2 OUTUFA (16) ! User File Attributes. INTEGER*2 OUTPRO ! File Protection. INTEGER*2 OUTDAT (18) ! Creation/Revision. .BLANK;.LEFT MARGIN -5;.FILL Given the above declarations, you can load the parameter block and attribute list with the following code fragment: .BLANK;.LEFT MARGIN +5;.NOFILL PARAMS(1) = 0 ! Or pointer to File ID CALL GETADR (PARAMS (2), ATRLST) PARAMS(3) = 0 PARAMS(4) = 0 PARAMS(5) = 0 PARAMS(6) = 0 ATRLST (1,1) = 32*'400'O + '4'O CALL GETADR (ATRLST (2,1), OUTUFA) ATRLST (1,2) = 2*'400'O + '2'O CALL GETADR (ATRLST (2,2), OUTPRO) ATRLST (1,3) = 35*'400'O + '15'O CALL GETADR (ATRLST (2,3), OUTDAT) ATRLST (1,4) = 0 .BLANK;.LEFT MARGIN -5;.FILL Given this, the QIO call is: .BLANK CALL WTQIO (IOWAT, LUN, EF, , IOSTAT, PARAMS, IDSW) .HEADER LEVEL Summary The author has found the above to be a useful subset of the F11ACP QIO calls. There is, of course, still more to cover: file access and deaccess, directory operations (including wildcard operations), access and placement control, and so on. Mount and dismount QIOs are also untouched, and potentially useful; they are undocumented ("subject to change"), but they could probably be puzzled out from the code to F11ACP, MOU, and DMO. The MTAACP functions are similar to those for F11ACP, but not always alike; here again is new ground to plow. But I hope I have given at least an introduction into this useful but little used capability of the RSX executive. .APPENDIX Bibliography .LEFT MARGIN 8 .NOAUTOPARAGRAPH .BLANK RSX11M/M-PLUS I/O Drivers Reference Manual, Order Number AA-FD09A-TC .BLANK IAS/RSX-11 I/O Operations Reference Manual, Order Number AA-M176A-TC .BLANK RSX-11M/M-PLUS and Micro/RSX Executive Reference Manual, Order Number AA-FR95A-TC