269
Chapter 5 Operating System Issues
The status confusion and register conflict is avoided by disabling interrupts
during the critical portions of the operating system code. The code shown in this
chapter enables interrupts after the frozen special registers and stack support
registers have been saved. This is insufficient to deal with the nested interrupt
situation described above. However, this does reduce interrupt latency, which is a
concern to real–time 29K users. Some implementors may chose to move the enabling
of interrupts to a later stage in the operating system support code — more
specifically, to a point after register stack support registers have been assigned their
new values. Register usage changes will also be required to avoid conflict.
Within the example code used throughout this chapter, interrupts can be enabled
just after special register CHC has been saved (before
lr1
is pushed on the PCB). This
low latency technique enables
lightweight
interrupt handlers to be supported during
the operation of normally critical operating system code. Lightweight handlers
typically only run in Freeze mode and can easily avoid register conflict if they are
restricted to global registers
it0–it3.
Using the
Interrupt Queuing Model
described in
section 4.3.12, or the
Signal Dispatcher
described in section 2.5.6, a lightweight
handler responds to the peripheral device interrupt. It transfers any critical peripheral
device data and clears the interrupt request. In doing so, it inserts an
interrupt–descriptor, or signal number, into a queue for later processing.
A Supervisor C level interrupt handler known as the Dispatcher removes queue
entries and calls the appropriate handler to process them. If the operating system is
interrupted in a non–critical region by a device requiring a Supervisor mode C level
handler, then the dispatcher is immediately started. If the interrupt is in a critical
region then the Dispatcher shall be started later when the current critical tasks have
been completed. If the Dispatcher is already running when the interrupt occurred,
then the associated interrupt descriptor shall wait in the queue until the Dispatcher
removes it for processing.
The use of a Dispatcher and interrupt queuing helps to reduce interrupt latency
via the use of lightweight interrupts when building queue entries. However, the
method has some restrictions. It works where troublesome nested interrupt servicing
can be partially delayed for later high level handler completion. But some interrupts
can not be delayed. For example an operating system may be running with address
translation turned on, and a TLB miss may occur for an operating system memory
page which needs the support of a high level handler to page–in the data from a
secondary disk device. In this case the interrupt must be completely serviced
immediately. This is not a typical environment for 29K users in real–time
applications. And even in many non–real–time operating system cases the operating
system runs in physical mode or all instruction and data are known to be currently in
physical memory. The trade–offs required in deciding when to enable interrupts and
resolving register conflict are specific to each operating system implementation.