THE AST Almost everyone is aware that RSX is a multi-tasking, multi-processing operating system. It is less obvious that a single task may easily schedule and service multiple events. The primary mechanism provided to process events is the asynchronous system trap or AST. You use AST's in two steps. First, you declare that when some event occurs you wish to interrupt normal processing and transfer control to the appropriate routine. Later when RSX detects the event, it causes control to be passed to your special routine. Obviously any program that works in a straight-forward, serial fashion will not need to use AST's. A program reading and processing input from one terminal falls into this category. But once the program needs to handle two or more terminals, AST's become an important tool. One major advantage with AST's is there is no wasted motion. Consider the different techniques available to determine when one or more inputs from three different terminals completes. The brute force approach would be to loop and keep checking the three I/O status blocks (looking for a non-zero value). This approach waste CPU time. Alternatively, you could use three seperate event flags and wait using the logical-or directive for completion. You then then have to check to see which I/O actually completed. If you issue the I/O with AST completions, you have to do nothing. When input line is entered, RSX tranfers program control to the appropriate routine. AST's in this environment actually help keep program logic simple. You can setup your routines as if your are processing in a serial fashion. Instead of using subroutine calls, you let AST's take direct program flow from one processing stage to another. AST's come in two forms: discrete and specified. Discrete AST's apply to one specific event, either a single I/O completion (QIO$), an elapsed time interval (MRKT$) or offspring task status (CNCT$, SPWN$, SDRC$). Specified AST's are used for notification of a class of events. AST's of this type include receive data (SRDA$), receive-by-reference (SRRA$), powerfail recovery (SPRA$), floating-point exception (SFPA$), command arrival (SCAA$), and specified exit (SREA$, SREX$). The difference between discrete and specified is quite simple. When an AST occurs, the RSX executive queues a AST data structure to the task. When the task is next scheduled, the first AST is removed from the queue and the task's normal processing is interrupted. The difference between discrete and specified is simply where the executive gets the space for the AST data structure. You need the event notification, so RSX must have somehow preallocated the necessary data structure. Discrete AST's reuses some previously allocated space, the internal I/O packet, clock queue entry, or offspring control structure. When you arm a specific AST, RSX allocates the necessary space and links to your program. Then when the event occurs, the data structure is unlinked from its holding list and queued as an AST. When the AST finally triggers, the data structure is returned to the holding list. Thus there is a subtle difference between discrete and specified AST's. Between the time the first event occurs and the specified AST is actually triggered, any further occurence of the event will not cause an AST. This is illustrated by a task which issues the SRDA$ directive for receive data notification. When a high priority program sends two messages in a row to the task, only first causes the AST to be queued. Your system would misfunction if the AST routine only received a single message and then returned. The proper algorithm is to receive messages until there are no more (DSW status IE.ITS). Then it is safe to exit the AST routine because the receive data AST has been rearmed. There are various facts you need to know about AST's. First, an AST has no effect on your normal task priority. If a higher priority task is blocking your execution, having an AST queued to you makes no difference. The AST will occur if your task even if the task is waiting, suspended, or stopped. If the task happened to be checkpointed when an AST was queued, the task is brought back into memory at its normal priority. When the program returns from the AST, the task keeps its original state unless something you did while processing the AST changes the state. A normal interaction between main-line and AST code is to have the main-line wait or stop on some event flag. The AST code processes the event to some point, queues further processing for the main-line, sets the event flag and declares a significant event. The only task state which prevents a queued AST from trigering is AST's disabled (DSAR$). Note then while an AST is in effect, RSX disables AST's, so you cannot get interrupted from while proceessing an AST. RSX pushes some key task status on your stack when it triggers the AST. These are then restored when you exit the AST using the ASTX$S directive. SP+06 Event flag mask SP+04 PS of task prior to AST SP+02 PC of task prior to AST SP+00 Task's DSW word These words should not altered by the AST code. Notice that RSX does not save the general or floating-point registers. Your AST code is responsible for saving and restoring any registers it uses. Some AST's also push additional information on the stack. This information must be removed before the ASTX$ directive is issued. An easy method of handling the optional data and registers is a Macro-11 cooroutine (see Figure 1). The routine saves all registers, copies any optional parameter into R3, and calls the AST routine back. You exit the AST with a simple return. All registers are then restored and the AST exits. The optional information returned for some AST's is very important. For instance, the AST serving I/O completion for the three terminals mentioned at the beginning would need to know which terminal's I/O finished. The optional parameter is the address of the terminal I/O status block. From this you can determine which terminal. One method is to test the address against the three known I/O status block addresses. A better algorithm is to consider the I/O status block as a part of a larger structure. The AST optional parameter is now the address of the terminal structure. addr+00 -> I/O status block addr+04 -> Logical unit number addr+06 -> I/O input buffer . . VMS did this correctly in their AST implementation. Instead of always using the I/O status address as the AST parameter, you may specify any 32-bit identifer, which is usually a structure address. This applies to all VMS AST's. The lack of this feature is particularly obvious for mark time AST's. The optional parameter is the event flag number. If you want to map to a structure, the best you can do is use the value for a table lookup. There is often a need for synchronization between AST's and your main-line code. If both were doing updates to a command area, you need block AST's while the main-line code performed its functions. This is simply done by using the DSAR$ (disable AST) and ENAR$ (enable AST) around the critical section. But what if you have a common routine that is used at both levels and requires synchronization. Figure 2 shows another cooroutine that solves this problem. It attempts to diasble AST's. If this fails because AST's are already disabled or you are calling from an AST routine the routine simple exits. Otherwise, a cooroutine return is made. When the critical routine finally returns, AST's are reenabled. One common point of criticality is file I/O. The main-line and AST's routines cannot both do FCS or RMS I/O or internal data structures can be corrupted. All is safe as long as AST's are disabled around the I/O calls in the main-line code. RSX does not make it easy to use AST's with the high-level languages. Most of the system calls do not let you specify an AST, so you must supply you own. You must also code a Macro-11 stub as the AST service code. In the following case, the routine QIOAST saves the registers and jumps to a FORTRAN routine with the I/O status address. When it returns, the ASTQIO cooroutine restores all registers. ARGBLK: .BYTE 1,0 ;One argument .WORD 0 ;I/O status QIOAST::JSR R5,ASTQIO ;Save registers MOV R3,ARGBLK+2 ;Set I/O status MOV #ARGBLK,R5 ;Get calling parameters JMP FOOBAR ;Jump to Fortran Finally, AST code and overlays do not mix. While main-line code can be overlaid and interrupted by AST's, all code executed by an AST must be in the root. There is no good way for an AST to save and restore overlay context. For further reading on AST's, see section 2.3.3 in the RSX-11M/RSX-11M-PLUS Excutive Reference Manual.