Subject: Re: interrupts, threads, and preventing wakeup-before-sleep?
To: None <kpneal@pobox.com>
From: Nathan J. Williams <nathanw@wasabisystems.com>
List: tech-kern
Date: 02/17/2003 22:31:46
kpneal@pobox.com writes:

> Now, ltsleep() is not documented as doing anything to the interrupt mask.
> So if the proper spl call is made before locking a simple lock and the
> lock is used with ltsleep() then the spl level will not be lowered! This
> makes simple locks useless when trying to prevent a wakeup-before-sleep
> condition where the waker is an interrupt, and therefore makes ltsleep()
> useless in this case.

ltsleep() saves the spl level it is called with and restores it *for
that lwp*. The spl will be lowered if the next lwp that runs isn't at
an elevated spl, such as a lwp that is about to run in userlevel.


So the right sequence to wait for the condition is something like:

s = splfoo();
simple_lock(foolock);

while (condition false) {
  ltsleep(fooaddr, "foo", foolock);
}

simple_unlock(foolock);
splx(s);

and in the interrupt code:

simple_lock(foolock);
 .. set condition true ..
simple_unlock(foolock);
wakeup(fooaddr);

In the non-MP case, you are right that the simple_lock/simple_unlock
calls are no-ops; the mutual exclusion between the upper half and
lower half is provided by the spl calls.

In the MP case, the spl calls provide the same mutual exclusion as in
the UP case, and also prevent deadlock on one processor
(consider what would happen if the upper half got the lock and then
the interrupt came in and started spinning, at interrupt level, for
the same lock). The simple_lock calls provide mutual exclusion between
one half running on one processor and the other half running on
another.

        - Nathan