>This may reflect a basic misunderstanding of mine, which would explain a
lot… If I have a function that I know will be called at dispatch_level,
and it requires access to a shared resource, what do I do? Can I use
anything that would block (presumably including spinlocks)? Can I have a
spinlock that has the possibility of being acquired by multiple different
dispatch_level threads? That would imply that one or more of them are
blocking…
The specific case here is that I’m trying to protect a shared data
structure between the protocol side and the miniport side of an NDIS IM
driver.
I guess that also begs another basic question that I thought I understood
before this mess: can a thread at >= dispatch_level hold multiple
spinlocks at one time? The second one might block, and the first one will
already be held. I’d swear I’ve used nested spinlocks before, and I
always pay attention to acquisition/release ordering too.
First, I’d like to clarify how I use some terminology. When I think of
execution “blocking”, I think of a thread switch happening. I should also
define “thread” to means a stack plus an “execution context”. An execution
context (any suggestion of better terminology?) is not related to which
stack your on, and means the state of the processor registers at the
moment. When code is interrupted, it’s execution context changes, but it’s
stack doesn’t. Interrupts and returns MUST occur in LIFO order, thread
preemption can resume execution on ANY runnable thread
DISPATCH_LEVEL code (and above) preempts PASSIVE_LEVEL code, and executes
on an arbitrary thread stack, possible resuming a different piece of
PASSIVE_LEVEL code when it returns from DISPATCH_LEVEL. Code at
DISPATCH_LEVEL and above, can be interrupted, but not preempted. There can
be only one execution context for DISPATCH_LEVEL per processor, so your
scenario above simple can’t happen, as there aren’t different
DISPATCH_LEVEL threads a processor. On a single processor system, it’s not
possible for you to be running code at DISPATCH_LEVEL, and acquire a
spinlock, and then be preempted by some other piece of DISPATCH_LEVEL code
which tries to acquire the same spinlock. In SMP systems, you may go to
acquire the spinlock and find it’s locked, and that processor will just
spin at DISPATCH_LEVEL, still being interruptible. Spinning on a spinlock
does NOT give the processor to other code at DISPATCH_LEVEL., it’s
essentially stuck at the spinlock until it’s released.
You can hold multiple spin locks at DISPATCH_LEVEL, and you have to be
careful about ordering, which you seem to know already. The danger is some
other processor acquires the spin locks in a different order, you may
create deadlock because processor 1 has spinlock a and is waiting on
spinlock b, and processor 2 has spinlock b and is waiting on spinlock a.
Choosing the IRQL level for a spinlock is important, as it must be acquired
at the highest IRQL level of any code that might acquire it. For example,
say you have data you access in your DPC at DISPATCH_LEVEL, and the same
data is accessed at a higher IRQL in the interrupt service routine. If you
acquire the spinlock in the DPC at DISPATCH_LEVEL, the ISR may come along,
interrupt the DPC, and attempt to acquire the same spinlock at the DIRQL.
Since the DPC already holds the spinlock, the ISR will get stuck waiting on
the spinlock and your system is mostly frozen. The correct thing to do is
for the DPC to acquire the spinlock at the IRQL level that the ISR would
acquire it at, which assures you will not be interrupted by the ISR while
the spinlock is held. If you get an interrupt on another processor, it may
enter the ISR, and spin on the spinlock held by the DPC, until the DPC is
done with the spinlock.
Hope this make this clearer.
You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com