2004-10-08 19:08:54

by michael_soulier

[permalink] [raw]
Subject: wait_event and preemption in 2.6


I am sending this on behalf of a coworker who is unfortunate enough to
be using a crappy email client. We are not subscribed to the mailing
list, so please include us in your replies.

---quote---
Dear kernel folks,

I'm writing a device driver for PPC Linux and I'm using wait_event. It
seems to me that there is a potential race condition in wait_event when
preemption is turned on (2.6 kernel).

The scenario goes something like this: After the waiting process is
woken up and returns from schedule it goes to the top of the loop and
prepares to wait again (despite the condition being true). Then it will
check the condition and break out of the loop. But what if in-kernel
preemption occurs while it's doing that and another process is
immediately scheduled to run? Does the process sleep forever? Assume
that the event (say interrupt) that caused the original wakeup is a one
shot.

I'm probably missing something. I've googled for an answer and asked
some of my Linux friends but it's not clear. Thanks for any replies.
Please cc me.

John
---end---

Thank you,
Mike

--
Michael P. Soulier <[email protected]>
6000/6010/60* Development, Mitel Networks Corporation
"...the word HACK is used as a verb to indicate a massive amount of nerd-like
effort." -Harley Hahn, A Student's Guide to Unix


2004-10-08 20:18:48

by Robert Love

[permalink] [raw]
Subject: Re: wait_event and preemption in 2.6

On Fri, 2004-10-08 at 13:45 -0400, [email protected] wrote:

> I'm writing a device driver for PPC Linux and I'm using wait_event. It
> seems to me that there is a potential race condition in wait_event when
> preemption is turned on (2.6 kernel).
>
> The scenario goes something like this: After the waiting process is
> woken up and returns from schedule it goes to the top of the loop and
> prepares to wait again (despite the condition being true). Then it will
> check the condition and break out of the loop. But what if in-kernel
> preemption occurs while it's doing that and another process is
> immediately scheduled to run? Does the process sleep forever? Assume
> that the event (say interrupt) that caused the original wakeup is a one
> shot.

See the PREEMPT_ACTIVE logic.

If a task is preempted it is marked PREEMPT_ACTIVE and it skips the
runqueue removal logic in schedule(). So even if it is !TASK_RUNNING it
will run again.

You can see this in schedule() and preempt_schedule(), both in
kernel/sched.c.

Robert Love


2004-10-08 20:25:17

by Joe Korty

[permalink] [raw]
Subject: Re: wait_event and preemption in 2.6

On Fri, Oct 08, 2004 at 01:45:10PM -0400, [email protected] wrote:
> I'm writing a device driver for PPC Linux and I'm using wait_event. It
> seems to me that there is a potential race condition in wait_event when
> preemption is turned on (2.6 kernel).
>
> The scenario goes something like this: After the waiting process is
> woken up and returns from schedule it goes to the top of the loop and
> prepares to wait again (despite the condition being true). Then it will
> check the condition and break out of the loop. But what if in-kernel
> preemption occurs while it's doing that and another process is
> immediately scheduled to run? Does the process sleep forever? Assume
> that the event (say interrupt) that caused the original wakeup is a one
> shot.
>
> I'm probably missing something. I've googled for an answer and asked
> some of my Linux friends but it's not clear. Thanks for any replies.
> Please cc me.


Hi Mike,
Here is the answer Robert Love gave me to that very same question,
over a year ago.......

> On Mon, 2003-04-14 at 17:54, Joe Korty wrote:
>> Is this analysis correct? If it is, perhaps there is an alternative
>> to fixing these cases individually: make the TASK_INTERRUPTIBLE/
>> TASK_UNINTERRUPTIBLE states block preemption. In which case the
>> 'set_current_state(TASK_RUNNING)' macro would need to include the
>> same preemption check as 'preemption_enable'.

> Thankfully you are wrong or we would have some serious problems :)
>
> See kernel/sched.c :: preempt_schedule() where we set p->preempt_count
> to PREEMPT_ACTIVE.
>
> Then see kernel/sched.c :: schedule() where we short-circuit the
> remove-from-runqueue code if PREEMPT_ACTIVE is set.
>
> Thus, it is safe to preempt regardless of the task's state. It will
> eventually reschedule.
>
> Robert Love