Re: down_interruptible and timers

MOLNAR Ingo (mingo@chiara.csoma.elte.hu)
Tue, 26 Jan 1999 10:20:59 +0100 (CET)


On Mon, 25 Jan 1999, Tim Waugh wrote:

> All I want is a primitive that I can use to count and wait for events.
> Semaphores used to do that, before they became recursive. Now my code is
> broken, and I'm not sure what the correct fix is.

> How would you modify the code so that it works again?

something like this?:

/*
* Wait for an event at most 5 seconds
*/
int __wait_parport_event(*port)
{
int ret = 0;
signed long timeout = 5*HZ;
struct wait_queue wait = { current, NULL };

add_wait_queue(&port->wait, &wait);

for (;;) {
current->state = TASK_INTERRUPTIBLE;
if (atomic_read(port->events)
break;

timeout = schedule_timeout(timeout);

if (signal_pending(current)) {
ret = -EINTR;
break;
}
if (!timeout) {
ret = -TIMEDOUT;
break;
}
}
current->state = TASK_RUNNING;
remove_wait_queue(&port->wait, &wait);
return ret;
}

static inline int wait_parport_event (*port)
{
if (!atomic_read(&port->events))
return __wait_parport_event(port);
return 0;
}

the IRQ handler wakes port->wait up when there is some work to do. Note
that this code doesnt have the race you mentioned earlier (and this
technique is used in the kernel at lots of places), because we _first_
change our process state to INTERRUPTIBLE, then do we check the events
counter, and reschedule if no work. This means if there comes an interrupt
right after we've checked the event counter, we will not miss the wakeup,
we will only do one more reschedule. (because doing a schedule() with
TASK_RUNNING guarantees that we return without a wakeup)

to decrease the counter you might want to something like:

if (err = wait_parport_event(port)) {
....
return;
}
<do the work>
atomic_dec(&port->events);

(you dont need an atomic counter right now, but the above code is already
SMP-safe even without the kernel-lock and isnt much different)

-- mingo

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/