.TITLE QIO .IDENT /31JA89/ ; Version: ; File:[22,320]QIO.MAC Last Edit: 19-JUL-1989 11:27:28 ; ; Author: Philip Hannay ; History: 31-Jan-89 -- Philip Hannay. Created from old QIO.MAC. ; ; .REM | Procedure QIO(fnc: word; lun: word; efn: event_flag; var iosb: IO_status_block; var parm: QIO_param_list); EXTERNAL; {*USER* Pascal-3 Procedure to execute QIO "nowait" function. This procedure provides access to all functionality provided by the QIO nowait directive. It is assumed that you will include the PAS$EXT:QIO.TYP include file that contains various IO defintions for both normal and EIO type QIOs. A number of predefined function values are defined as constants. However, you may need to supply your own. NOTE: THE QIO NO WAIT works differently if your task is non-checkpointable. If your task is non-checkpointable, the input buffer you supplied will be used, and you can actually see the characters coming in before the QIO completes. On the other hand, if your task in checkpointable, the driver will used an external buffer, and you will not see any input characters until the QIO is complete. NOTE: ERROR CODES are returned in your IOSB as byte integers. That means Pascal sees the first two bytes of the IOSB as a positive integer as the error code is in the low order byte (and thus the sign bit) of the first IOSB word. Take this into account when you examine the IOSB. If the low order byte exceeds 127 (177 octal), then you are looking at a negative byte integer. To extract the error code into an integer, MOD the first IOSB word by 256 (to get low order byte), and if result exceeds 127, subtract 256 from the result. The final integer will then the be correct positive or negative number. To extract the high order byte, DIV the first IOSB word by 256. Since this is the terminating character (7 or 8 bit), it is unsigned, and may be taken as is. The second IOSB word is always a two byte integer (character count), and is unsigned. You can treat it as signed, since no QIO character count can exceed 8192. Note that the IO_status_block definition in GENERAL.TYP also lets you look at the status block as a 4 byte array. This lets you access the two bytes of the first word of the block directly. Accessing the bytes directly, you can get the IO status code using an ORD(BYT[1]). The resulting integer is unsigned from 0 thru 255. So if you want a signed integer, subtract 256 from the integer IF integer exceeds 127. You can look directly at the high order byte (terminating character if any) of the first status block word by doing an ORD(BYT[2]). To look at it as a character, use CHR(ORD(BYTE[2])). BE CAREFUL, if you are not familiar with the "no wait" action. Your task will continue processing, even though the QIO is not yet done. You must determine its state by examining the event flag and the IOSB. These QIOs can pile up, and if you keep issuing new ones, you may fill up pool. Read more in Executive Reference manual, and I/O Drivers Reference manual. Your program execution will continue after calling QIO, however the IO will not yet be complete. When execution continues after the QIO call, must be sure to check the directive status first to make sure that the QIO was accepted ($DSW=1), otherwise, you may be waiting for an IO that will never complete. Check the DSW IMMEDIATELY after calling QIO. Later in your program, you can check to see if the IO has completed, by looking at the associated event flag (set if complete), or the first word of the IO status block (non-zero if complete). Use the associated event flag for a stop for event flag if you have no more work to do. IMPORTANT - if you post more that one QIO at a time, remember that the associated event flag is cleared at every posting. Thus, if you are using the event flag to single that IO is complete, you need to use different flags for each QIO. On the other hand, if you use the non-zero state of the IO status block to signal that IO is complete, you can use the same event flag for multiple QIOs. Note that if you use the same flag, you should check for completed IO PRIOR to stopping for the event flag, in case an IO completed before you issued your last QIO. QIOs are dequeued by the device driver in that same order as posted by your program (FIFO). Thus you can count on QIOs for the SAME DEVICE to complete in the order you posted them. Note that this is for the SAME device only. An IO.KIL function will complete all outstanding IO, at once, for the specified device (ie. the device currently associated with the LUN to which you sent the QIO). A file close operation (CLOSE) in a high level language will issue an IO.KIL to the device on which the file was open. This will complete any QIOs posted to that device even if they were posted using different LUNs (which were pointed to that device). In particular, if you open a file for IO to a terminal port, when you close it, any QIOs posted to that terminal port will be completed by the IO.KIL of the file close. Note that you may need to supply imbedded carriage return and line feed in your output buffer, or use the VFC parameter (parameter 4) supplying a FORTRAN style form control character like blank (LF buffer CR) or "1" (LF buffer CR CR), etc. Note that normal DEC convention is to output a leading LF (linefeed) before any output, and then output a trailing CR (carriage return) after outputting buffer. FNC is the IO function code - a word value. Use the predefined contants in QIO.TYP, or supply your own code. LUN is the logical unit number to be assigned to the appropriate device. EFN is the event flag to be set when the I/O is completed. You must supply an event flag (local or otherwise). You cannot use f0. IOSB is the two word IO status block. PARM is the 6 word QIO parameter list. Supply a zero for any parameters that are null or not applicable. Remember that a zero will have meaning in many cases depending on the function code used. If you supply a timeout value in the parameter list, remember that a zero indicates a "zero timeout" is to be done, and a positive value indicates "timeout of value*10 seconds" to be done. IMPORTANT NOTE: Variables passed in the PARM parameter list cannot be noted by the Pascal compiler, and it may make a mistake when it optimizes code, based on the assumption that the QIOW call does not use those variables. To avoid a problem, be sure to make global any variable that is passed in PARM (as an address) that is modified by the QIOW call. In particular, the input buffer variable where the results of a read operation will be placed. By making the variable a global variable, the compiler will do no further optimization. IOSB and IOSB2 represent the two words of the IO status block. IOSB contains the IO status word. For read functions, the high byte contains the terminating character. IOSB2 is the second word of the IO status block, for read functions, it contains the byte count read in. Directive status is available in $DSW on return. } | ; ; Assemble with PASMAC.MAC as prefix file. ; .MCALL QIO$S PROC QIO PARAM FNC, INTEGER PARAM LUN, INTEGER PARAM EFN, SCALAR PARAM ISB1, ADDRESS PARAM PARM, ADDRESS SAVE BEGIN MOV SP,R0 ;PRESERVE SP MOVB EFN(0),R1 ;EFN PARAM IS A BYTE, MUST CLEAN IT UP BIC #^C^O377,R1 ;MAKE IT AN UNSIGNED WORD BNE 1$ MOV #IE.IEF, $DSW ;MUST SUPPLY EVENT FLAG BR 2$ 1$: MOV PARM(0),R2 ;R2 IS ADDRESS OF PARAMETER LIST ADD #10.,R2 ;R2 NOW POINTS TO LAST PARAMETER - ; NOTE THAT WE DO THIS SINCE THE ; QIO$S WILL MOVE THE PARAMETERS ; ONTO THE STACK STARTING WITH THE ; LAST ONE. QIO$S FNC(0),LUN(0),R1,,ISB1(0),,<-(R2),-(R2),-(R2),-(R2),-(R2),(R2)> 2$: ENDPR .END