Programming 版 (精华区)
发信人: zpw (zhao), 信区: Programming
标 题: Synchronizing Multiple Interrupts
发信站: 紫 丁 香 (Wed Jul 29 21:06:42 1998), 转信
Synchronizing Multiple Interrupts
The Windows NT kernel provides a mechanism to protect data that is shared
between an interrupt service routine (ISR) and code running at a lower
priority level. If this mechanism were not available, then the ISR could
execute while the lower priority code was in the process of modifying the
shared data, potentially resulting in a catastrophic failure.
The mechanism that the system provides is the service KeSynchronizeExecution:
BOOLEAN KeSynchronizeExecution(
IN PKINTERRUPT Interrupt,
IN PKSYNCHRONIZEROUTINE SynchronizeRoutine,
IN PVOID SynchronizeContext
);
A driver calls KeSynchronizeExecution when it needs to access data shared with
the ISR. The parameter SynchronizeRoutine is the address of a function that
actually accesses the shared data. The service calls the supplied function at
raised IRQL, while holding the spin lock associated with the interrupt. If an
interrupt occurs while SynchronizeRoutine is running, the execution of the ISR
is deferred until SynchronizeRoutine returns.
Now suppose the driver is managing not one, but possibly several interrupts.
Each interrupt has its own priority level (IRQL). If the driver writer does
not take precautions, then one ISR could interrupt the execution of a second
ISR, raising the possibility of data corruption.
One way to avoid the problem is to first determine which interrupt has the
highest IRQL, and use KeSynchronizeExecution from inside the ISRs of interrupts
that have lower IRQLs. The ISR for the lower priority interrupt passes in a
pointer to the interrupt object having the highest IRQL. The system takes the
spin lock associated with the higher level interrupt, thereby ensuring atomic
access to the critical data. This is just a generalization of the usage of
KeSynchronizeExecution as described for sharing data between ISRs and
non-interrupt code.
Because it could be expensive to make extra calls and to change IRQLs while in
an ISR, NT enables the driver writer to assign a common synchronization level
for a set of interrupts. For a set of interrupts that have a common IRQL, the
associated ISRs cannot interrupt one another, so they don't have to call
KeSynchronizeExecution to ensure atomic access to data. The key to setting a
common synchronization level for a set of interrupts is found in the service
IoConnectInterrupt:
NTSTATUS IoConnectInterrupt(
OUT PKINTERRUPT *InterruptObject,
IN PKSERVICE_ROUTINE ServiceRoutine,
IN PVOID ServiceContext,
IN PKSPIN_LOCK SpinLock,
IN ULONG Vector,
IN KIRQL Irql,
IN KIRQL SynchronizeIrql,
IN KINTERRUPT_MODE InterruptMode,
IN BOOLEAN ShareVector,
IN KAFFINITY ProcessorEnableMask,
IN BOOLEAN FloatingSave
);
The parameter in question is SynchronizeIrql. To determine this value, the
driver first collects the IRQLs for all of its interrupts (using
HalGetInterruptVector), and selects the greatest. The driver must also
initialize storage for a spin lock, and pass its address in parameter SpinLock.
The spin lock must remain in existence while the interrupts are hooked.
Once the driver has determined the greatest IRQL for all its interrupts, and
has intialized a spin lock, it calls IoConnectInterrupt for each interrupt,
using the same values for SynchronizeIrql and SpinLock for each call. A driver
that uses this technique causes all of its ISRs to run at the same IRQL, which
greatly simplifies the task of serializing access to critical data.
If you develop NT or WDM drivers with Vireo Driver::Works, it is very easy to
use this method. The class that handles interrupts is called KInterrupt. There
are two forms of KInterrupt::Connect. The first form is the simple form, used
when a driver has only one interrupt, or when multiple interrupts do not
require synchronization:
NTSTATUS KInterrupt::Connect(PKSERVICE_ROUTINE Isr, PVOID Context);
The second form is for the case when there are multiple interrupts requiring
synchronization:
NTSTATUS KInterrupt::Connect(
PKSERVICE_ROUTINE Isr,
PVOID Context,
PKSPIN_LOCK pSpin,
KIRQL SynchIrql
);
--
※ 来源:.紫 丁 香 bbs.hit.edu.cn.[FROM: yaoyu.hit.edu.cn]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:3.630毫秒