Skip to contentSkip to conversation

Problems with wait queues

DISCUSSION Nicolas Bougues 6 participants 9 messages Jun 26, 2002 – Jun 27, 2002

lore
Share & tools
lore
#0 lore raw

Dear all,

I'm writing a device driver for a PCI board that sends/receives one frame (80 bytes) of data every 100th/sec. The kernel is 2.4.18 non SMP.

I use the timer task, and every 100th/sec, I transmit any pending buffer and store the received one, so that it can be handled by the user mode app.

The driver is accessible using a standard device node.

I implemented a wait queue mechanism in order to deal with blocking read/writes from user mode. When the dev_write sees the TX queue is full, it wait_event_interruptible(txq, condition). Idem for RX.

And every 100th/sec, when it gets more data for RX or more room for TX, it wake_up_interruptible(txq|rxq).

My problem is that I wrote a test app that loops around read() or write() on my device in user mode, and when running this app, my loadavg increases, up to 1.00, which is surprising.

But, in the meantime :
- vmstat shows no user mode nor system activity.
- time of the user mode test app shows 0.00 for both user and system time.
- a busy task (such as dd if=/dev/zero of=/dev/null bs=1024k count=300000) takes the same amount of time to run when the test app is running, as it took when the system was idle.

If I insert an usleep(1000*100), which will wait about 1/100th sec, in the loop around read()/write(), the wait queues aren't used anymore in the driver (since there is always room for TX or data for RX), and the loadavg stays at 0.00, which is what is expected.

Does anybody have any idea on what I may have done wrong, and why would loadavg increase when vmstat show no activity ?

Thanks.
--
Nicolas Bougues

#1 lore raw
Quoted 2 lines · Nicolas Bougues

Does anybody have any idea on what I may have done wrong, and why would loadavg increase when vmstat show no activity ?

loadavg does not report what you think it reports

#2 lore raw
Quoted 7 lines · Andries Brouwer
Quoted 2 lines · Nicolas Bougues

Does anybody have any idea on what I may have done wrong, and why would loadavg increase when vmstat show no activity ?

loadavg does not report what you think it reports

As far as I understand, loadavg reports the average number of processes in the TASK_RUNNING state.

What happens in my driver, I believe, is that :
- on timer interrupt, I do some stuff, and wake_up the waiting process
- then the loadavg is computed (seeing my waiting task as TASK_RUNNING)
- then the scheduler runs the task
- then the task goes immediatly back to sleep

Quoted 1 line

From this point of view, then my problem is just "cosmetic". Isn't

there a way to do things in a different order, so that I could still get a meaningful(*) loadavg ?

(*): by meaningful, I mean representing the number of busy processes at a random point in time.
--
Nicolas Bougues

#3 lore raw
Quoted 18 lines · Nicolas Bougues
Quoted 7 lines · Andries Brouwer
Quoted 2 lines · Nicolas Bougues

Does anybody have any idea on what I may have done wrong, and why would loadavg increase when vmstat show no activity ?

loadavg does not report what you think it reports

As far as I understand, loadavg reports the average number of processes in the TASK_RUNNING state.

What happens in my driver, I believe, is that :
- on timer interrupt, I do some stuff, and wake_up the waiting process
- then the loadavg is computed (seeing my waiting task as TASK_RUNNING)
- then the scheduler runs the task
- then the task goes immediatly back to sleep

Quoted 9 lines
Quoted 1 line

From this point of view, then my problem is just "cosmetic". Isn't

there a way to do things in a different order, so that I could still get a meaningful(*) loadavg ?

(*): by meaningful, I mean representing the number of busy processes at a random point in time.
--
Nicolas Bougues

I am sure that you can have things look correct as well as run properly. However, you didn't show us the code. You need to do something like:

            interruptible_sleep_on(&semaphore);

while your wake-up occurs with:

            wake_up_interruptible(&semaphore);

Or, you can do (the hard way) :

             while(!something)
             {
                 current->policy |= SCHED_YIELD;
                 schedule();
             }

Both ways (and others) will look fine with top and will sleep properly.

Cheers,
Dick Johnson

Penguin : Linux version 2.4.18 on an i686 machine (797.90 BogoMips).

Windows-2000/Professional isn't.

#4 lore raw

Richard,

Quoted 3 lines · Richard B. Johnson

I am sure that you can have things look correct as well as run properly. However, you didn't show us the code.

It's quite large, and I didn't think I was "syntactically" wrong. But the code is available, if somebody wants to have a look.

Quoted 8 lines

You need to do something like:

            interruptible_sleep_on(&semaphore);

while your wake-up occurs with:

            wake_up_interruptible(&semaphore);

That's what I do, although I use the wait_event_interruptible macro instead of interruptible_sleep_on.

Quoted 4 lines

Both ways (and others) will look fine with top and will sleep properly.

If we're talking about %CPU times, right. If we're talking loadavg, no. As I said in my previous message, I think it's because my wake_up_interruptible() is *always* triggered during the timer interrupt, just before the scheduler runs (new data is available every 100th/sec).

I'm not sure, but I think that the loadavg is computed at the beginning of each scheduler run, thus, my task always looks "running" at this time, even though it just runs for a few microseconds each time.

--
Nicolas Bougues

#5 lore raw
In reply to Richard B. Johnson

For the benefit of any newcomers to the list who haven't clocked RBJ yet...

Quoted 9 lines · [email protected] said:

I am sure that you can have things look correct as well as run
properly. However, you didn't show us the code. You need to do something like:

            interruptible_sleep_on(&semaphore);

while your wake-up occurs with:

            wake_up_interruptible(&semaphore);

Do not ever use sleep_on() and friends. Almost all usage of these functions will be buggy.

--
dwmw2

#6 lore raw
Quoted 8 lines · David Woodhouse

For the benefit of any newcomers to the list who haven't clocked RBJ yet...

Quoted 3 lines · [email protected] said:

I am sure that you can have things look correct as well as run
properly. However, you didn't show us the code. You need to do something like:

Quoted 9 lines
Quoted 5 lines
            interruptible_sleep_on(&semaphore);

while your wake-up occurs with:

            wake_up_interruptible(&semaphore);

Do not ever use sleep_on() and friends. Almost all usage of these functions will be buggy.

Whatever your message means; perhaps it was a way of saying "Hello" to an old friend?

Attached is a file showing about 485 usages of 'sleep_on' in the kernel drivers. If this usage is, as you say, buggy then will you please inform us unwashed hordes what we should use to replace these?

Cheers,
Dick Johnson

Penguin : Linux version 2.4.18 on an i686 machine (797.90 BogoMips).

Windows-2000/Professional isn't.

#7 lore raw
Quoted 10 lines
Quoted 3 lines

Do not ever use sleep_on() and friends. Almost all usage of these functions will be buggy.

Whatever your message means; perhaps it was a way of saying "Hello" to an old friend?

Attached is a file showing about 485 usages of 'sleep_on' in the kernel drivers. If this usage is, as you say, buggy then will you please inform us unwashed hordes what we should use to replace these?

The simplest way is with the wait_event[_interruptible] macros. In newer versions of the USB drivers, you'll find examples. You may also set your task's state and put yourself on a waitqueue, before you do something that will cause you to be woken up.

And yes, most examples you found are buggy, as they can miss a wakeup.
To use sleep_on safely you must make sure that you cannot be woken up before you begin to sleep.

Regards
Oliver

#8 lore raw
In reply to Richard B. Johnson
Quoted 3 lines · Richard B. Johnson

Attached is a file showing about 485 usages of 'sleep_on' in the kernel drivers. If this usage is, as you say, buggy then will you please inform us unwashed hordes what we should use to replace these?

Anything you like -- as long as it doesn't have gaping races which are obvious to anyone with half a clue who actually _thinks_ about the code rather than assuming that _driver_ authors all got it right :)

We _really_ need to kill sleep_on() in 2.5.

Signature · 1 line
dwmw2