(edited 19-Aug-91 because of indexing) (Resident Monitor (RMON)\RMON_CHAP)

The main purpose of the (Resident Monitor) (RMON) is to provide services to running programs and to the Keyboard Monitor. The services include fielding traps and interrupts, providing the programmed requests, and acting as the central manager of the device-independent I/O system. In a multi-job system, the monitor also arbitrates the demands of up to eight jobs for processor time.

This chapter describes the functions of RMON that are generally common to all RT--11 systems. It provides information on the monitor's terminal service for a single console terminal. (See (mtt_chap) for information on multiterminal systems.) It also describes how clock interrupts are handled and explains how timer support is implemented. The queued I/O system is discussed, scheduling for multi-job systems is described, and the system job feature is introduced. Lastly, information on RMON's data structures is provided. (Terminal Service)

RT--11 provides terminal service through RMON. Terminal service is always resident, and it is part of RMON itself. Because of the way RT--11 implements terminal service, no handler is involved in the interaction between you at the terminal and the running system. It is designed to be a good interface between a person and the system, rather than an interface between a peripheral device and the system.

As part of the resident terminal service, RMON provides special programmed requests for terminal I/O. Because it uses ring buffers to implement the terminal service, RMON provides support for line-by-line editing. The terminal input interrupts are always enabled, which means that you can get the system's attention at any time by pressing CTRL/C, CTRL/B, CTRL/F, and so on. You can also type ahead to the system without losing characters.

The ring buffers are the heart of the terminal service implementation. In single-job systems, one input ring buffer and one output ring buffer are located in the impure area of the single background job. In multi-job systems, each job has its own set of ring buffers located in its impure area. The ring buffers store text in a buffer zone between you at the terminal and a running program in memory. The default size of the input ring buffer is 134(10) bytes; the default size of the output ring buffer is 40(10) bytes. (Output Ring Buffer)

An output ring buffer consists of the buffer area, three pointers, and a byte count. The buffer, or ring, itself is a block of bytes reserved for storing characters. Two of the three pointers store and retrieve characters. The PUT pointer marks the location where the next character will be stored and is used by the programmed requests that fill the buffer, such as .TTYOUT, .TTOUTR, and .PRINT. The GET pointer marks the next character to be retrieved and is used by the output interrupt service routine that sends characters to the terminal. The third pointer, HIGH, points to the first memory location past the buffer. Lastly, the monitor maintains a byte count for the number of characters currently in the buffer. (OUTRINGBUF_FIG) shows an output ring buffer in memory just after the system was bootstrapped.

(Output Ring Buffer\OUTRINGBUF_FIG) (POSTSCRIPT\S560C3ORINGBUF_FIG.EPS\12) (Storing a Character in the Output Ring Buffer)

The output ring buffer is filled by characters that are passed by .TTYOUT, .TTOUTR, and .PRINT. Characters that echo what you type on the terminal are also stored here, including sets of backslashes to enclose text you rub out with the DELETE key on a hard copy terminal. To store a character in the output ring buffer, the monitor first compares the buffer size to the byte count to check for room. If there is no room, the character cannot be stored. This condition is sufficient to block a job if the job is doing output. (If the output is the result of echoing, it is simply discarded.) If there is enough room, the monitor checks to see if the PUT pointer is equal to the HIGH pointer. This check ensures that the PUT pointer is pointing to a location that is within the buffer. If the PUT and HIGH pointers are the same, the monitor subtracts the size of the buffer from the current PUT pointer to obtain the new PUT pointer. By doing this, the monitor (wraps) around the ring to move from the highest address in the buffer to the lowest one.

Next, the monitor moves a byte into the buffer and it increments both the PUT pointer and the byte count. (STOROUTRB_FIG) shows how characters are stored in the output ring buffer.

(Storing Characters in the Output Ring Buffer\STOROUTRB_FIG) (postscript\ml0-007375b\22.5) (Removing a Character from the Output Ring Buffer)

The terminal output interrupt service routine removes characters from the output ring buffer. If the character count is 0, the routine terminates. The routine checks to see if the GET pointer is equal to the HIGH pointer. If it is, this means it is time to (wrap) around the ring to move from the highest address in the buffer to the lowest one. The wrap routine subtracts the size of the buffer from the current GET pointer to obtain the new value of the GET pointer. This check ensures that the GET pointer is pointing to a location that is within the buffer.

Next, the output interrupt service routine removes one character through the GET pointer and prepares to send it to the terminal. It increments the GET pointer and decrements the byte count. (Input Ring Buffer)

The input ring buffer is similar to the output ring buffer except that in addition to the GET, PUT, and HIGH pointers, it has a LOW pointer that points to the first byte of the buffer. This pointer is useful when the pointers are moving backward through the buffer as a result of CTRL/U or DELETE. It indicates when to (wrap) the buffer in the reverse direction, from the lowest address to the highest.

The monitor also keeps a count of the number of lines that are stored in the input ring buffer. A (line )is any sequence of characters terminated by line feed, CTRL/Z, or CTRL/C. (Each time you issue a carriage return at the terminal, RT--11 stores two characters in the input ring buffer: a carriage return and a line feed.) In normal mode, the monitor does not pass input characters to a program until an entire line is present. This is why you can use DELETE to rub out a character and CTRL/U to remove an entire line when you are typing at the terminal. Since the monitor provides for line-by-line editing, application programs need not have this overhead themselves.

In (special mode), however, the monitor passes bytes to a program exactly as they are typed on the terminal. In the latter case, the program itself must be able to interpret editing characters, such as DELETE and CTRL/U. ()Special mode does not provide the complete transparency required to handle devices other than terminals -- such as communication lines -- through RMON's terminal service. You can achieve transparency through the multiterminal feature of RT--11 by using the (read pass-all) and (write pass-all) modes. These are described in (mtt_chap).

(INRINGBUF_FIG) shows the input ring buffer just after the system was bootstrapped.

(Input Ring Buffer\INRINGBUF_FIG) (postscript\s560c3inringbuf_fig.eps\15) (Storing a Character in the Input Ring Buffer)

When you type characters at the terminal, the keyboard interrupt service routine stores them in the input ring buffer. First, the routine checks to see if there is room in the buffer. If there is no room, it rings the terminal bell (by putting a bell character in the output ring buffer). If there is room, the routine increments the byte count, increments the PUT pointer, wrapping it if necessary, and stores the byte in the ring buffer. It also increments the line counter if the character typed is a valid line terminator. (STORINRINGBF_FIG) shows how characters are stored in the input ring buffer.

(Storing Characters in the Input Ring Buffer\STORINRINGBF_FIG) (postscript\ml0-007376b\24.5) (Removing a Character from the Input Ring Buffer)

The monitor removes characters from the input ring buffer when it processes the .TTYIN, .TTINR, .GTLIN, .CSIGEN, and .CSISPC programmed requests. First it increments the GET pointer, wrapping around the ring if necessary. Then it gets a byte from the buffer and decrements the byte count. It decreases the line count as well if the character is a valid line terminator. (High-Speed Ring Buffer)

RT--11 provides an optional, additional high-speed ring buffer that you can specify during system generation. This adds an extra input ring buffer to RMON; it adds an extra output ring buffer only if your system has multiple DL interfaces.

When the high-speed ring buffer is present, all character processing and interpretation is performed at fork level. The high-speed buffer is used to pass characters from interrupt level to fork level. The advantage of having the high-speed buffer is that it allows the monitor to handle short bursts of characters coming in at a very high rate. This is useful for systems with intelligent terminals that report their status by sending a burst of information to the host computer. It is also useful for connecting one computer to another over a serial line.

The disadvantage to using the high-speed ring buffer is that a .FORK call is required for each burst of characters, and, thus, overall terminal service may be slower. (Terminal I/O Limitations)

Terminal input and output limitations are completely separate; you use different methods to change each of them.

RT--11 accepts terminal input in either of two forms: a line at a time, or a character at a time. In line mode, characters you type at the terminal are stored in the input ring buffer until you type a valid line terminator such as carriage return, line feed, CTRL/Z, or CTRL/C. Only then does a running program receive the line of data. The factor limiting the length of the input line is the size of the input ring buffer. (The setting of the terminal right margin bears no relation to the length of the input line.) The default length is 134(10) bytes, but you can change this through the system generation process. Any attempt to insert characters beyond this limit causes the terminal bell to ring, and the extra characters are lost. The Command String Interpreter can accept only 80 characters per line. Most utility programs (PIP for example) use the CSI to obtain lines of data from the terminal, limiting the functional input line length to 80 characters.

In character mode, a running program receives each character immediately after you type it at the terminal. In this mode, you can enter any number of characters without using a line terminator.

The length of terminal output lines is not related to the size of the output ring buffer; instead, it is related to the setting of the terminal right margin. Use the SET TT: WIDTH=(n )command to adjust the right margin. (See the (SUG_BOOK) for details on SET TT: WIDTH and SET TT: CRLF.) (Control Functions)

A special aspect of RT--11's terminal service is its response to control characters that you type at the terminal. The monitor handles each character differently, depending on the special function of each one. The following sections describe the different processes involved for the various control characters. (CTRL/C)

When you type one CTRL/C at the terminal, the terminal interrupt service routine puts it into the input ring buffer, just as it would any other character. The monitor treats it as a line terminator and passes it to the running program.

However, if you type two CTRL/Cs in a row, the monitor processes them entirely differently. Instead of passing them directly to the program, the monitor aborts the running job. A program can use the .SCCA programmed request to intercept CTRL/C and prevent the abort (see the (SML_BOOK) for a description of .SCCA). (CTRL/O)

When the terminal interrupt service routine detects a CTRL/O, it never places the character in the input ring buffer, even if it is in special mode. The monitor simply toggles a flag in the impure area. (This flag is the sign bit of the output ring buffer byte count.)

The first time you type CTRL/O, the monitor echoes it, then clears the output ring buffer byte count. It empties the ring by setting the GET and PUT pointers equal to each other, and output from a running program is thrown away. This can unblock a job waiting for room in the output buffer. The next time you type CTRL/O or your job issues the .RCTRLO programmed request, normal output resumes. (CTRL/S and CTRL/Q)

RT--11 implements terminal synchronization through the characters CTRL/S and CTRL/Q. CTRL/S, or XOFF, is a signal that stops a host computer from transmitting data to a terminal. The CTRL/Q, or XON, signal causes the computer to resume the transmission. Although XOFF has many uses, RT--11 supports only the two most common.

In a typical situation, you may be doing program development using a video terminal. When you use the TYPE monitor command to review a file, the text scrolls past faster than you can read. You can press the Hold-Screen key or type CTRL/S to stop the display so that you can read it, and then again press Hold-Screen or type CTRL/Q to resume the scrolling. You initiate the XOFF yourself, in this case.

In another situation, the computer may send characters to a terminal faster than the terminal can display them. So, the terminal itself sends the XOFF signal to the computer, empties its internal silo, and sends XON when it is ready to accept more data. This procedure is transparent to you.

A flag in RMON, called XEDOFF, indicates the XOFF/XON status. Typing CTRL/S sets the flag; typing CTRL/Q clears it. When XEDOFF is set, the monitor disables terminal output interrupts and stops emptying the output ring buffer. See the (SUG_BOOK) for a description of the SET TT: NOPAGE command, which disables CTRL/S and CTRL/Q processing. (CTRL/B, CTRL/F, and CTRL/X)

These control characters have meaning in only multi-job systems. In multi-job systems, CTRL/B and CTRL/F direct terminal I/O to the correct job. CTRL/X summons the system job prompt; you supply the system job name in response to that prompt. (See (int_book) for more information on communicating with system jobs.) The CTRL/B, CTRL/F, and CTRL/X characters are not put into the input ring buffer. Instead, they are recognized by the input interrupt service routine (unless SET TT: NOFB is in effect, in which case the characters have no special meaning) and the monitor switches the set of ring buffers it is using.

The interrupt service routine uses two control words, TTOUSR and TTIUSR, to point to the impure area of the correct job. The job's identification is stored in a special buffer in the impure area. The foreground job ID is the job name followed by a right bracket (>); the background job ID is B>; the ID for a system job is its job name. When terminal I/O is directed to a different job, the new job's identification prints on the terminal. (SET Options Status Word, .TCFDF)

The word $TTCNF in RMON is a status word that indicates which terminal SET options are in effect. For multiterminal systems, each terminal control block has a status word similar to $TTCNF. $TTCNF reflects the status of the SCOPE, PAGE, FB, FORM, CRLF, and TAB options. (SETOPTSTAT_TAB) shows the meanings of the bits. Unused bits are reserved for future use by Digital. (SET Options Status Word ($TTCNF)\SETOPTSTAT_TAB) (3\6\8) (Bit\Symbol\Meaning When Set) (0\HWTAB$\SET TT: TAB option is in effect.) (1\CRLF$\SET TT: CRLF option is in effect.) (2\FORM$\SET TT: FORM option is in effect.) (3\FBTTY$\SET TT: FB option is in effect.) (4-6\\Reserved) (7\PAGE$\SET TT: PAGE option is in effect.) (8-14\\Reserved.) (15\BKSP$\SET TT: SCOPE option is in effect.)

To get the status word and current width of the terminal (in systems without the multiterminal special feature), use the following lines of code: .LIBRARY "SRC:SYSTEM" .MCALL .FIXDF .TTCDF .SYCDF .FIXDF ;RMON fixed area layout .SYCDF ;SYSCOM area .TTCDF ;Terminal Config area MOV @#$SYPTR,R5 ;Get address of fixed area MOV $TCFIG(R5),R5 ;Get address Term Config area MOV $TTCNF(R5),STATUS ;get current term config bits MOVB $TTWID(R5),WIDTH ;and current width setting STATUS: .BLKW 1 WIDTH: .BLKB 1 .END

Use the following additional line to obtain the value of the current carriage or cursor position (a value of 0 means the cursor or carriage is at the left margin): MOVB -1(Rn),POSIT (Clock Support and Timer Service\CLOCKTIMER_SEC)

You do not need a system clock in order to run RT--11 on a PDP-11 computer. However, if your computer does have a clock, RT--11 provides basic support for keeping time of day or time of year, depending on the processors. As distributed, RT--11 provides timer service with all multi-job and mapped single-job systems. Timer service for SB requires a system generation. (SB Systems Without Timer Service)

As distributed, SB systems (without the timer feature) provide basic support for a system clock. Essentially, RT--11 keeps track of the time of day, but does not provide a means to implement mark time or timed wait requests.

The bootstrap routine looks for a clock on the system. If it finds one, it sets CLOCK$ (bit 100000) in the RMON configuration word ($CNFG1) at fixed offset 300. If the clock has a CSR (Control and Status Register), the bootstrap turns the clock on. If the clock does not have a CSR (as is the case with some LSI--11 and PDP-11/23 computers), no executing routine can turn the clock on or off; there may be a switch for the clock on the front panel.

RMON maintains the time of day in a two-word counter. The counter is called $TIME (high-order word) and $TIME+2 (low-order word). RT--11 stores time of day as the number of ticks since midnight if you set the time with the monitor TIME command. If you do not set the time, RT--11 stores the number of ticks since the system was last bootstrapped.

RT--11 supports KW11--L and similar line frequency clocks, and KW11-P programmable clocks. (Support for the programmable clock is a feature that you select through system generation.) The default interrupt frequency for the clocks is the same as the line frequency. That is, the clock interrupts 60 times per second with 60 Hz power, and 50 times per second with 50 Hz power. Each time the clock interrupts, it adds one tick to the two-word time of day counter.

In a simple system with a clock and no timer service, you can use the monitor TIME command to set the time of day or get the current time. A running program can use the .GTIM programmed request to obtain the current time, and .SDTTM to set it. (Systems with Timer Service)

Timer service is supported in all multi-job systems and mapped single-job systems. It is a system generation special feature for SB systems. Timer service provides three extra programmed requests: the mark time request (.MRKT), the cancel mark time request (.CMKT), and the timed wait request (.TWAIT). In addition, another system generation special feature provides device time-out support through the time-out macro (.TIMIO) and the cancel time-out macro (.CTIMIO), which are described fully in (dev_book).

To implement timer services, RT--11 uses a timer queue, which is a linked list of queue elements, sorted in order of expiration time. The element that expires soonest is at the head of the queue. The .MRKT, .TWAIT, and .TIMIO requests use the timer queue. They schedule completion routines to be executed after a certain time interval elapses.

The monitor uses the timer queue internally to implement the .TWAIT programmed request, which causes the job that issues it to be suspended. The monitor places a timer request in the timer queue with the .RSUM programmed request code as its completion routine. The job waits until the specified time interval has elapsed. Execution resumes when the monitor itself issues the .RSUM request as a completion routine.

(TIMERQEL_TAB) shows the timer queue element. It includes the symbolic names and offsets as well as the contents of each word in the data structure. Note that time is stored as a two-word number; the number of ticks until the timed wait expires.

(Timer Queue Element Format (.QTIDF)\TIMERQEL_TAB) (3\6\6) (Name\Offset\Contents) (C.HOT\0\High-order time) (C.LOT\2\Low-order time) (C.LINK\4\Link to next queue element; 0 if none) (C.JNUM\6\Owner's job number) (C.SEQ\10\Owner's sequence number ID) (C.SYS\12\-1 if system timer element;-3 if .TWAIT element in mapped system) (C.COMP\14\Address of completion routine)

To store the time of day in all systems with timer support, RT--11 uses a two-word pseudoclock called PSCLOK (low-order word) and PSCLKH (high-order word). In this pseudoclock RMON stores the time, in ticks, that has elapsed since the system was bootstrapped. Each clock interrupt adds one tick to the counter. Two other words, $TIME and $TIME+2, contain a constant that, when added to the value of the pseudoclock, yields the current time of day.

The monitor uses the pseudoclock to implement timer requests. When a new queue element is put on the queue, the monitor adds the low-order word of the pseudoclock to the two-word time value in the queue element and it stores the resulting value, a modified time, in the queue element time words. Whenever the pseudoclock carries into the high-order word (approximately every 18 minutes), the monitor subtracts 1 from the high-order word of time in each pending timer queue element. The element expires when the high-order time word is 0 and the low-order time word is less than or equal to the pseudoclock low-order word. This method of storing time information means that handling timer requests requires only test and compare instructions, which execute rapidly, and a pass over the queue roughly every 18 minutes to correct the time words.

Every time the system clock interrupts, the monitor increments the pseudoclock. It then checks the first element in the timer queue. If the high-order word of the timer element is 0 and the low-order word is greater than the low-order word of the pseudoclock, the element has expired. The monitor removes it from the timer queue and processes it as a completion routine for the correct job. The monitor continues to check the timer queue until it finds an element that has not yet expired or the queue is empty.

There are several uses for system timer elements. If C.SYS is --1, the element is being used by .TIMIO for device time-out support, or by RMON for multiterminal device time-out. If C.SYS is --3, the element is being used to implement a .TWAIT request in a mapped system. For .MRKT and other .TWAIT requests, C.SYS is 0.

In mapped systems, completion routines that have --1 in C.SYS are run in kernel mode and the queue element is discarded. That is, the queue element is not linked into the list of available elements. If C.SYS is --3, the completion routine is still run in kernel mode. However, the queue element is linked into the available queue when the completion routine is run. (The timer queue element is used as the completion queue element.) In all other cases, the queue element is linked into the available queue and completion routines run in user mode. ((xm_chap) provides more information on extended memory systems.) (Queued I/O System\QIOSYS_SEC)

RT--11 performs I/O transfers through a queued I/O system. A job can thus have multiple I/O requests outstanding at a given time -- that is, it can issue an I/O request and still continue processing.

RT--11 implements queued I/O through the queue elements, the device handlers, and the routines in RMON. Once a device handler is in memory and the job has opened a channel, any .READ or .WRITE requests for the corresponding peripheral device are interpreted by the monitor and translated into a call to the handler. (QIOPARTS_FIG) illustrates the relationship between these components.

(Components of the Queued I/O System\QIOPARTS_FIG) (POSTSCRIPT\S560C3QIOPARTS_FIG.EPS\22) (I/O Channel Format\IOCHANL_SEC)

(IOCHANL_tab) shows the format of an I/O channel. Since each channel uses five words, the size of the monitor's channel area is five times the number of channels. RT--11 allocates 16 channels for each job. The channel area is 80(10) words long. One channel area for each job is located in the job's impure area. The .CDFN programmed request can provide more channels. (CSW_TAB) shows the significant bits in the Channel Status Word. (#)

(I/O Channel Description (.CHNDF)\IOCHANL_tab) (3\6\6) (Name\Offset\Contents) (C.CSW\###0\Channel Status Word (See (csw_tab))) (C.SBLK\###2\Starting block number of this file (0 if non-file-structured)) (C.LENG\###4\Length of file (if opened by .LOOKUP)

Size of empty area (if opened by .ENTER)) (C.USED\###6\Highest block written) (C.DEVQ\##10\I/O count (pending requests)) (C.UNIT\##11\Device unit number) (C.SIZ\##12\Symbol whose value is the size of block in bytes)

(Channel Status Word (CSW), .CSWDF\CSW_TAB) (3\6\8) (Bit\Symbol\Meaning) (0\HDERR$\Hard error bit. 0 = No error. 1 = Hard error.) (1-5\INDX$M\Index into the $PNAME table and other device tables.) (6\RENAM$\RENAME flag. 0 = No RENAME is in progress. 1 = A RENAME operation is in progress.) (7\DWRIT$\0 = The file was opened with a .LOOKUP. The monitor does not modify the directory when the file is closed. 1 = The file was opened with an .ENTER. The monitor modifies the directory when the file is closed.) (8-12\DBLK$M\The number of the directory segment containing this entry.) (13\EOF$\End-of-file (EOF) bit. 0 = No end-of-file. 1 = End-of-file was found on this channel.) (14\RONLY$\Write not allowed.) (15\ACTIV$\0 = The channel is free. 1 = The channel is active.) (I/O Queue (.QELDF)\IOQ_SEC)

The RT--11 I/O queue system consists of a linked list of queue elements for each resident device handler and a queue of available elements for each job. I/O queue elements are seven words long for unmapped systems, and 10(10) words long for mapped systems. Each job has one queue element in its impure area. One queue element is sufficient for a job that uses wait-mode I/O.

(IOQEL_tab) shows the format of an I/O queue element. It includes the symbolic names and offsets, as well as the contents of each word in the data structure. (#)

(I/O Queue Element\IOQEL_TAB) (3\6\6) (Name\Offset\Contents) (Q.LINK\###0\Link to next queue element; 0 if none) (Q.CSW\###2\Pointer to Channel Status Word in I/O channel) (Q.BLKN\###4\Physical block number) (\###6\Special function support; contents determined by device-unit support:

If 8-unit handler:

(2\8) (Q.FUNC\Function code (8 bits))

If Extended Device-Unit handler:

(2\8) (Q.FUNC\4 low bits for special function) (Q.2UNI\3 bits (MSB) of unit number) (Q.TYPE\1 bit when set means special function) ) (\###7\Unit and job number:
(2\8) (Q.UNIT\3 bits (LSB) of unit number) (Q.JNUM\4 bits job number; high bit reserved and always 0) ) (Q.BUFF\##10\User buffer address (mapped through PAR1 with Q.PAR or Q.MEM value, if mapped monitor)) (Q.WCNT\##12\Word count:

if (<) 0, operation is WRITE if = 0, operation is SEEK if > 0, operation is READ

The true word count is the absolute value of this word.) (Q.COMP\##14\Completion routine code:

if 0, this is wait-mode I/O if 1, just queue the request and return if even, this is a completion routine address) (Q.ELGH\##16\Size of I/O queue element if not mapped) (Q.PAR\##16\UMR relocation constant (mapped monitors only)) (Q.MEM\##20\PAR1 displacement bias for MMU (mapped monitors only)) (\##22\Reserved (mapped monitors only)) (Q.ELGH\##24\Size of I/O queue element if mapped)

If your program uses asynchronous I/O, you must allocate more queue elements for it by using the .QSET programmed request. Otherwise, if the program initiates an I/O transfer and no queue element is available, RT--11 must wait for a free element before it can queue up the new request. Obviously, this slows processing. The number of queue elements is always sufficient when you allocate (n )new elements, where (n )is the total number of pending requests that can be outstanding at one time for a particular program. This produces a total of (n+1 )available elements, since the original single queue element is added to the list of available elements.

The list header, called I.QHDR, is a linked list of free queue elements. It contains a pointer to an available queue element. If I.QHDR is 0, no elements are currently available. (3AVAILQ_FIG) shows an I/O queue with three queue elements, all of which are available. In this diagram, I.QHDR points to element 1. The first word in each queue element is a pointer to the next element in the queue. Thus, element 1 is linked to element 2, element 2 is linked to element 3, and element 3 is the last element in the linked list; its link word is 0.

(I/O Queue with Three Available Elements\3AVAILQ_FIG) (POSTSCRIPT\S560C33AVAILQ_FIG.EPS\20)

When a program initiates a request for an I/O operation, the monitor allocates a queue element for the request by removing it from the list of available elements. The monitor then links the element into the I/O queue for the appropriate device handler. This is accomplished by using two words in the handler header -- ddLQE and ddCQE.

The fourth word of the handler is a pointer to the last element in its queue. This pointer is called (ddLQE), where (dd )is the two-character physical device name. The fifth word of the handler, called (ddCQE), is a pointer to the current queue element.

(2AVAILQ_FIG) shows the status of the queue elements when one I/O request is pending. The monitor removes the first queue element from the available list and puts it on the device handler's queue.

(I/O Queue with Two Available Elements\2AVAILQ_FIG) (POSTSCRIPT\S560C32AVAILQ_FIG.EPS\20)

When a program requests a second I/O transfer for the same handler before the first transfer completes, the monitor removes another queue element from the available list and adds it to the queue for that handler. (1AVAILQ_FIG) illustrates this.

(I/O Queue with One Available Element\1AVAILQ_FIG) (POSTSCRIPT\S560C31AVAILQ_FIG.EPS\20)

When the transfer currently in progress completes, the monitor returns queue element 1 to the available list and initiates the transfer indicated by queue element 2. (AVAILQ1RET_FIG) illustrates the queue status when one element is returned.

(I/O Queue when One Element Is Returned\AVAILQ1RET_FIG) (POSTSCRIPT\S560C3AVAILQ1RET_FIG.EPS\20)

When the I/O operation indicated by queue element 2 finishes, the monitor returns that element to the available list, as (AVAILQ2RET_FIG) indicates. Note that the elements are now linked in a different order from that shown previously in (3AVAILQ_FIG).

(I/O Queue when Two Elements are Returned\AVAILQ2RET_FIG) (postscript\s560c3availq2ret_fig.eps\20)

In single-job systems, the monitor always puts the new queue element at the end of the device queue. By using ddLQE it can do this quickly. In multi-job systems, the device queue is sorted in order by job number, with the queue elements belonging to the highest job number appearing at the beginning of the queue and those belonging to the lowest job number at the end. The monitor puts the new element in the queue at the end of the list within a specific job group. Thus, if two requests are queued waiting for a particular handler, the request with the higher job number is honored first. At no time though, does the monitor abort an I/O transfer already in progress to start a higher priority request. The operation in progress always completes before the monitor initiates another transfer.

(DEVQ1ADD_FIG) illustrates a large queue for a device handler. The monitor adds the new element, an I/O request from the foreground job, to the queue at the end of the list of other foreground job elements. Note that the monitor does not preempt the current queue element, even though it is a request from the background job.

(Device Handler Queue when a New Element is Added\DEVQ1ADD_FIG) (postscript\s560c3devq1add_fig.eps\34) (Completion Queue)

The monitor maintains a completion queue for a job (for each job in multi-job systems), using it to serialize completion routines for the job. The head of the completion queue is called I.CMPL and it is located at offset 6 from the start of the impure area. I.CMPE, at offset 4, points to the end of the completion queue. By using I.CMPE, the monitor can quickly add a new completion queue element to the end of the queue.

A completion routine is a section of code in a program that begins to execute as soon as an asynchronous event occurs. For example, the .READC programmed request starts an I/O transfer and provides the address in the program at which execution is to begin when the I/O transfer completes. See the (SML_BOOK) for a thorough description of completion routines.

When an I/O transfer completes, the monitor checks C.COMP at offset 14(8) from the start of the I/O queue element. If the value is greater than 1, it specifies a completion routine address. The monitor then transforms the I/O queue element into a completion queue element and places it on the completion queue for the job whose job number appeared in Q.JNUM at offset 7 from the start of the I/O queue element.

(CMPLQEL_tab) shows a completion queue element. It includes the symbolic names and offsets, as well as the contents of each word in the data structure. (#)

(Completion Queue Element Format (.QCMDF)\CMPLQEL_tab) (3\6\6) (Name\Offset\Contents) (QC.LNK\0\Link to next queue element; 0 if none) (\###2-###6\Reserved) (QC.CSW\##10\Channel Status Word) (QC.OFT\##12\Offset from start of channel area to this channel) (QC.CMP\##14\Completion routine address) (.SYNCH Considerations)

The .SYNCH request also makes use of the completion queue, but it does not use an I/O queue element. When you issue a .SYNCH call, you supply as an argument the address of a seven-word area in your program, called the synch block. The synch block contains, among other things, the address of the routine to be executed. (SYNCQEL_TAB) shows a synch block, or synch queue element. When the monitor interprets your .SYNCH request, there is no current I/O queue element for it to modify. So, it uses your seven-word area as a completion queue element. The monitor puts the synch block at the head of the appropriate job's completion queue. (#)

(Synch Queue Element (.QSYDF)\SYNCQEL_tab) (3\6\6) (Name\Offset\Contents) (QS.LNK\###0\Link to next queue element; 0 if none) (QS.JOB\###2\Job number) (\###4-###6\Reserved) (QS.ID\##10\Synch ID) (QS.SYN\##12\-1 (cue that this is a synch element)) (QS.CMP\##14\Synch routine address) (Flow of Events in I/O Processing)

As the central manager of the device-independent I/O system, RMON supervises the I/O procedure, using a queue element as the communication link between a device handler and a program that requests an I/O transfer. The following sections describe the sequence of events that occur in a simple read or write operation. (Issuing the Request)

Before a program can request an I/O transfer, it has to open a new file or find an existing file on a device. This procedure sets up a channel containing five words of information about the location and length of the file. A channel number is associated with the five-word block so that you can refer to the block later by specifying this number in a single byte. The monitor uses the channel information when it needs to process an I/O request.

A running program initiates an I/O procedure by issuing a request to read from or write to a particular channel. MACRO-11 programs, for example, can use the .READ, .READW, .READC, .WRITE, .WRITW, .WRITC, and .SPFUN programmed requests. Programs written in other languages use similar statements to read and write data.

When the I/O request executes, the monitor uses the channel number the request specifies to find the corresponding device handler. Then the monitor calls its queue manager routine, which allocates a queue element from the list of available elements and fills in the necessary information.

When a queue element is not available in a single-job system, the monitor executes in a tight loop, waiting for a queue element to appear in the list of available elements. This condition is satisfied when a device interrupts and the handler issues the .DRFIN macro, which indicates that an I/O transfer is complete, and the monitor returns the queue element for that transfer to the available list.

When a queue element is not available in a multi-job system, the job requests a scheduling pass, starting with the job whose priority is immediately below that of the current job. When the original job gets a chance to run again, it first checks the available list for a free queue element. If no element is available, it requests another scheduling pass. In FB systems, there is no blocking bit associated with queue element availability. Therefore, the job that needs a queue element is not officially blocked, even though it cannot run effectively until it gets a queue element. (Queuing the Request)

All jobs (system utility programs, application programs, and language processors) and KMON run in (user state). Each job uses its own stack. In user state, a low-priority job that is running can be replaced by a higher-priority job that is runnable. Similarly, a higher-priority job that is unable to run for any reason can be replaced by a runnable lower-priority job. In single-job systems, there is only one (background) job. When it is unable to run (or when no job is able to run in a multi-job system), the monitor runs the null job, which consists of waiting for I/O to complete.

The monitor switches to (system state )to modify important data structures and to perform operations that do not run entirely within a job. Stack operations and interrupts in system state use the monitor's stack rather than a job's stack. Jobs cannot run when the monitor is in system state, and switching between lower- and higher-priority jobs is postponed until the monitor returns to user state. In system state, then, the monitor can safely modify critical data structures without the risk that another job could gain control and corrupt the same data structures. ((UANDSSTATE_SEC) describes system and user state in greater detail.)

The monitor switches to system state before it puts the new element on the device handler's queue in order to prevent interference from other jobs. However, a device interrupt could remove an element from the queue while the monitor is adding the new element and adjusting the LQE and CQE pointers. To ensure the integrity of the queue, the monitor (holds) the handler while it performs the modification.

Holding a handler prevents any other process or routine from changing the I/O queue. For example, when a device interrupts and an I/O operation completes, the handler issues a .DRFIN call to return to the monitor and remove the current queue element from the I/O queue. Depending on the type of I/O request the program issued, the current element should either go back to the linked list of available queue elements, or it should go onto the completion queue for the appropriate job. However, if the handler is held when it issues the .DRFIN, the monitor does not remove the current queue element from the I/O queue. Instead, it delays this action by setting a flag that it checks later. Similarly, when a job aborts, the abort routine holds a handler while it removes queue elements belonging to the aborted job. This prevents the monitor from starting up the next transfer queued for this device until all elements for the aborted job are gone. After the monitor holds the device handler, it checks to see if the queue is empty.

If the queue is empty, the monitor immediately clears the hold flag for the handler, and then makes the new element both the current and the last element in the queue. It increments both the count of queue elements on this channel (the C.DEVQ byte at offset 10(8) in the channel area) and the total number of I/O requests for this job. Remaining in system state, the monitor jumps to the device handler's I/O initiation section to start up the transfer. When the handler starts the transfer and returns control with a RETURN instruction, execution of the program continues in user state within the queue manager. That is, the monitor is executing (for the program).

If the queue is not empty, the monitor continues to hold the handler until it finishes modifying the queue. In single-job systems, the monitor puts the new element at the end of the queue. In multi-job systems, elements in the queue are sorted by job number, as (IOQ_SEC) explains. The monitor searches the queue from front to back, and places the new element at the end of the group of elements belonging to this job. It increments both the count of queue elements on this channel (the C.DEVQ byte at offset 10(8) in the channel area) and the total number of I/O requests for this job in I.IOCT. (For an exception to this, see the abort processing information in the (dev_book).) Since the device handler is busy, the monitor cannot start up an I/O transfer for this request, so its queue element sits in the queue. The queue manager returns to user state.

Whether or not the queue was empty, the queue manager checks to see if this request is for wait-mode I/O. If so, the program waits for the transfer to complete. If this request is not for wait-mode I/O, execution of the program continues concurrently with the I/O transfer. (Performing the I/O Transfer)

After the monitor and a device handler have started up an I/O transfer, a peripheral device performs the actual operation and interrupts when it is finished. The interrupt causes control to pass to the device handler's interrupt service section, where the code assesses the results of the I/O operation and restarts it if necessary. When the transfer is done, the handler uses the .DRFIN macro to return to the monitor and remove the current queue element from its I/O queue.

(DEVHANRMON_FIG) summarizes the relationship between the parts of a device handler and RMON. (dev_book) provides a detailed description of the internal operation of a device handler.

(Device Handler/RMON Relationship\DEVHANRMON_FIG) (POSTSCRIPT\S506C3DEVHANRMON_FIG.EPS\23) (Completing the I/O Request)

When a device interrupts, an I/O transfer completes, and the handler issues the .DRFIN call, it is the monitor that must take the appropriate action to complete the I/O procedure. In general, this means that the monitor must remove the current queue element from the handler's I/O queue and put it in the list of available elements or on the completion queue. Another I/O request could cause the monitor to hold the handler while it adds an element to the queue. In this case, the monitor simply sets a flag, dismisses the interrupt, and returns to the interrupted process, removing the element later.

When the handler is not held, the monitor first decrements the count of queue elements on this channel. When the count reaches 0, it makes runnable a job that is waiting for activity on this channel to complete. The monitor next decrements the total number of I/O requests pending for this job. Again, if this number becomes 0, it makes runnable a job that is waiting for all its I/O to complete. When either count reaches 0, it can cause the scheduler to run.

Next, the monitor removes the queue element from the handler's queue. If there is another element in the handler's queue waiting to be processed, the monitor calls the handler again to start the next operation as soon as the final disposition of the current element is resolved. The monitor raises the priority to 7 for a short time as it links the element into either the list of available elements or the job's completion queue. If the element specifies a completion routine address at Q.COMP (offset 14(8)), the monitor transforms the I/O queue element into a completion queue element and puts it at the end of the job's completion queue. Then, the monitor returns control to the process or program that was interrupted.

If the element does not specify a completion routine address, the monitor simply returns the element to the available list. Control returns to the process or program that was interrupted, or the scheduler can run. (Scheduling in Multi-Job Systems)

In a multi-job system, the monitor must arbitrate the demands of up to eight jobs for processor time, in addition to performing all its other functions. Multi-job monitors use a number of special tools to implement support for more than one job. These tools exist in single-job systems, but many of them are considerably simpler. For example, the code for context switching essentially disappears in the single-job monitor.

The (scheduler )is the part of the monitor that determines which job is eligible to run and gives control of the processor to it. The scheduler uses a simple algorithm to determine which job should run. It looks at the jobs in order from highest priority to lowest. If a job exists and is runnable, the monitor restores its context and returns to it. Status bits in a flag word (I.BLOK, at offset 36(8) from the start of the impure area) reflect the (blocking conditions )that can prevent a job from running and thereby give a lower-priority job a chance to execute. (Context switching )is the procedure through which the monitor saves a job's (context )-- its machine environment and important job-specific information -- and begins execution of another job.

All the processes that are job-dependent are kept separate from those that are monitor functions. The monitor functions are, therefore, re-entrant. Data structures that contain job-specific information are located in the (impure area )for each job, and each job has its own stack. Routines that run in a job-dependent environment, including some parts of the monitor, use the job's stack and run as part of the user job in (user state). Any routines that run outside a job's context, including interrupts, use the monitor's stack and execute in (system state). This arrangement allows the monitor to (unwind) the stack after a series of interrupts without changing jobs or stacks.

Two or more jobs can share a peripheral device, so the queued I/O system (as (QIOSYS_SEC) explains) must keep track of the priority of the job requesting an I/O transfer and act accordingly. The USR is serially reentrant -- that is, it cannot be shared by two jobs; all jobs must take turns using the USR.

Lastly, (monitor routines )check for blocking conditions, change execution state, interlock parts of the monitor to prevent corruption of important data structures, request a scheduling pass, and so on. The following sections describe the components of the monitor and provide an understanding of the scheduling process in a multi-job environment. (User and System State\UANDSSTATE_SEC)

In order to isolate job-dependent functions from monitor processes, the monitor provides two execution states: user state and system state. All jobs and KMON run in user state. Each job maintains relevant data in its impure area and uses its own stack. Context switching is enabled in user state. That is, a lower-priority job that is running can be replaced by a higher-priority job that is runnable. A higher-priority job that is unable to run for any reason can be replaced by a runnable lower-priority job.

The monitor switches to system state and the system stack for several reasons. Jobs cannot run when the monitor is in system state, and context switching is delayed until the monitor returns to user state. Consequently, the monitor can modify important data structures in system state without interference from other jobs. The monitor uses system state for operations that do not run entirely within a job context. These operations, which must not be interrupted by context switching, include the following: (UNNUMBERED) Blocking a job Starting up an I/O transfer Aborting an I/O transfer Servicing a timer request Executing the .PROTECT programmed request Executing the .CHCOPY programmed request Interlocking the USR Executing any mapping programmed request Servicing an interrupt Executing device handler code (except for .TIMIO completion routines and .SYNCH routines, which run in user state in a specific job's context)

Because it is chiefly system or monitor routines that execute in system state, monitor errors are fatal. Traps to 4 (odd address errors, and illegal or nonexistent memory addressing errors) and traps to 10 (illegal or reserved instruction errors), occurring in system state, halt the system. (Switching to System State Asynchronously)

The monitor switches from user state to system state asynchronously whenever an interrupt occurs. As a result of the interrupt the monitor may modify important data structures. The switch to system state prevents interference from a context switch while the modifications are in progress. In unmapped systems, the monitor switches from the job's stack to the system stack. In mapped systems, the monitor does not perform the stack switch because the hardware does it automatically. Subsequent interrupts that occur in system state put information on the system stack. Note that these subsequent interrupts do not cause another switch to system state. (Interrupt Level Counter)

The monitor recognizes three levels of execution state. It uses a counter called INTLVL to distinguish among the three levels. Every interrupt increments this counter. When INTLVL is -1, execution is in user state. When INTLVL is 0, execution is in system state at level zero. When INTLVL is positive, execution is still in system state, but at a deeper interrupt level. (INTLVL_TAB) summarizes the relationship between the number of interrupts pending and the execution state.

(Values of the interrupt Level Counter (INTLVL)\INTLVL_TAB) (3\10\10) (Number ofInterrupts\Value ofINTLVL\Execution State) (0\-1\User State) (1\0\System State Level Zero) (2 or more\1 or greater\Deeper System State)

(INTEFFECTS_FIG) shows how interrupts influence the flow of events in a running system.

(Interrupts and Execution States\INTEFFECTS_FIG) (POSTSCRIPT\S560C3INTEFFECTS_FIG.EPS\28)

($INTEN Monitor Routine)

When an interrupt occurs, control passes to the routine specified in the interrupt vector, and the current PS and PC are put on the job's stack. In RT--11, both device handlers and in-line interrupt service routines call the monitor at the common interrupt entry point, $INTEN. Device handlers use the .DRAST macro to call the monitor; in-line interrupt service routines use the .INTEN macro.

$INTEN is the monitor routine that performs the switch to system state. The routine assumes that it was called because an interrupt occurred. Therefore, it expects the old PS and PC to be on the job's stack. The priority should be 7, and the interrupt service routine must not have destroyed any registers between the time the interrupt occurred and the time $INTEN was called. Device handlers generally call the monitor immediately, before any processing is done. In-line interrupt service routines sometimes perform crucial operations immediately, at priority 7, then call $INTEN to lower processor priority to device priority.

$INTEN assumes it was called with the following instruction sequence, or its equivalent: JSR R5,@$INTEN .WORD ^C(<)priority*40>&340

$INTEN's first action is to save R4 on the job's stack. Since the JSR instruction already saved R5, the job's stack now appears as shown in (INTENSTACK_TAB).

(Job's Stack After $INTEN\INTENSTACK_TAB) (3\8\8) (Byte Offset\Contents\Agent) (0\R4\$INTEN) (2\R5\.DRAST macro (JSR R5)) (4\PC\Interrupt) (6\PS\Interrupt)

Next, $INTEN increments the INTLVL counter from -1 to 0. For unmapped systems, it saves the job's stack pointer in a memory location and switches to the system stack. $INTEN then lowers processor priority to device priority, and calls the device handler or interrupt service routine back as a coroutine. The interrupt service routine continues to execute in system state. (Switching to System State Synchronously)

The monitor switches to system state synchronously -- that is, without depending on an interrupt -- whenever other monitor routines need to go to system state temporarily to ensure the integrity of a certain operation. In these circumstances, the monitor routines can call the $ENSYS routine to switch to system state.

In special circumstances, a routine in a running privileged job (rather than in the monitor) needs to switch to system state. The routine can do this by artificially mimicking an interrupt and using the .INTEN macro to call the $INTEN monitor routine. ($ENSYS Monitor Routine)

The $ENSYS routine is voluntarily and synchronously called by any other monitor routine that needs to switch to system state. $ENSYS mimics an interrupt by altering the job's stack so it duplicates the stack condition immediately after an interrupt. Routines call $ENSYS by using the following instructions: JSR R5,$ENSYS .WORD (<)return address>-. .WORD 340

The instructions following the call to $ENSYS execute in system state. When the routine that must execute in system state completes, it issues an RTS PC instruction. Control then passes in user state to the routine specified in the calling sequence as ((<)return address>).

(ENSYSSTACK_TAB) shows how $ENSYS manipulates the stack to imitate an interrupt.

(Job's Stack After $ENSYS\ENSYSSTACK_TAB) (2\8) (Byte Offset\Contents) (0\R5) (2\Return address) (4\0)

(.INTEN Macro\bold)

When a routine in a user privileged job needs to switch to system state, it can use a procedure similar to $ENSYS, which is used solely by monitor routines. Essentially, the routine must push the PS and PC onto the stack, and then call the monitor $INTEN routine with a JSR R5 instruction, which puts R5 on the stack as well.

A device handler or a user program subroutine can use the following instructions to switch to system state: MOV @SP,-(SP) ;MAKE ROOM ON THE STACK CLR 2(SP) ;FAKE INTERRUPT PS = 0 .MTPS #340 ;GO TO PRIORITY 7 .INTEN 0,PIC ;ENTER SYSTEM STATE

This routine must be executed with a return address on the top of the stack. (Returning to User State)

Any routine that is executing in system state issues an RETURN instruction when it completes. The monitor (unwinds) its stack from one or more interrupts as each RETURN instruction is issued. As each routine completes, the monitor decrements the INTLVL counter.

When INTLVL is greater than 0, it indicates that the routine that was just interrupted was executing in system state. The monitor defers some special chores until it is just about to return to user state. If it is time to decrement INTLVL after a RETURN instruction, and the value of INTLVL is currently 0, the monitor knows that it is about to drop back to user state. At this time, there are four special considerations for the monitor: (UNNUMBERED) Is there an outstanding fork routine? (Fork routines run before jobs or their completion routines.) Is a scheduling pass required? (As a result of an interrupt, a job that was previously blocked may now be runnable.) Are there outstanding clock ticks? (The monitor may need to normalize its time of day counter and check the timer queue.) Is there an outstanding floating-point interrupt?

After taking these considerations into account, the monitor is ready to return to user state. It decrements INTLVL to -1 and in unmapped systems, switches to the appropriate job's stack. It restores R4 and R5, and then executes the RTI instruction to begin execution in user state. (Context Switching in Multi-Job Systems\RMONCXW_SEC)

There is no need for context switching in single-job systems, because there is only one possible job to run. In multi-job systems, context switching occurs as a result of the scheduler's command to run a different job. Its purpose is to restore the context for a job so that it can run. Context switching can occur for one of two reasons: (UNNUMBERED) The current job becomes blocked and a lower-priority job is runnable. A higher-priority job than the current job becomes runnable.

Note that the RT--11 monitor never saves a job's context simply because it switches to system state. For example, if there is only one job running, the monitor does not bother to save or restore its context. A job's context is only significant when there are two or more jobs running. RT--11 avoids the overhead of unnecessary context switching by saving and restoring the context only when it runs a different job. This is a significant saving because there are many situations in which a job is running, an interrupt triggers a switch to system state, and control passes back to the same job once the interrupt is serviced.

When the monitor saves a job's context, it preserves (does not modify) the job-dependent information on the job's stack and in the job's impure area. For mapped monitors, it saves the mapping context information in the Mapping Context Area (MCA) region in extended memory. The following information is preserved and saved in a context switch: (All Monitors) (UNNUMBERED) PS PC Stack Pointer (saved in the impure area) Registers R0 through R5 BPT vector IOT vector TRAP vector System communication area (locations 4-0-52) Location 56 (multiterminal systems only) FPP status word and floating-point registers (if floating-point hardware is present) All data specified by the program in a .CNTXSW programmed request Stack and impure area (preserved) (Mapped Monitors) (unnumbered) Kernel PAR1 Memory management fault trap vector PARs and PDRs Region control blocks and window control blocks (preserved) Memory management register 3 (MMR3)

See (XMCNTX_SEC) for a description of mapping context switching for virtual and privileged jobs.

When the monitor switches in the new job's context, it tests for a pending completion routine by checking a status bit in I.STATE. If the job's completion queue has a completion queue element on it, the monitor puts a pseudointerrupt on the job's stack to call the completion queue manager when the scheduler actually starts up the job. (Blocking Conditions)

A running job is (blocked )if it cannot proceed until some asynchronous event happens. (BLOCKCOND_TAB) lists the blocking conditions, the bits in I.BLOK (at impure area fixed offset 36(8)) that reflect the conditions, and the events that unblock a job. Unused bits are reserved for future use by Digital.

Note that there is no bit that indicates that a job is waiting for a queue element. This is a special case and the monitor handles it by checking the list of available queue elements. If there are none, it requests a scheduling pass to give a lower-priority job a chance to run. The monitor continues to check the available list until a queue element becomes available.

Job blocking exists in all systems. When a single-job system is blocked, the system idles (runs the null job) until some asynchronous event unblocks the job.

(Blocking Conditions\BLOCKCOND_TAB) (3\30\10) (Blocking Agent\I.BLOK Bit, Name, and Mask\Unblocking Agent) (Any request that uses the USR; any monitor command; an exit from a background job.\4USRWT$20\The USR release routine, DEQUSR, when the USR is free and no higher-priority job needs it.) (The keyboard monitor SUSPEND command.\6KSPND$100\KMON, when an operator issues the RESUME command.) (The .EXIT request; a job that aborts.\8EXIT$400\I/O completion from device handlers, when the job's total I/O count is 0.) (Termination of the foreground or system job.\9NORUN$1000\None. Only KMON can clear this bit by removing the job image from memory.) (The .SPND or the .TWAIT programmed request.\10SPND$2000\The monitor's .RSUM processor, when the .RSUM request executes or a .TWAIT completion routine runs.) (The .READW, .WRITW, .WAIT, .SDATW, .RCVDW, .MWAIT, and wait mode SPFUN programmed requests.\11CHNWT$4000\I/O completion from device handlers, when the I/O count for the specified channel is 0.) (The .EXIT programmed request issued from a foreground or system job; the .MTSET request issued for a DZ line; .MTDTCH issued for any terminal but a shared console.\12TTOEM$10000\The monitor's terminal service output routine, when the output ring buffer is empty or CTRL/O is typed.) (The .TTYOUT, .PRINT, .MTOUT, and .MTPRNT programmed requests.\13TTOWT$20000\The monitor's terminal output interrupt service routine, when there is room in the output ring buffer.) (The .TTYIN request (with JSW bit 6 clear); the .CSIGEN, .MTIN, .CSISPC, and .GTLIN programmed requests.\14TTIWT$40000\The monitor's terminal input interrupt service routine, when a line or character is available.) (Any request that needs a queue element when none is available.\none\The monitor's queue element return routine, when a queue element becomes free.) (How the Monitor Blocks a Job)

A job becomes blocked when it encounters any of the circumstances listed in (BLOCKCOND_TAB). These circumstances are brought about when one of the three following events occurs: (UNNUMBERED) The job issues one of the programmed requests listed in (BLOCKCOND_TAB). The SUSPEND command is issued. The job aborts.

Typically, the job, which is running in user state, issues a programmed request, such as .EXIT. The monitor remains in user state while it processes the programmed request. It then checks to see if the job is waiting because of a blocking condition. The .EXIT request, for example, must wait for all the job's I/O requests to complete before it actually terminates the job. Since waiting for all I/O to complete is a blocking condition, the monitor initiates the appropriate test to see if there are outstanding I/O requests and this job is now blocked.

The monitor calls its $SYSWT routine whenever it needs to determine whether or not a job is blocked. The monitor passes to $SYSWT a bit mask for the bit in I.BLOK corresponding to this particular condition. ((BLOCKCOND_TAB) lists the bit masks for I.BLOK; bit 8 corresponds to the .EXIT request condition.) It also passes a (decision subroutine), which is a routine that determines whether or not a job is blocked for a particular reason. There is a unique decision subroutine for each call to $SYSWT, except the waiting for a queue element condition, which has none. The decision subroutine returns with the carry bit set if the job is indeed blocked. Note that a job can be blocked for only one reason at a time.

When control eventually returns to the job, it executes within the monitor in user state at $SYSWT again. (That is, the monitor runs under the auspices of the job, executing code on its behalf.) The blocking condition must be checked once more in order to reblock a job that may have been unblocked to allow a completion routine to run. (Completion routines are part of a job, but they can run even if the main part of the job is blocked. The monitor unblocks the job to run the completion routine, then runs $SYSWT to reblock the job when the completion routine finishes. (SCHEDCMPL_SEC) discusses the implications of completion routines for scheduling.) ($SYSWT Monitor Routine)

$SYSWT is the monitor routine that decides whether or not a job is blocked. If a job is blocked, $SYSWT sets the appropriate blocking bit. The flowchart in (SYSWT_FIG) shows how $SYSWT works.

($SYSWT Monitor Routine\SYSWT_FIG) (postscript\ml0-007378b\37)

First, $SYSWT runs the decision subroutine passed by the monitor to determine whether or not the job is blocked for a specific reason (point (A )in (SYSWT_FIG)). If the job is not blocked, control returns to the job and it continues to run (point (B)). In the .EXIT case, for example, a job is not blocked if there is no pending I/O to delay the exit procedure.

If the job is blocked, $SYSWT calls $ENSYS to enter system state (point (C)). Then it sets the appropriate blocking bit. In the .EXIT example, a job is blocked if there are pending I/O requests; $SYSWT sets the EXIT$ bit, bit 8, in I.BLOK.

Next, $SYSWT runs the decision subroutine again. If the job is still blocked, $SYSWT requests a scheduler pass (point (E)). It does this to give a runnable lower-priority job a chance to execute.

If the job is no longer blocked, $SYSWT clears the blocking bit and returns (point (F)). When the monitor switches back to user state, the scheduler runs if a scheduling pass is pending. When control finally returns to this job (the one for which $SYSWT originally ran), the monitor continues execution on the job's behalf at the beginning of the $SYSWT routine (point (A)).

$SYSWT runs the decision subroutine twice because interrupts can occur while $SYSWT is running. Since an interrupt can signal the removal of a blocking condition, the job's status can change even as $SYSWT is trying to determine it.

An interrupt can occur after the decision subroutine (point (A)) declares a job to be blocked, but before $SYSWT sets the blocking bit. This time interval is shown as (Window 1) in (SYSWT_FIG). In this situation $SYSWT sets the blocking bit erroneously. But, when it runs the decision subroutine the second time, it discovers that the job is not blocked anymore. $SYSWT clears the bit and returns to the job (point (F)).

(Window 2) in (SYSWT_FIG) indicates the second time interval in which an interrupt can occur. The interrupt can remove the blocking condition immediately after $SYSWT correctly sets the blocking bit. In this case, the monitor's UNBLOK routine clears the blocking bit and requests a scheduling pass because this job became runnable. Control returns to $SYSWT (point (D)), which runs the decision subroutine again. Since the job is no longer blocked, execution leaves $SYSWT (point (F)) and the scheduler runs immediately before the monitor returns to user state. (How the Monitor Unblocks a Job)

An asynchronous event initiates the monitor's procedure to unblock a job. (BLOCKCOND_TAB) lists the significant events that can unblock a job. The completion of all I/O for a specific channel is a significant event, for example, and unblocks a job whose CHNWT$ bit is set.

When an interrupt occurs, control passes to an interrupt service routine. The interrupt routine enters system state by executing the $INTEN monitor routine. Then, the interrupt service routine assesses the meaning of the interrupt and takes appropriate action. In a device handler, for example, an interrupt can indicate that an I/O transfer is complete. The handler returns to the monitor to remove the current element from the I/O queue.

In all cases, the monitor clears the blocking bit and requests a scheduling pass if the significant event removes a blocking condition. (Scheduler Operations)

The scheduler runs only if there is an outstanding request for a scheduling pass. The monitor checks a flag byte called INTACT each time it is ready to switch from system to user state. If INTACT is not equal to zero, the scheduler runs. The scheduler exists in all systems. In single-job systems, the scheduler decides only whether to run the single background job, or to run the null job. (How the Monitor Requests a Scheduling Pass)

The monitor requests a scheduling pass by calling the $RQTSW monitor routine. It does this whenever a job's ability to run changes. (That is, whenever a running job becomes blocked, or whenever a blocked job becomes runnable.) (Characteristics of a Runnable Job)

A job that does not have any blocking bit set is runnable. However, there is one circumstance in which a job with a blocking bit set can still be runnable. A job's completion routine can run even though the mainline program is blocked. (SCHEDCMPL_SEC) discusses scheduling implications for completion routines. ($RQTSW Monitor Routine)

The $RQTSW routine posts a request for a scheduling pass for a specific job by placing a value in the flag byte, INTACT. INTACT holds the job number of the highest-priority job that requested a scheduling pass. $RQTSW ignores a scheduling request for a job if its priority is lower than that of the running job. When a job whose priority is higher than that of the running job requests a scheduling pass, $RQTSW saves the job's number in INTACT, which holds the number in the following format:

Job number INTACT = ---------- + 200 2 (How the Scheduler Works)

The scheduler runs just before the monitor returns to a job. Remember that INTLVL, the interrupt level counter, is 0 when it is time to return to user state.

A scheduling pass needed to make a job runnable happens asynchronously, as a result of an interrupt that removed a blocking condition. A scheduling pass needed to make the current job nonrunnable happens synchronously, after a job issues a programmed request, after the SUSPEND command is issued, or after a job aborts.

The scheduler runs only if INTACT is not equal to 0. When INTACT is 0, it indicates that no job changed its status, and, therefore, the same job that was interrupted should run again. When INTACT is not 0, it contains the number of the highest-priority job that changed its status. The scheduler runs only if the job number in INTACT is greater than the current number of the current job, which is kept in JOBNUM in the monitor.

The scheduler examines jobs in order of descending priority. It starts with the job whose number is in INTACT, which is not necessarily the highest-priority job in the system. As soon as the scheduler finds a runnable job, the monitor switches context and runs the job. If no jobs at all are runnable, the system idles -- that is, it runs the null job briefly, then scans all jobs again for runnability. (Implications for Completion Routines\SCHEDCMPL_SEC)

A job's completion routine can run even though the mainline program is blocked. When an asynchronous event occurs, such as the completion of an I/O request, the interrupt service routine enters system state through the $INTEN monitor routine. The device handler's interrupt service routine returns to the monitor when I/O completes, so the monitor can remove the I/O queue element from the device handler's queue. If the I/O request specified a completion routine address, the monitor changes the I/O queue element into a completion queue element and puts it on the job's completion queue. The monitor sets CPEND$ (bit 7) in the job state word (I.STATE, the first word in the job's impure area) to indicate that a completion routine is pending.

As the monitor switches from system to user state, it checks the completion pending bit in I.STATE in the job's impure area. If a routine that just ran in system state queued one or more completion routines for this job and the job is not currently running a completion routine, the monitor clears the blocking bit so the scheduler can run the job. This action permits completion routines to execute even though the mainline program is blocked.

When all the completion routines finish, the mainline program begins to execute. However, since it was recently blocked, the monitor executes for the job at the start of the $SYSWT routine. $SYSWT runs the relevant decision subroutine (the routine for the condition that originally blocked this job) and reblocks the job, if necessary. (System Jobs)

System jobs are described in detail in the (int_book). The multi-job mapped monitors are distributed with system job support, and through the system generation process, you can create such support for the FB monitor.

RMON in a system job environment is approximately 300(10) words larger than an equivalent monitor that does not support system jobs. (Characteristics)

System jobs are similar to ordinary foreground jobs in that, for both kinds of jobs, object code must be stored in relocatable object file format. In addition, system jobs are subject to the same restrictions as foreground jobs -- that is, they use restricted arithmetic with global variables. (Logical Names)

You reference a system job by its logical name, which, by default, is its file name. However, you can assign a new name when you start the job by using the SRUN monitor command with the /NAME:logical-job-name option. Logical job names must be unique. They can be alphanumeric and consist of as little as one letter or digit.

The foreground and background jobs have default logical names as well as their actual file names. For the foreground, the default logical name is (F); for the background, it is (B). (F )and (B )are permanently assigned; you cannot use them for system jobs. In addition, (EL )is the logical job name permanently assigned to the error logger system job. You can assign another logical name to the foreground job, in addition to (F )by using the FRUN monitor command with the /NAME:logical-job-name option.

The job name is stored in ASCII at offset I.LNAM in the job's impure area. (Job Number)

In a monitor without the system job feature, the background job number is 0 and the foreground job number is 2. In an environment that supports system jobs, the background job number is still 0, but the foreground job number is always 16(8). By default, each system job takes the next highest available job number. Job numbers are multiples of 2, and range from 0 to 16(8). For example, the first system job you start with the SRUN command has a job number of 14, the second system job has a job number of 12, and so on. (Priority)

A monitor that supports the system job feature provides the same event-driven, static priority scheduler that ordinary multi-job systems use. The monitor services jobs according to their priority. The background job always has priority 0, the lowest priority. The foreground job always has the highest priority, which is 7. You cannot change these assignments.

To assign a priority to a system job you can: (unNUMBERED) Use the SRUN command to start the jobs in order of their importance so that the first job you start gets priority 6, the second job gets priority 5, and so on. Explicitly specify the priority when you start the system job. Use the SRUN/LEVEL:priority command to do this. You can specify a priority level for each job in the range 1 through 6, as long as another job is not currently assigned to the level you choose.

The job number is equal to the priority times 2.

You can assign a priority only when you start a system job with the SRUN command. The priority levels do not change dynamically, and you cannot change the priority of a job while it is running. (Design Considerations)

If you are planning to write or run system jobs, you should keep in mind two major design considerations: (unNUMBERED) RT--11 provides an event-driven, static priority scheduler. Address space in low memory is at a premium, and certain parts of each job must reside in low (rather than extended) memory. (Scheduling Considerations)

The RT--11 scheduler arbitrates the demands jobs make for CPU time, awarding the use of system resources to the highest-priority job that is not blocked. Thus, a compute-bound job that is not blocked can lock out all the jobs with a lower priority. On the other hand, an I/O-bound job, such as the RT--11 QUEUE program, is often blocked waiting for I/O transfers to complete. As a result, it does not interfere significantly with lower priority jobs. If you are running a text editor in the background, for example, the fact that the QUEUE program is active is practically transparent to you.

When you design a program to run as a system job, consider carefully how often it will require system resources. Keep in mind the fact that RT--11 does not permit parallel use of the USR by two or more jobs. Write the program in such a way that it does not monopolize the system and lock out other jobs. (Space Considerations)

An unmapped environment allows the swapping out of the USR and the sliding down of KMON to extend the amount of low memory available to the programs. That provides about 20K words of memory for the foreground job and device handlers. However, low memory is the only memory available to the system.

In a mapped environment, the USR is always resident. Further, the USR cannot slide down in memory below location 40000 (into the area mapped by kernel PAR1). As a result, about 9.5K-words are available for foreground jobs, device handlers, and system jobs in a mapped environment. This smaller amount of low memory may not be a problem because extended memory is available to the system. Only a job's impure area, queue elements, channels, and (for privileged jobs) the interrupt service routines must reside in low memory. And like the USR, those four parts of a job cannot reside in the PAR1 area. The rest of the job can reside in extended memory.

The mapped monitors provide four ways to make use of extended memory for foreground and system jobs: (unNUMBERED) Run your program in the completely virtual environment, as described in (xm_chap). Use the .SETTOP feature in your program. Segment your program and use the /V linker option to make the overlays resident in extended memory. Use the memory management programmed requests in a MACRO program to increase the program's physical address space.

These methods provide the means to execute code in extended memory. They are described in detail in (xm_chap). (Programmed Requests)

Two programmed requests -- .GTJB and .CHCOPY -- have optional arguments that are meaningful only in a multi-job environment with the system job feature. The .GTJB request obtains job status information for any job in the system. You can reference another job by either logical job name or job number. The .CHCOPY request opens a channel for input, logically connecting it to a file that is currently open for another job for input or output. See the (SML_BOOK) for a detailed explanation of these requests. (Message Handling\MSGHAND_SEC)

RT--11 provides two methods for sending messages between jobs: (unnumbered) The .SDAT/.RCVD/.MWAIT programmed requests, through which foreground and background jobs can communicate with each other.

Those requests are described in the (SML_book) and their use is illustrated in the foreground/background communications example in the (int_book). The MQ pseudohandler, through which system and foreground jobs communicate. MQ is resident in the monitor and not a file on your distribution kit. (The MQ pseudohandler can be removed from the monitor through the SYSGEN procedure, but its functionality is then no longer available.)

The MQ message handler is described in this section.

The MQ handler is written as an RT--11 pseudohandler. A pseudohandler is a type of handler that does not connect to any real hardware. For most other purposes, the MQ handler performs like the other RT--11 device handlers, except that it communicates with a job, not a device. Essentially, it makes another job appear to be a peripheral device. As a result, you can open a channel to any other job by using a special .LOOKUP programmed request format, described in the (SML_BOOK). You can send a message by issuing a .WRITx request. Then you can receive a message to the job by using a .READx request. The first word of the received data buffer contains a count of the words transferred.

A further difference between other RT--11 device handlers and the MQ handler becomes apparent when a job exits (with the .EXIT programmed request) or when it aborts (because of CTRL/C or a fatal monitor error). The monitor allows outstanding I/O requests that are queued for the job to complete, but discards any messages that are queued for the job by examining the queue for the MQ handler and removing queue elements that send messages to the job. The mapped monitors normally use a special internal macro to transfer message data via the MTPD instruction. This procedure is slow, but safe, since it does not use a PAR to map any buffers. In some cases, you can use a faster, but more restrictive, transfer procedure by setting the conditional assembly symbol MQH$P2 equal to 1. When the MQ handler is assembled, the assembler will generate code which uses kernel PAR2 to map the user buffers. In this case, all the kernel PAR1 restrictions also apply to PAR2. So, the USR, queue elements, channels, and interrupt service routines cannot reside within locations 20000 through 60000 in a system that actually uses the MQ handler. Note that you cannot run completely virtual jobs when a monitor maps MQ through PAR2 (MQH$P2=1). (Monitor Commands)

The collection of monitor commands has some special features that reflect the system job environment. This section describes them briefly. See the (SUG_BOOK) for a complete description. Examples of using the following commands are located in the (int_book). (SRUN and FRUN Commands)

Use the SRUN command to start execution of a system job. You can also use the FRUN command to begin execution of a system job in the foreground partition. ()If you use SRUN or FRUN to start a foreground/system job and a job with the same name is already in memory but has finished executing, the monitor unloads the job in memory and brings in a new copy from a peripheral device. (LOAD and UNLOAD Commands)

Use the LOAD command to bring a device handler into memory and to assign ownership of a peripheral device to a specific job. Different jobs can own different units of a file-structured device. Since a foreground/system job must already be in memory before you can assign a device to it, remember to start the job with FRUN/SRUN before you use the LOAD command. If the job will not run without the handler, use the /PAUSE option with the FRUN or SRUN command. Note that you cannot assign ownership of SY or MQ.

The UNLOAD command removes a device handler, a foreground/system job, or a global region from memory. You should type a colon (:) after the name of the device handler to distinguish it from the name of a foreground/system job or a global region. If a colon is not included, the UNLOAD command attempts to unload a foreground/system job or a global region of the specified name. If none is found, the command then attempts to unload a device handler with that name. For example, RK could be both the name of a foreground/system job, a global region, and the name of a device handler. To specifically remove the device handler, issue: (.)(UNLOAD RK:)

To unload the foreground/system job or a global region, issue: (.)(UNLOAD RK) (SUSPEND and RESUME Commands)

Use the SUSPEND command to stop execution of a foreground/system job.

Use the RESUME command to continue execution of a foreground/system job that was stopped by the SUSPEND command or the /PAUSE option for SRUN or FRUN. (SHOW JOBS Command)

Use the SHOW JOBS command to display status information about all foreground/system jobs currently in the system. (Interchanging Between System Jobs\COMSYSJOB_SEC)

Interchanging between system jobs is described, with examples, in the (int_book). (Data Structures)

The following sections describe some of the RMON data structures. (Fixed Offsets)

Some words always have fixed positions relative to the start of RMON. These words are called fixed offsets. In general, they contain either status words or pointers to other significant information. The fixed offset area in RMON is located at the start of the RTDATA p-sect.

To access the fixed offsets from a running program, use the .GVAL programmed request, as follows: .LIBRARY "SRC:SYSTEM" .MCALL .FIXDF .GVAL #area,#offset

Here, (area )represents a two-word argument block, and (offset )is a byte offset from (RMONOFFS_TAB).

(RMON Fixed Offsets\RMONOFFS_TAB) (4\7\8\7) (1\Bits have meaning only if global SCCA is enabled.) (Offset\Symbol\ByteLengthin Octal\Description) (0\$RMON\4\Common interrupt entry point; contains the instruction JMP $INTEN. The .INTEN macro uses it.) (4\$CSW\240\Background job channel area (16(10) channels; each is five words long). See (iochanl_sec) for bit definitions.) (244\$SYSCH\12\Internal channel used for system functions; KMON uses this channel.) (246-254\\2\Reserved.) (256\$BLKEY\2\Segment number of the directory now in memory. A value of 0 implies that no directory is there.) (260\$CHKEY\2\Device index and unit number of the device whose directory is in memory. The low byte contains the device index into the monitor tables; the high byte is the unit number.) (262\$DATE\2\Current date value. See .DATE programmed request in (sml_book) for the date word format. (Defined by .DATDF macro in SYSTEM.MLB)) (264\$DFLG\2\(Directory operation in progress) flag. This is nonzero to inhibit CTRL/C from aborting a job while a directory operation is in progress.) (266\$USRLC\2\Address of the normal USR area. This is where the USR resides when it is called into memory by the background job and $UFLOA (location 46) is 0. In other words, the foreground job must provide space for the USR to swap. (Note: If the foreground job calls in the USR and $UFLOA is 0, the foreground job aborts.) See (scm_chap) for information on USR swapping.) (270\$QCOMP\2\Address of the I/O exit routine for all devices. The exit routine is an internal queue management routine through which all device handlers exit once the I/O transfer is complete. Any new device handlers you add to RT--11 must also use this exit location; use the .DRFIN macro in your handler to generate the exit code automatically.) (272\SPUSR\2\Special device error word. Non-RT--11 file-structured devices, such as magtape, use this word to report errors to the monitor.) (274\$SYUNI\2\The high byte contains the unit number of the system device. This is the unit number of the device from which the system was bootstrapped.) (276\$SYSVE\1\Monitor version number. You can always access the version number in this fixed offset to determine if you are using the most recent version of the software.) (277\$SYSUP\1\Monitor release level. This number identifies the release level of the monitor version specified in byte 276.) (300\$CNFG1\2\Configuration word. These 16 bits indicate information about either the hardware configuration of the system or a software condition. Another configuration word located at fixed offset 370 contains additional data. See (300CONFIG_SEC) for the meaning of each bit.) (302\\2\Reserved.(Obsolete; always 0.)) (304\$TTKS\2\Address of the console keyboard status register. The default value is 177560. See (mtt_chap) for details on changing the hardware console interface to another terminal.) (306\$TTKB\2\Address of the console keyboard buffer register. The default value is 177562.) (310\$TTPS\2\Address of the console printer status register. The default value is 177564.) (312\$TTPB\2\Address of the console printer buffer register. The default value is 177566.) (314\$MAXBL\2\The maximum file size allowed in a 0 length .ENTER programmed request. The default value is 177777(8) blocks, allowing an essentially unlimited file size. You can change this value from within a running program (although this is not recommended) or by using SIPP to patch this location.) (316\$E16LS\2\Offset from the start of RMON to the dispatch table for EMTs 340 through 357. SL and the BATCH processor uses this. (Defined by .E16DF macro in SYSTEM.MLB)) (320\$CNTXT\2\A pointer to the impure area for the current executing job. (Defined by .IMPDF macro in SYSTEM.MLB)) (322\$JOBNU\2\The executing job's number.) (324\$SYNCH\2\Address of monitor routine to handle .SYNCH requests. Your interrupt routines can issue the .SYNCH programmed request, which enters the monitor through this address to synchronize with the job they are servicing.) (326\$LOWMA\24\Start of the low-memory protection map. This map protects vectors at locations 0 through 476. See (LOWMEMBITMAP_SEC) for more information on the low-memory bitmap.) (352\$USRLO\2\A pointer to the current entry point of the USR. This may be 0, if the USR is not in memory; it may be the relocation code in USRBUF, if the USR was just brought into memory; it is the processing code in all other cases.) (354\\2\Reserved. (Obsolete; always 0.)) (356\$ERRCN\2\Low byte is the error count byte for use by system utility programs. The high byte is reserved.) (360\$MTPS\2\Entry point of the move to PS routine. The .MTPS macro calls this routine to perform processor independent moves to the Processor Status word.) (362\$MFPS\2\Entry point of the move from PS routine. The .MFPS macro calls this routine to do processor independent moves from the Processor Status word.) (364\$SYIND\2\Index into the monitor device tables for the system device. See (DEVTAB_SEC) for information on the device tables.) (366\$STATW\2\Indirect file and monitor command state word. See (366stwdf_sec) for the meaning of each bit.) (370\$CNFG2\2\Extension configuration word. This is a string of 16 bits indicating the presence of an additional set of hardware options on the system. See (370CONFG2_SEC) for the meaning of each bit.) (372\$SYSGE\2\System generation features word. The bits in this word indicate the presence or absence of some system generation special features. See (372SYSGEN_SEC) for the meaning of each bit.) (374\$USRAR\2\Size of the USR in bytes. Your program can use this information to dynamically determine the size of the region you need in order to swap the USR. (The USR is always resident in mapped systems.)) (376\$ERRLE\1\Error severity at which to abort indirect command files. You can change this level with the SET ERROR command. The default setting is ERROR. See (usererrbyte_sec) for more information.) (377\$IFMXN\1\Depth of nesting of indirect files. The default nesting level is 3. You can change this value by using SIPP to patch this location. Be sure to refer to offset 377 as a byte, not as a word.) (400\$EMTRT\2\Internal offset for use by SL and BATCH only.) (402\$FORK\2\Offset to fork processor from the start of RMON. Use the .DREND macro in your device handler to automatically set up a pointer to the fork processor.) (404\$PNPTR\2\Offset to the $PNAME table from the start of RMON.) (406\$MONAM\4\Two words of Radix-50 containing the name of the current monitor file.) (412\$HSUFF\2\One word of Radix-50 containing the suffix used by the current monitor to name device handlers. For unmapped systems, this word is normally blank. For mapped systems, it is normally (X), right-justified. This word is set up by the bootstrap; you can modify it there (see the (INS_BOOK) and the (SYG_BOOK) for details).) (414\$SPSTA\2\Status of the transparent spooler. See (414SPOOL_SEC) for the meaning of each bit.) (416\$EXTIN\1\IND stored error byte. (Defined by .UEBDF macro in SYSTEM.MLB)) (417\$INDST\1\IND control status byte. See (indsta_bit_sec) for bit definitions.) (420\$MEMSZ\2\Total physical memory available in 32-word blocks.) (422\$ELTIM\2\Reserved for error logger.) (424\$TCFIG\2\Address of terminal SET option status word. (Defined by .TTCDF macro in SYSTEM.MLB)) (426\$INDDV\2\Pointer to INDDEV (the ASCII name of the device from which IND was run). Also pointer to a 2-byte KMON/UCF interface, located in the first word under INDDEV. See (CLITYPCLIFLG_SEC) for details.

This should be considered a read-only location. If you want to change the default device from which IND is run, use the ..INDN offset as described in the (INS_BOOK).) (430\$MEMPT\2\Offset to memory control block pointers. (Defined by .MEMDF macro in SYSTEM.MLB)) (432\P1$EXT\2\Pointer to $P1EXT routine, described in (dev_book). (Defined by .P1XDF macro in SYSTEM.MLB.)) (434-444\\2\Reserved.) (446\$IMPLO\2\Pointer to word following last word in table of pointers to the impure area. See (imploc_info_sec) for more information.) (450\$KMONI\2\Indicates if KMON is the background job. If $KMONI contains nonzero value, then KMON is background job; if $KMONI contains zero, then KMON not background job.) (452\$PROGD\1\Indicates default editor for EDIT command. The bit values in $PROGD are defined in (progd_sec).) (453\$PROGF\1\Indicates which FORTRAN compiler is run by the COMPILE/FORTRAN, EXECUTE/FORTRAN, and FORTRAN commands. See (progf_sec) for bit definitions.) (454\$WILDD\1\Indicates if wildcarding (*) is implicit or must be supplied explicitly. A value of one indicates implicit wildcarding; zero indicates explicit wildcarding.) (455\$JOBS\1\Indicates the number of job slots available on the system. See (jobs_bits_sec) for bit definitions.) (456\$QHOOK\2\Pointer to RMON code hooks for UB system support handler. (Defined by .QHKDF macro in SYSTEM.MLB) ) (460\$H2UB\2\Pointer to the UB system support handler entry vector.) (462\$XOFF\2\Pointer/offset to an XON/XOFF flag.

In nonmultiterminal monitors, $XOFF points to a byte that contains the XON/XOFF flag. In multiterminal monitors, $XOFF contains the offset in the TCB to the T.STAT word. In either case, the high bit (bit 7) of the byte contains the flag. If bit 7 is set, the terminal has sent XOFF to the monitor; if clear, XON is in effect. ) (464\$RTSPC\4\Address of SEC/RETURN instructions.) (466\$CNFG3\2\Third configuration word. See (cnfg3_sec) for bit definitions.) (470\$XTTNR\2\Pointer to a routine to be called when there is no room for input characters in the terminal input buffer.) (472\$THKPT\2\Pointer to the optional multiterminal handler hooks data structure, THOOKS. See (mtty_han_hook_sec) for the THOOKS data structure.) (474\\2\Reserved. (Obsolete; always 0.)) (476\$XTTPS\2\Terminal service calls @$XTTPS before reading @$TTPS and after changing @$TTPS.) (500\$XTTPB\2\Terminal service calls @$TTPB after changing @$TTPB.) (502\$SLOT2\1\The value of $SLOT*2.) (503\\1\Reserved.) (504\$SPSIZ\2\Special device file size. Used to return value from a special directory handler to the monitor. The monitor returns this value in R0 for special directory operations.) (Configuration Word ($CNFG1)\300CONFIG_SEC)

The configuration word, $CNFG1, gives information about either the hardware configuration of the system or a software condition. (300CONFIG_TAB) lists the bits and their meanings. Unused bits are reserved for future use by Digital.

(Configuration Word (.CFIDF), Offset 300 \300CONFIG_TAB) (3\4\8) (Bit\Symbol\Meaning) (0\FBMON$\0 = SET MODE SJ in effect. 1 = SET MODE NOSJ in effect.) (1\SLKMO$\1 = KMON uses SL editor.) (2\\Reserved. (Obsolete; always 0.)) (3\BATCH$\1 = BATCH is in control of the background.) (4\SLEDI$\1 = Single-line editor is available to user programs.) (5\CLK50$\0 = 60-cycle clock 1 = 50-cycle clock The value can be controlled by SET CLOCK 50/60.) (6\HWFPU$\1 = FP11 floating-point hardware exists.) (7\FJOB$\0 = No foreground or system job is in memory. 1 = A foreground or system job is in memory.) (8\\Reserved. (Obsolete; always 0.)) (9\USR$\1 = USR is permanently resident, by issuing SET USR NOSWAP. (USR is always resident in mapped systems and this bit is always set.)) (10\QUEUE$\1 = The QUEUE program is running.) (11\LSI11$\1 = The Processor Status word on this system cannot be accessed by means of an address in the I/O page.) (12\KT11$\1 = A mapped system is running.) (13\LKCS$\1 = The system clock has a status register.) (14\KW11P$\1 = A KW11--P clock exists and programs can use it.) (15\CLOCK$\1 = There is a system clock (L clock, P clock, or 11/03--11/23 line-frequency clock).) (Low-Memory Protection Bitmap ($LOWMA)\LOWMEMBITMAP_SEC)

RT--11 maintains a bitmap that reflects the protection status of low memory, locations 0 through 477. This map is required in order to avoid conflicts in the use of the vectors. In multiuser systems, the .PROTECT programmed request allows a program to gain exclusive control of a vector or a set of vectors. When a vector is protected, RMON updates the bitmap to indicate which words are protected. If a word in low memory is not protected, it is loaded from block 0 of the executable file. If a word in low memory is protected, it is not loaded from block 0 of the file. In addition, if the word is protected by a foreground job, it is not destroyed when you run a new background program.

The bitmap is a 20(10)-byte table that starts at offset $LOWMA, 326(8) bytes from the beginning of RMON. (BITMAP_TAB) lists the offset from RMON and the corresponding locations represented by that byte. (#)

(Low-Memory Bitmap\BITMAP_TAB) (4\8\8\8) (Offset\Locations\Offset\Locations) (326\##0--17\340\240--257) (327\#20--37\341\260--277) (330\#40--57\342\300--317) (331\#60--77\343\320--337) (332\100--117\344\340--357) (333\120--137\345\360--377) (334\140--157\346\400--417) (335\160--177\347\420--437) (336\200--217\350\440--457) (337\220--237\351\460--477)

Each byte in the table reflects the status of eight words of memory. The first byte in the table controls locations 0 through 17, the second byte controls locations 20 through 37, and so on. The bytes are read from left to right. Thus, if locations 0 through 3 are protected, the first byte of the table contains 11000000. Only words are protected, not individual bytes. Thus, protecting word 0 means that bytes 0 and 1 are both protected.

If locations 24 through 27 are protected, the second byte of the table contains 00110000.

The leftmost bit of each byte represents lower memory locations; the rightmost bit represents higher memory locations. For example, to protect locations 300 through 307, the leftmost four bits of the byte at offset 342 must be set to result in a value of 360 for that byte: 11110000.

The single-job monitors do not support the .PROTECT programmed request. If you need to protect vectors in a single-job system, either use SIPP to manually modify the bitmap or dynamically modify the bitmap from within a running program.

For example, the following instructions protect locations 300 through 306 dynamically: MOV @#$SYPTR,R0 BISB #^B11110000,$LOWMA+14(R0)

The RT--11 monitor uses the low-memory bitmap to automatically protect some locations in low memory. The locations it protects are as follows: (SIMPLE) 0--16 24--32 50--66 100--102 (line-frequency clock) 104--106 (if KW11-P selected as system clock) 114--116 244--246 250--252 (for mapped systems only) The system device handler interrupt vector Interrupt vectors for loaded device handlers Vectors for all interfaces supported in a multiterminal system Vectors of device handlers that you load with the LOAD command are protected; vectors of device handlers that you bring into memory with the .FETCH programmed request are not protected. (DCL and IND Indirect File Status Word ($STATW)\366STWDF_SEC)

The DCL and IND indirect file status word, $STATW, returns information about the DCL (indirect command) and IND (indirect control) files. (366stwdf_TAB) lists the bits and their meanings. Unused bits are reserved for future use by Digital.

(DCL and IND File Status Word (.STWDF), Offset 366\366stwdf_tab) (3\10\8) (Bit Mask\Symbol\Meaning) (000001-000002\\Reserved.) (000004\IFIND$\0 = @ means indirect command file. 1 = @ means indirect control file.) (000010\IFDOL$\Dollar sign ($) entered at command line.) (000020\IFSPC$\Special chain exit.) (000040\IFBEX$\BATCH is forcing exit after error in user job.) (000100\IFRVT$\Revert to TTY input from indirect file.) (000200\IFGTC$\CTRL/C seen in indirect file while GTLIN$ bit set in $JSW.) (000400\IFACT$\Indirect file active.) (001000\IFCHA$\Chain to indirect file.) (002000\IFEKO$\Don't echo indirect file lines.) (004000\IFCTC$\CTRL/C seen in indirect file.) (010000\IFDAT$\Data in indirect file buffer above the USR.) (020000\IFEOF$\EOF in indirect command file.) (040000\IFABT$\Abort indirect command file input.) (100000\IFINP$\Input from indirect command file.) (Second Configuration Word ($CNFG2)\370CONFG2_SEC)

The second configuration word, $CNFG2, indicates the presence of an additional set of hardware options on the system. (370CONFG2_TAB) lists the bits and their meanings. Unused bits are reserved for future use by Digital.

(Extension Configuration Word (.CF2DF), Offset 370 \370CONFG2_TAB) (3\4\8) (Bit\Symbol\Meaning) (0\CACHE$\1 = Cache memory is present.) (1\MPTY$\1 = Parity/ECC memory is present.) (2\SWREG$\1 = A readable switch register is present.) (3\LIGHT$\1 = A writeable console display register is present.) (4\LDREL$\1 = A handler used by LD may have been unloaded.) (5\XITSW$\1 = Do not swap user code or exit.) (6\BUS$\See below and (confg2_bus_tab).) (7\CIS$\1 = The Commercial Instruction Set (CIS) option is present.) (8\EIS$\1 = The Extended Instruction Set (EIS) option is present.) (9-10\\Reserved. (Obsolete; always 0.)) (11\KXCPU$\See below and (confg2_bus_tab).) (12\GSCCA$\1 = Global SCCA support in monitor.) (13\PROS$\See below and (confg2_bus_tab).) (14\PDP70$\1 = The processor is a PDP-11/70.) (15\PDP60$\1 = The processor is a PDP-11/60.) (Determining Processor Bus Structure)

Three bit masks in $CNFG2 indicate the type of processor on which RT--11 is running: BUS$, PROS$, and KXCPU$. Programs that previously determined if RT--11 is running on a CTI Bus machine by testing only PROS$, along with other bus determinations, should use the following algorithm. The algorithm establishes the correct bit mask and then tests values within that mask for relevant $CNFG2 values.

Given the following symbol values: BUS$M = 020100 mask for bus bits BUS$U = 000000 value for UNIBUS BUS$Q = 000100 value for Q-bus BUS$C = 020000 value for CTI Bus BUS$X = 020100 value for other bus or busless system

Use the following code fragment: .GVAL #AREA,#$CNFG2 ; Put value of $CNFG2 in R0 BIC #^CBUS$M,R0 ; Relevant mask CMP #BUS$U,R0 ; Look for UNIBUS BEQ UNIBUS ; If equal, then UNIBUS CMP #BUS$Q,R0 ; Look for Q-bus BEQ Q-bus ; If equal, then Q-bus CMP #BUS$C,R0 ; Look for CTI Bus BEQ CTI Bus ; If equal, then CTI Bus CMP #BUS$X,R0 ; Look for other bus or ; busless BEQ UNKBUS ; If equal, then KXJ-11 if ; KXCPU$ is set ; Done

(Determining Processor Bus Structure\confg2_bus_tab) (4\8\10\4) (Symbol\Bit Mask\\Meaning) (BUS$\000100\0 =\RT-11 is running on UNIBUS or CTI Bus machine.

If PROS$ = 0, then UNIBUS machine

If PROS$ = 1, then CTI Bus machine) (\\1 =\RT--11 is running on Q-bus machine, a machine with an unknown bus (not CTI Bus, Q-bus, or UNIBUS), or a KXJ--11 processor.

If PROS$ = 0, then Q-bus machine

If PROS$ = 1, then unknown bus machine; check KXCPU$) (KXCPU$\004000\0 =\RT--11 is not running on a KXJ-11 processor; check BUS$ and PROS$.) (\\1 =\RT--11 is running on a KXJ-11 processor.) (PROS$\020000\0 =\RT-11 is running on a Q-bus or UNIBUS machine; check BUS$.) (\\1 =\RT--11 is running on a CTI Bus, unknown bus, or KXJ--11 bus machine; check BUS$ first, then check KXCPU$.) (System Generation Features Word ($SYSGE)\372SYSGEN_SEC)

The system generation features word, SYSGEN, indicates which major system generation features are present. (SYSGEN372_TAB) lists the meaning of each bit. Unused bits are reserved for future use by Digital. In addition, do not set or clear any bits in this word yourself.

Note that the values of the low byte must correspond to the conditional variables you use when you assemble your device handler files. Attempts to use handlers that are not compatible with the monitor cause the (?KMON-F-Conflicting SYSGEN options) error message to appear.

(System Generation Features Word (.SGNDF), Offset 372 \SYSGEN372_TAB) (3\6\8) (Bit\Symbol\Meaning) (0\ERLG$\1 = The error logging feature is present.) (1\MMGT$\1 = The memory management feature is present.) (2\TIMIT$\1 = The device I/O time-out feature is present.) (3\RTEM$\1 = This is an RTEM--11 system.) (4-7\\Reserved.) (8\FPU11$\1 = FPU support selected during system generation.) (9\MPTYS$\1 = The memory parity feature is present.) (10\TIMER$\1 = The SB mark time feature is present.) (11-12\\Reserved.) (13\MTTY$\1 = The multiterminal feature is present.) (14\STASK$\1 = The system job feature is present.) (15\TSXP$\Running under an operating system other than RT--11.) (Transparent Spooler (SPOOL) Status Word ($SPSTA)\414SPOOL_SEC)

The transparent spooler status word, SPSTAT, indicates the status of the transparent spooler (SPOOL). (SPOOL414_TAB) indicates the meaning of each bit. Unused bits are reserved for future use by Digital.

(Transparent Spooler Status Word (.SPLDF), Offset 414 \SPOOL414_TAB) (3\6\8) (dag\The meaning of the spooler unit field (SP$UNI) is determined by the bit mask in (spool_op_field_tab): (unnumbered) If SP$OPR is SP$NXT, SP$OFF, SP$ON, or SP$KIL, then SP$UNI is the SP unit number. If SP$OPR is SP$ABT, then SP$UNI is the aborting job number. If SP$OPR is SP$EXI, then SP$UNI has no meaning. ) (Bit\Symbol\Meaning) (0-2\SP$UNI(dag)\Unit number for SET commands.

The meaning of the unit number bits is tied to SP$OPR as shown below.) (3-6\SP$OPR\Type of operation to perform. See (spool_op_field_tab).) (7\SP$ACT\Spooler active.) (8-10\SP$NFL\Type of flag page support. See (spool_flag_tab).) (11\SP$SHO\1 = Display spooler status.) (12\SP$SCN\1 = Print screen (CTI bus-based computers only).) (13\SP$GTM\1 = Date and time request for flag pages.) (14\SP$IEN\1 = Fake interrupt enable.) (15\SP$ERR\1 = Error bit (set by SPOOL).)

(Spool Operation Type Field (SP$OPR)\spool_op_field_tab) (3\6\6) (BitMask\Symbol\Meaning) (0001\SP$NXT\Move to start of next file.) (0010\SP$OFF\Set spooler unit off.) (0100\SP$ON\Set spooler unit on.) (1000\SP$KIL\Remove spooled output from work file.) (0110\SP$ABT\Spooler aborted.) (1110\SP$EXI\Cause spooler shutdown.)
(Spool Flag Page Support Field (SP$NFL)\spool_flag_tab) (3\6\6) (BitMask\Symbol\Meaning) (000\SP$DEF\Default number of flagpages.) (111\SP$0\No flagpages.) (xxx\\This number of flagpages, where (xxx) is in the range 1-6.) (IND Control Status Byte ($INDST)\indsta_bit_sec)

The following bits are defined in the IND control status byte:

(IND Control Status Byte (.INDDF), Offset 417 \indsta_bit_tab) (3\6\8) (Value\Symbol\Meaning) (001\\Reserved.) (002\\Reserved.) (004\CC$IND\Set if double CTRL/C abort is disabled by IND.) (010\CC$GBL\Set if double CTRL/C is disabled by global .SCCA.) (040\LN$IND\Set if current line passed by IND.) (100\IN$RUN\Set if KMON issued RUN of IND.) (200\IN$IND\Set if IND active.) (Pointer to the End of the Impure Area ($IMPLO)\imploc_info_sec)

Subtract 2 from the contents of $IMPLO--2 to return a pointer to the foreground job impure area if a foreground job is loaded, or a 0 if no foreground job is loaded.

The lowest word in the table of pointers to impure areas contains --1. The word above the word containing --1 is the pointer to the background job impure area. The pointers to the impure area for any system jobs supported by the monitor are located between the pointers to the foreground and background impure areas. (Default Editor ($PROGD)\progd_sec)

The following bits are defined in $PROGD. The high byte is undefined. All unused bits are reserved by Digital.

(Default Editor (.PGMDF), Offset 452 \progd_tab) (3\8\8) (Value\Symbol\Meaning) (022\$$KED\SET EDIT KED is effect.) (023\$$K52\SET EDIT K52 is effect.) (024\$$KEX\SET EDIT KEX is effect.) (026\$$EDIT\SET EDIT EDIT is effect.) (027\$$TECO\SET EDIT TECO is effect.) (Default FORTRAN Compiler ($PROGF)\progf_sec)

The following bits are defined in $PROGF. The high byte is undefined. All unused bits are reserved by Digital.

(Default FORTRAN Compiler, Offset 453\progf_tab) (3\8\8) (Value\Symbol\Meaning) (000006\$$FORT\SET FORTRA F4 is in effect. The default.) (000030\$$F77\SET FORTRA F77 is in effect.) (Job Slots on the System ($JOBS)\jobs_bits_sec)

The values in $JOBS for the distributed monitors are as follows. All unused bits are reserved by Digital.

(Job Slots on the System, Offset 455\jobs_bits_tab) (2\6) (Value\Meaning) (001\1 job slot (distributed single-job monitor).) (002\2 job slots (distributed FB monitor).) (010\8 job slots (distributed multi-job mapped monitors).) (Third Configuration Word ($CNFG3)\cnfg3_sec)

The following bits are defined in the third configuration word. All unused bits are reserved by Digital.

(Third Configuration Word (.CF3DF), Offset 466 \cnfg3_tab) (3\8\8) (Value\Symbol\Meaning) (000004\CF3.IM\Each job possesses an impure area.) (000010\CF3.VB\RUN is SET to VBGEXE.) (000020\CF3.UI\The UB system support handler is set to not install.) (000040\CF3.UA\The UB system support handler is active (set only when CF3.UB is set).) (000100\CF3.UB\The UB system support handler is loaded in memory.) (000200\CF3.DM\At least one handler installed on the system uses DMA (direct memory access).) (000400\CF3.64\RMON has been generated for extended device-unit support and the $PNAM2 table exists in RMON.) (001000\CF3.AT\$JBREL exists in monitor.) (002000\CF3.OW\$OWNER table exists in RMON.) (004000\CF3.US\Support for UB system support handler in the PNAME table from BSTRAP.) (010000\CF3.1S\RMON supports exactly one DL11 console interface.) (020000\CF3.AS\Multiterminal monitor supports asynchronous terminal status (AST) word.) (040000\CF3.HI\The hardware supports separated (I & D) address space and Supervisor Mode.) (100000\CF3.SI\The monitor supports separated (I & D) address space and Supervisor Mode.) (KMON/UCF Interface Word (CLI.FL/CLI.TY)\CLITYPCLIFLG_SEC)

The KMON/UCF interface is a single word consisting of the following bytes: CLI.FL (the low byte) and CLI.TY (the high byte). This word is located immediately below INDDEV, the word pointed to by offset $INDDV. All unused bits and values are reserved for Digital.

(CLI.FL (.CLIDF)\CLIFLG_TAB) (3\6\8) (Bit\Symbol\Meaning) (7\UCF.KM\Set by UCF to pass a command to KMON. Cleared by KMON.) (4-6\\Reserved.) (3\UCL.ON\1 = Do UCL parsing.) (2\CCL.ON\1 = Do CCL parsing.) (1\DCL.ON\1 = Do DCL parsing.) (0\UCF.ON\1 = Do UCF parsing. Set by UCF.)
(CLI.TY (.CLIDF)\CLITYP_TAB) (3\6\8) (Value\Symbol\Meaning) (0\UCF.RN\The program is running as UCF.) (1\DCL.RN\The program is running from DCL.) (2\CCL.RN\The program is running from CCL.) (3\UCL.RN\The program is running as UCL.) (4-255\\Reserved.) (Impure Area)

The impure area is an area of memory where the monitor stores all job-dependent data. For each job, the impure area contains job-specific information, such as terminal ring buffers and I/O channels. The monitor sets up the impure area and maintains its contents.

The impure areas contain all the information the monitor requires to run a job. The information stored in the impure area is job-specific. The impure area for the background job is located in the p-sect RMON in the Resident Monitor and it is permanently resident. In a multi-job system, the impure area for a foreground or system job is located in memory below the start of the job itself. The size of the impure area is the value in the global symbol FMPUR, which you can find by looking at your monitor's link map.

The monitor maintains a table of one-word pointers to the impure areas of all jobs in the system. This table is located at $IMPUR and is either eight, two, or one word(s) long, depending on whether the monitor is single-job or multi-job, and whether system job feature is present or not.

In RT--11, a background job is always present. It is KMON if no other background job exists. In a multi-job system, the foreground or system job impure area pointer may be 0 if no such job is in memory. When you issue an FRUN command, the monitor creates an impure area for the foreground job. Similarly, the SRUN command creates an impure area for a system job. In both cases, the monitor also updates the job's $IMPUR entry to point to the impure area.

The contents of the impure area are the same for the background and the foreground jobs, as shown in (IMPUREAREA_TAB). The offset in the table is the offset from the start of the impure area itself. Beginning at I.JID, the contents of the impure area depend on which system generation features you select.

(Impure Area (.IMPDF)\IMPUREAREA_TAB) (4\7\8\7) (Offset\Symbol\ByteLength(Octal)\Description) (0\I.STATE\2\Job state word bits. See (ISTATE_TAB) for the meaning of each bit.) (2\I.QHDR\2\Head of available queue element linked list.) (4\I.CMPE\2\Last entry in the completion queue.) (6\I.CMPL\2\Head of the completion queue.) (10\I.CHWT\2\Pointer to channel during I/O wait. When a job is waiting for I/O on a channel to complete, the address of that channel area is stored here.) (12\I.PCHW\2\Saved I.CHWT during execution of a completion routine.) (14\I.PERR\2\Error bytes 52 and 53 saved during completion routines.) (16\I.TTLC\2\Terminal input ring buffer line count (for non-multiterminal systems).) (16\I.CNSL\2\Multiterminals only: Pointer to terminal control block (TCB) for this job's console terminal.) (20\I.PTTI\2\Previous terminal input character (for non-multiterminal systems).) (20\unused\2\Multiterminals only: reserved.) (22\I.TID\2\Pointer to job ID area, later in impure area.) (24\I.JNUM\2\Job number of the job that owns this impure area.) (26\I.CNUM\2\Number of I/O channels defined. The default is 16(10); you can use .CDFN to define more.) (30\I.CSW\2\Pointer to the job's channel area.) (32\I.IOCT\2\Total number of I/O operations outstanding.) (34\I.SCTR\2\Suspension counter. A value less than 0 means the job is suspended.) (36\I.BLOK\2\Job blocking bits. See (IBLOKBITS_TAB) for the meaning of each bit.) ((4\LEFT)The following offsets are not guaranteed to remain constant from release to release. In fact, since the pointers and status words can vary depending on the special features you select through system generation, you should consult the link map from the monitor assembly to find the correct offsets for your system. Some items, such as the input and output ring buffers, have a variable length.) (-\I.JID\10\Job's terminal prompt string. If the system job feature is present, the length of I.JID is 14(8).) (-\I.LNAM\6\System jobs only: Logical job name in ASCII.) (-\I.NAME\10\File name and file type, in Radix-50, of the running job.) (-\I.SPLS\2\Pointer to nonlinked .DEVICE list.) (-\I.TRAP\2\Address of trap to 4 and 10 routine defined via .TRPSET.) (-\I.FPP\2\FPU only: Address of FPP exception routine defined via .SFPA.) (-\I.SPSV\2\Mapped only: Bottom of saved SP data.) (-\I.SWAP\4\Multi-job only: Pointer to extra swap information specified in the .CNTXSW programmed request.) (-\I.SP\2\Multi-job only: Saved stack pointer.) (-\I.BITM\24\Multi-job only: Bitmap for protection.) (-\I.CLUN\2\Multiterminals only: LUN of job's console.) (-\I.TTLC\2\Multiterminals only: Terminal input ring buffer line count.) (-\I.IRNG\2\Input ring buffer low limit.) (-\I.IPUT\2\Input PUT pointer for interrupts.) (-\I.ICTR\2\Input character count.) (-\I.IGET\2\Input GET pointer for .TTYIN.) (-\I.ITOP\2\Input ring buffer high limit.) (-\------\TTYIN\Input ring buffer.) (-\I.OPUT\2\Output PUT pointer for .TTYOUT.) (-\I.OCTR\1\Output character count.) (-\I.CTLO\1\^C flag) (-\I.OGET\2\Output GET pointer for interrupts.) (-\I.OTOP\2\Output ring buffer high limit.) (-\------\TTYOUT\Output ring buffer.) (-\I.QUE\QWDSIZ\The initial queue element; 16(8) bytes (24 bytes if mapped).) (-\------\4\Multi-job only: First internal message channel words.) (-\I.SERR\2\(All monitors) The third word of the message channel is used as the hard/soft error flag.) (-\I.MSG\4\Multi-job only: Further internal message channel words.) (-\I.TERM\2\Terminal status word. (.TSTDF)) (-\I.TRM2\2\Terminal status word 2. (.TS2DF)) (-\I.SCCA\2\CTRL/C terminal status word set via .SCCA. (.TASDF)) (-\I.SCC1\2\Mapped only: PAR1 value of I.SCCA.) (-\I.DEVL\2\Pointer to linked .DEVICE list.) (-\I.FPSA\2\Mapped and FPU only: Pointer to FPU save area, later in impure area.) (-\I.SCOM\36\Mapped only: System communication save area (for non-multiterminal systems).) (-\I.SCOM\40\Mapped and multiterminals only: System communication save area.) (-\I.RSAV\20\Mapped only: Register save area.) (-\I.MPTR\2\Mapped only; Pointer to job's mapping context area (MCA) in extended memory. The PAR1 value. See (cmpdf_tab) for contents of the mapping context area.) (-\I.MPB\16\Mapped only; Temporary copy of the job's parameter block for a PLAS request; contains an RDB or WDB, depending on type of request.) (-\I.PLSP\2\Fully mapped (ZB or ZM) only; D-space / I-space 'pass' parameter for PLAS requests.) (-\I.CMAP\2\Fully mapped (ZB or ZM) only; .CMAP request status. See (cmpdf_tab) for bit definitions.) (-\I.WPTR\2\Mapped only: Pointer to window control blocks, at I.WNUM later in impure area.) (-\I.RGN\RGWDSZ\Mapped only: Region control blocks.) (-\I.WNUM\2\Mapped only: Number of window blocks.) (-\------\WNWDSZ\Mapped only: Window control blocks.) (-\I.SSP\2\Fully mapped (ZB or ZM) only; saved Supervisor Mode stack pointer.) (-\I.FSAV\62\Mapped and FPU only: FPU save area.) (-\I.VHI\2\Mapped only: Virtual high limit of job; nonzero if linker /V option used.) (-\I.VSTP\2\Mapped only; used for nonvirtual .SETTOP; maximum high limit for completely virtual jobs.) (-\I.ECTR\2\.SPCPS only: EMT depth counter.) (-\I.SPCP\2\.SPCPS only: Address of .SPCPS blocks.) (-\I.SPC1\2\Mapped and .SPCPS only: PAR1 for .SPCPS blocks.) (-\I.SCHP\2\Pointer to the job's system channel. The monitor uses this channel for its own calls, such as .DSTATUS.) (-\I.SYCH\14\The job's system channel, for all foreground and system jobs. The background job's channel is in the fixed offset area of RMON.) (-\IMP.SZ\0\Symbol whose value is the length in bytes of impure area.) (Job State Word Bits)

The job state word, I.STATE, indicates status information about a job. (ISTATE_TAB) shows the meaning of each bit. Unused bits are reserved for future use by Digital.

(Job State Word Bits, Offset 0 (.ISTDF)\ISTATE_TAB) (3\8\7) (Mnemonic\Bit\Meaning When Set) (ABPND$\0\An abort has been requested for this job.) (BATRN$\1\BATCH or Error Logger is running for this job.) (CSIRN$\2\The CSI is running for this job.) (USRRN$\3\The USR is running for this job.) (-\4\Reserved.) (ABORT$\5\The job is being aborted.) (-\6\Reserved.) (CPEND$\7\This job has a completion routine pending.) (-\8-10\Reserved.) (LOAD$\11\Mapped only; foreground or system job is in the load phase; the job has not yet started running. Context switch code in RMON will initialize mapping and clear LOAD$ bit.) (WINDW$\12\This is a virtual job.) (VRUN$\13\This job is running under VBGEXE.) (VLOAD$\14\This job is being loaded under VBGEXE.) (CMPLT$\15\A completion routine is running for this job.)

(Job Blocking Bits\bold)

The job blocking word, I.BLOK, indicates which condition is blocking a job. Unused bits are reserved for future use by Digital. (IBLOKBITS_TAB) shows the meaning of each bit.

(Job Blocking Bits, Offset 36 (.IBKDF)\IBLOKBITS_TAB) (3\8\7) (Mnemonic\Bit\Meaning When Set) (-\0-3\Reserved.) (USRWT$\4\The job is waiting for the USR.) (-\5\Reserved.) (KSPND$\6\The job is suspended as a result of the SUSPEND command.) (-\7\Reserved.) (EXIT$\8\The job is waiting for all I/O to complete.) (NORUN$\9\The job is not running (that is, it is a foreground or system job).) (SPND$\10\The job is suspended.) (CHNWT$\11\The job is waiting for I/O on a channel to complete.) (TTOEM$\12\The job is waiting for the output ring buffer to be empty.) (TTOWT$\13\The job is waiting for room in the output ring buffer.) (TTIWT$\14\The job is waiting for terminal input.) (-\15\Reserved.) (Mapping Context (I.CMAP) Word Bits)

The I.CMAP word is written by the .CMAP programmed request and shows the status of a job's mapping context. The job's mapping context is used by the system to determine which WCBs, RCBs, PARs and PDRs, are supported for which processor modes. That information is used when context switching those structures in and out of the processor's memory management unit.

Context switching is discussed in detail in (xm_chap).

The word is divided into 4 fields. Each field tracks a particular aspect of a job's mapping context.

The following bits are defined; any undefined bits are reserved by Digital.

(Change Mapping Context (I.CMAP) Word Bits (.CMPDF)\cmpdf_tab) (3\8\8) (Bit Mask\Symbol\Meaning) (000001\CM.PR0\Separate PAR0 mapping.) (000002\CM.PR1\Separate PAR1 mapping.) (000004\CM.PR2\Separate PAR2 mapping.) (000010\CM.PR3\Separate PAR3 mapping.) (000020\CM.PR4\Separate PAR4 mapping.) (000040\CM.PR5\Separate PAR5 mapping.) (000100\CM.PR6\Separate PAR6 mapping.) (000200\CM.PR7\Separate PAR7 mapping.) (\\) (001400\CM.S\Supervisor mode I & D Separation Field.) (001000\CM.SII\Nonseparate Supervisor I & D space.) (001400\CM.SID\Separate Supervisor I & D space.) (\\) (002000\\Reserved.) (\\) (030000\CM.SUP\Supervisor mode context switching support field.) (020000\CM.NOS\No Supervisor mode context switching.) (030000\CM.JAS\Supervisor mode context switching.) (\\) (140000\CM.U\User mode I & D separation field.) (100000\CM.UII\Nonseparate User I & D space.) (140000\CM.UID\Separate User I & D space.) (Device Tables\DEVTAB_SEC)

The following tables in RMON keep track of the devices on the RT--11 system. The size of each table is determined by the number of device slots ($SLOT) built into the system. The value for $SLOT*2, used to calculate the size of each table, is located at $SLOT2 (RMON fixed offset 502). The relative location of each device handler in each table is the same, except for tables $UNAM1 and $UNAM2, as explained in the following sections. Therefore, pertinent information for a particular handler can be returned by sequentially indexing into each table (at the same offset from the start of the table).

(3\8\14) (Table\Size\Contents) ($OWNER:\(<)$SLOT*2>*2\Device ownership; omitted in single-job monitors and can be removed from multi-job monitors through system generation.) ($UNAM1:\(<)$SLOT*2>+4\Physical device name.) ($UNAM2:\(<)$SLOT*2>+4\Logical device name.) ($PNAME:\$SLOT*2\Installed handlers.) ($ENTRY:\(<)$SLOT*2>+2\Handler addresses. Last word contains -1 and indicates end of table.) ($STAT:\$SLOT*2\DSTATUS value.) ($DVREC:\$SLOT*2\Handler disk blocks.) ($HSIZE:\$SLOT*2\Handler memory size.) ($DVSIZ:\$SLOT*2\Handler device blocks.) ($PNAM2\(<)$SLOT*2>+2\Physical device name for extended-unit (single-letter) device names. Last word contains default device name, if assigned.)

Typically, you would use the table in the following manner: (numbered) Find the value located in fixed offset $SLOT2. Do a .CSTAT and use the mask to isolate the index, INDX$M, for the handler in question. Use this value to index into the $PNAME table for that handler. Index into the various tables, using that value and $SLOT2. ($PNAME Table)

The permanent name table is called $PNAME. It is the central table around which all the others are constructed. The total number of entries is fixed at assembly time; you can allocate extra slots then. Entries are made in $PNAME at monitor assembly time for each device that is built into the system.

Each table entry consists of a single word that contains the Radix-50 code for the two-character physical device name. (For example, the entry for TS11 is .RAD50 /MS/.) The TT device must be first in the table; the system device is always second. After that, the position of a device in this table is not critical. Once the entries are made into this table, their relative position (that is, their order in the table) determines the general device index used in various places in the monitor. Thus, the other tables (other than $UNAM1 and $UNAM2) are organized in the same order as $PNAME. The offset of a device name entry in $PNAME serves as the index into the other tables for a given device.

The bootstrap checks the system generation parameters of a handler with those of the current monitor (by inspecting the low byte of $SYSGE at RMON fixed offset 372), and zeroes the $PNAME entry for that device if the parameters do not match. The INSTALL command cannot install a handler whose conditional parameters do not match those of the monitor. ($STAT Table)

The device status table is called $STAT. Entries to this table are made at assembly time for those devices that are permanently resident in the RT--11 system, such as TT. When the system is bootstrapped, the entries for all other devices are filled in when each handler is installed by the bootstrap or the INSTALL command. Each device in the system has a status entry in its corresponding slot in $STAT. The device status word identifies each physical device and provides information about it, such as whether it is random or sequential access. The device status word is part of the information returned to a running program by the .DSTATUS programmed request. See (dev_book) for details on the status word. ($DVREC Table)

The device handler block number table is called $DVREC. Entries to this table are made at bootstrap time for devices that are built into the system, and at INSTALL time for additional devices. The entries are the absolute block numbers where each of the device handlers resides on the system device. Since handlers are treated as files, their positions on the system device are not necessarily fixed. Thus, each time the system is bootstrapped, the handlers are located and $DVREC is updated with their locations on the system device. The pointer in $DVREC points to block 1 of the file. (Because handlers are linked at 1000, the actual handler code starts in the second block of the file.) A zero entry in the $DVREC table indicates that no handler file for the device in that slot was necessary (such as TT). (Note that if block 0 of the handler file resides on a bad block on the system device, RT--11 cannot install or fetch the handler.) Note also that 0 is a valid $DVREC entry for permanently resident devices. ($ENTRY Table)

The handler entry point table is called $ENTRY. Entries in this table are made whenever a handler is loaded into memory by either the .FETCH programmed request or by the LOAD command. The entry for each device is a pointer to the fourth word of the device handler in memory. The entry is zeroed when the handler is removed by the .RELEASE programmed request or by the UNLOAD command.

Some device handlers are permanently resident. These include the system device handler and the TT handler. The $ENTRY values for such devices are fixed at boot time. ($DVSIZ Table)

Each entry in the $DVSIZ table contains the size of a device in blocks. The value is 0 for a non-file-structured device. For devices that accept multisize volumes, the entry contains the size of the smallest possible volume. ($HSIZE Table)

Each entry in the $HSIZE table contains the size of a device handler in bytes. This value indicates the amount of memory needed to load each handler. ($UNAM1 And $UNAM2 Tables)

The tables that keep track of logical device names and the physical names that are assigned to them are called $UNAM1 and $UNAM2. Entries are made in these tables when the ASSIGN command is issued. The physical device name is stored in $UNAM1 and the logical name associated with it is stored in the corresponding slot in $UNAM2. When the system is first bootstrapped, there are two assignments already in effect that associate the logical names DK and SY with the device from which the system was booted.

The value of $SLOT, which is determined at system generation time, limits the total number of logical name assignments. Thus, you can issue one ASSIGN command for each device slot in your system. (The initial SY and DK assignments at bootstrap time do not come out of your total.)

The $UNAM1 and $UNAM2 tables are not indexed by the $PNAME table offset. ($OWNER Table)

The device ownership table is called $OWNER and it is used in the multi-job environments to arbitrate device ownership. There is no $OWNER table in the single-job systems.

The table is divided into two-word entries for each device. Entries are made into this table when the LOAD command is issued. Each two-word entry is in turn divided into eight four-bit fields capable of holding a job number. The low four bits of the first byte correspond to unit 0, and the high four bits correspond to unit 1. The low four bits of the next byte correspond to unit 2, and so on (see (OWNERTAB_FIG)). Thus, each device is presumed to have up to eight units, each assigned independently of the others. However, if the device is non-file-structured, units are not assigned independently; the monitor ASSIGN code ensures that ownership of all units is assigned to one job.

($OWNER Entry\OWNERTAB_FIG) (POSTSCRIPT\S560C3OWNERTAB_FIG.EPS\6)

When a background job, a foreground job, or a system job attempts to access a particular unit of a device, the monitor checks to be sure the unit being accessed is either public or belongs to the requesting job. If another job owns the unit, a fatal error is generated.

The device is public if the four-bit field is 0. If the device is not public, the field contains a code equal to the job number plus 1. Since job numbers are always even, the ownership code is odd. For example, in a distributed foreground/background system, the owner field value for the background job is 1; for the foreground job it is 3. In a system with the system job feature, the owner field value for the background job is still 1; for the foreground job it is 17. The owner field value for a system job is 1 plus the job number.

As mentioned above, support for the $OWNER table is a system generation feature for the multi-job monitors. By default, the table is supported and lets a job 'own' a device handler unit (LOAD device=jobnam).

If support for the $OWNER table is explicitly removed during the system generation procedure, attempts to assign device unit ownership returns a fatal level error message. However, because the handler loading operation precedes the attempted ownership assignment, the handler is loaded by RT--11 before the error message is returned. ($PNAM2 Table)

A system generation for extended device-unit support creates $PNAM2, a second physical device name table. The $PNAM2 table is used for extended device-unit logical to physical device name translation.

$PNAM2 contains the same index of physical device names as the $PNAME table. Handlers installed on the system that contain extended device-unit support are located in $PNAM2 with their single-letter device name in the same index position as the 2-letter device name entry in $PNAME. Handlers installed on the system that do not contain extended device-unit support are located in $PNAM2 with their 2-letter device name in the same index positon as their entry in $PNAME.

For example, if both the monitor and the DU handler are generated for extended device-unit support, the DU handler is located in $PNAME as ^RDU_ (a single space following the device name) and in the same index position in $PNAM2 as ^RD__ (two spaces following the device name). If the monitor is generated for extended device-unit support, the LP handler, without such support, is located as ^RLP_ (single space) at the same index position in both $PNAME and $PNAM2. (Adding a Device to the Tables)

You can create free slots in the tables by deleting or renaming one or more of the device handler files from the system device and rebooting the system, or by issuing the REMOVE command. The INSTALL command can install a different device handler into the table after the system has been booted. However, INSTALL does not make a device entry permanent. For more information on installation, the DEV macro, and the bootstrap, see (dev_book). (End of Chapter)