2002-02-26 19:54:35

by Richard B. Johnson

[permalink] [raw]
Subject: schedule()



I just read on this list that:

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

Will no longer be allowed in a kernel module! If this is true, how
do I loop, waiting for a bit in a port, without wasting CPU time?

A lot of hardware does not generate interrupts upon a condition,
there is no CPU activity that could send a wake_up_interruptible()
to something sleeping.

For instance, I need to write data to a hardware FIFO, one long-word
at a time, but I can't just write. I have to wait for a bit to be
set or reset for each and every write. I'm going to be burning a
lot of CPU cycles if I can't schedule() while the trickle-down-effect
of the hardware is happening.


Cheers,
Dick Johnson

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

111,111,111 * 111,111,111 = 12,345,678,987,654,321


2002-02-26 20:05:35

by Jeff Garzik

[permalink] [raw]
Subject: Re: schedule()

"Richard B. Johnson" wrote:
>
> I just read on this list that:
>
> while(something)
> {
> current->policy |= SCHED_YIELD;
> schedule();
> }
>
> Will no longer be allowed in a kernel module! If this is true, how
> do I loop, waiting for a bit in a port, without wasting CPU time?

Call yield() or better yet, schedule_timeout()

In 2.4, define the above to be yield() in some compatibility module...

--
Jeff Garzik | "UNIX enhancements aren't."
Building 1024 | -- says /usr/games/fortune
MandrakeSoft |

2002-02-26 20:10:55

by Davide Libenzi

[permalink] [raw]
Subject: Re: schedule()

On Tue, 26 Feb 2002, Richard B. Johnson wrote:

>
>
> I just read on this list that:
>
> while(something)
> {
> current->policy |= SCHED_YIELD;
> schedule();
> }
>
> Will no longer be allowed in a kernel module! If this is true, how
> do I loop, waiting for a bit in a port, without wasting CPU time?
>
> A lot of hardware does not generate interrupts upon a condition,
> there is no CPU activity that could send a wake_up_interruptible()
> to something sleeping.
>
> For instance, I need to write data to a hardware FIFO, one long-word
> at a time, but I can't just write. I have to wait for a bit to be
> set or reset for each and every write. I'm going to be burning a
> lot of CPU cycles if I can't schedule() while the trickle-down-effect
> of the hardware is happening.

What did it do yield() to you ? Doesn't it work for your case ?



- Davide


2002-02-26 20:12:25

by Richard B. Johnson

[permalink] [raw]
Subject: Re: schedule()

On Tue, 26 Feb 2002, Jeff Garzik wrote:

> "Richard B. Johnson" wrote:
> >
> > I just read on this list that:
> >
> > while(something)
> > {
> > current->policy |= SCHED_YIELD;
> > schedule();
> > }
> >
> > Will no longer be allowed in a kernel module! If this is true, how
> > do I loop, waiting for a bit in a port, without wasting CPU time?
>
> Call yield() or better yet, schedule_timeout()
>
> In 2.4, define the above to be yield() in some compatibility module...

Okay, thanks. I'll change my code to YIELD and define a macro for
both versions.


Cheers,
Dick Johnson

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

111,111,111 * 111,111,111 = 12,345,678,987,654,321

2002-02-26 20:14:57

by Richard B. Johnson

[permalink] [raw]
Subject: Re: schedule()

On Tue, 26 Feb 2002, Davide Libenzi wrote:

> On Tue, 26 Feb 2002, Richard B. Johnson wrote:
>
> >
> >
> > I just read on this list that:
> >
> > while(something)
> > {
> > current->policy |= SCHED_YIELD;
> > schedule();
> > }
> >
> > Will no longer be allowed in a kernel module! If this is true, how
> > do I loop, waiting for a bit in a port, without wasting CPU time?
> >
> > A lot of hardware does not generate interrupts upon a condition,
> > there is no CPU activity that could send a wake_up_interruptible()
> > to something sleeping.
> >
> > For instance, I need to write data to a hardware FIFO, one long-word
> > at a time, but I can't just write. I have to wait for a bit to be
> > set or reset for each and every write. I'm going to be burning a
> > lot of CPU cycles if I can't schedule() while the trickle-down-effect
> > of the hardware is happening.
>
> What did it do yield() to you ? Doesn't it work for your case ?
>
There isn't one in 2.4.x I'll modify my drivers to use YIELD
and #define it depending upon version.


Cheers,
Dick Johnson

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

111,111,111 * 111,111,111 = 12,345,678,987,654,321

2002-02-26 20:17:45

by Davide Libenzi

[permalink] [raw]
Subject: Re: schedule()

On Tue, 26 Feb 2002, Richard B. Johnson wrote:

> On Tue, 26 Feb 2002, Davide Libenzi wrote:
>
> > On Tue, 26 Feb 2002, Richard B. Johnson wrote:
> >
> > >
> > >
> > > I just read on this list that:
> > >
> > > while(something)
> > > {
> > > current->policy |= SCHED_YIELD;
> > > schedule();
> > > }
> > >
> > > Will no longer be allowed in a kernel module! If this is true, how
> > > do I loop, waiting for a bit in a port, without wasting CPU time?
> > >
> > > A lot of hardware does not generate interrupts upon a condition,
> > > there is no CPU activity that could send a wake_up_interruptible()
> > > to something sleeping.
> > >
> > > For instance, I need to write data to a hardware FIFO, one long-word
> > > at a time, but I can't just write. I have to wait for a bit to be
> > > set or reset for each and every write. I'm going to be burning a
> > > lot of CPU cycles if I can't schedule() while the trickle-down-effect
> > > of the hardware is happening.
> >
> > What did it do yield() to you ? Doesn't it work for your case ?
> >
> There isn't one in 2.4.x I'll modify my drivers to use YIELD
> and #define it depending upon version.

In 2.5 yield() maps to sys_sched_yield(). You can handle it in the same
way in your includes if version <= 2.4.




- Davide


2002-02-26 20:44:55

by Richard B. Johnson

[permalink] [raw]
Subject: Re: schedule()

On Tue, 26 Feb 2002, Davide Libenzi wrote:

> On Tue, 26 Feb 2002, Richard B. Johnson wrote:
>
> > On Tue, 26 Feb 2002, Davide Libenzi wrote:
> >
> > > On Tue, 26 Feb 2002, Richard B. Johnson wrote:
> > >
> > > >
> > > >
> > > > I just read on this list that:
> > > >
> > > > while(something)
> > > > {
> > > > current->policy |= SCHED_YIELD;
> > > > schedule();
> > > > }
> > > >
> > > > Will no longer be allowed in a kernel module! If this is true, how
> > > > do I loop, waiting for a bit in a port, without wasting CPU time?
> > > >
> > > > A lot of hardware does not generate interrupts upon a condition,
> > > > there is no CPU activity that could send a wake_up_interruptible()
> > > > to something sleeping.
> > > >
> > > > For instance, I need to write data to a hardware FIFO, one long-word
> > > > at a time, but I can't just write. I have to wait for a bit to be
> > > > set or reset for each and every write. I'm going to be burning a
> > > > lot of CPU cycles if I can't schedule() while the trickle-down-effect
> > > > of the hardware is happening.
> > >
> > > What did it do yield() to you ? Doesn't it work for your case ?
> > >
> > There isn't one in 2.4.x I'll modify my drivers to use YIELD
> > and #define it depending upon version.
>
> In 2.5 yield() maps to sys_sched_yield(). You can handle it in the same
> way in your includes if version <= 2.4.
>
>

Can't find it in any header file.

Script started on Tue Feb 26 15:45:06 2002
# grep "sys_sched_yield()" /usr/src/linux/include/linux/*.h
# grep "sys_sched_yield()" /usr/src/linux/include/asm/*.h
You have new mail in /var/spool/mail/root
# exit
exit

Script done on Tue Feb 26 15:46:46 2002

I'll #define a macro and be done with it.


Cheers,
Dick Johnson

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

111,111,111 * 111,111,111 = 12,345,678,987,654,321

2002-02-26 20:48:15

by Davide Libenzi

[permalink] [raw]
Subject: Re: schedule()

On Tue, 26 Feb 2002, Richard B. Johnson wrote:

> On Tue, 26 Feb 2002, Davide Libenzi wrote:
>
> > On Tue, 26 Feb 2002, Richard B. Johnson wrote:
> >
> > > On Tue, 26 Feb 2002, Davide Libenzi wrote:
> > >
> > > > On Tue, 26 Feb 2002, Richard B. Johnson wrote:
> > > >
> > > > >
> > > > >
> > > > > I just read on this list that:
> > > > >
> > > > > while(something)
> > > > > {
> > > > > current->policy |= SCHED_YIELD;
> > > > > schedule();
> > > > > }
> > > > >
> > > > > Will no longer be allowed in a kernel module! If this is true, how
> > > > > do I loop, waiting for a bit in a port, without wasting CPU time?
> > > > >
> > > > > A lot of hardware does not generate interrupts upon a condition,
> > > > > there is no CPU activity that could send a wake_up_interruptible()
> > > > > to something sleeping.
> > > > >
> > > > > For instance, I need to write data to a hardware FIFO, one long-word
> > > > > at a time, but I can't just write. I have to wait for a bit to be
> > > > > set or reset for each and every write. I'm going to be burning a
> > > > > lot of CPU cycles if I can't schedule() while the trickle-down-effect
> > > > > of the hardware is happening.
> > > >
> > > > What did it do yield() to you ? Doesn't it work for your case ?
> > > >
> > > There isn't one in 2.4.x I'll modify my drivers to use YIELD
> > > and #define it depending upon version.
> >
> > In 2.5 yield() maps to sys_sched_yield(). You can handle it in the same
> > way in your includes if version <= 2.4.
> >
> >
>
> Can't find it in any header file.
>
> Script started on Tue Feb 26 15:45:06 2002
> # grep "sys_sched_yield()" /usr/src/linux/include/linux/*.h
> # grep "sys_sched_yield()" /usr/src/linux/include/asm/*.h
> You have new mail in /var/spool/mail/root
> # exit
> exit
>
> Script done on Tue Feb 26 15:46:46 2002
>
> I'll #define a macro and be done with it.

It'd be too easy if it'd be inside an header file :-)

asmlinkage long sys_sched_yield(void);

in kernel/sched.c




- Davide


2002-02-26 21:11:58

by Richard B. Johnson

[permalink] [raw]
Subject: Re: schedule()

On Tue, 26 Feb 2002, Davide Libenzi wrote:
>
> In 2.5 yield() maps to sys_sched_yield(). You can handle it in the same
> way in your includes if version <= 2.4.

It's not exported as well as not defined in a header! It results in
an undefined symbol in the module.

Cheers,
Dick Johnson

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

111,111,111 * 111,111,111 = 12,345,678,987,654,321

2002-02-26 22:34:40

by Davide Libenzi

[permalink] [raw]
Subject: Re: schedule()

On Tue, 26 Feb 2002, Richard B. Johnson wrote:

> On Tue, 26 Feb 2002, Davide Libenzi wrote:
> >
> > In 2.5 yield() maps to sys_sched_yield(). You can handle it in the same
> > way in your includes if version <= 2.4.
>
> It's not exported as well as not defined in a header! It results in
> an undefined symbol in the module.

You can try to ask Marcelo to add a line in include/linux/sched.h and one
in kernel/ksym.c
In this way a compatibility interface can be achieved for code that needs it.




- Davide


2002-02-27 00:56:51

by Nigel Gamble

[permalink] [raw]
Subject: Re: schedule()

On Tue, 26 Feb 2002, Jeff Garzik wrote:
> "Richard B. Johnson" wrote:
> >
> > I just read on this list that:
> >
> > while(something)
> > {
> > current->policy |= SCHED_YIELD;
> > schedule();
> > }
> >
> > Will no longer be allowed in a kernel module! If this is true, how
> > do I loop, waiting for a bit in a port, without wasting CPU time?
>
> Call yield() or better yet, schedule_timeout()

Yes, please use schedule_timeout() if at all possible, or make sure that
the loop will only ever execute for a few 100us at most.

One thing to bear in mind is that using yield() will waste CPU time if
the code is ever called by a real-time process (unless it is a SCHED_RR
process with other runnable SCHED_RR processes at the same priority),
because there will be no other process that the scheduler is allowed to
run, so the RT process will just be chosen to run again, with no delay.

We really need high resolution timers, so that schedule_timeout() can be
used for delays of less than one jiffy.

Nigel Gamble [email protected]
Mountain View, CA, USA. http://www.nrg.org/

2002-02-27 15:27:38

by Richard B. Johnson

[permalink] [raw]
Subject: Re: schedule()

On Tue, 26 Feb 2002, Nigel Gamble wrote:
[SNIPPED]
> On Tue, 26 Feb 2002, Jeff Garzik wrote:
> > "Richard B. Johnson" wrote:
[SNIPPED]
> >
> > Call yield() or better yet, schedule_timeout()
>
> Yes, please use schedule_timeout() if at all possible, or make sure that
> the loop will only ever execute for a few 100us at most.
>

This can't be guaranteed. Many machine-to-machine communications
links need to continually retry (forever) without hurting the
operation of anything else. Yes, there are a few wasted CPU cycles,
but everything needs to run until the "plug that got kicked out"
is discovered and plugged back in (days, perhaps).

Its almost like; "There is no such thing as a fatal hardware error...".
Software needs to report that things are not right and also needs
to report when things got fixed. A bad chip is merely an exception
that needs to be worked around in software.

So, I don't have anything that loops forever when something is
broken. However, it will retry forever until it's fixed.

> One thing to bear in mind is that using yield() will waste CPU time if
> the code is ever called by a real-time process (unless it is a SCHED_RR
> process with other runnable SCHED_RR processes at the same priority),
> because there will be no other process that the scheduler is allowed to
> run, so the RT process will just be chosen to run again, with no delay.
>

Yeah. I looked at the code and it doesn't schedule directly in 2.4.1.
It just says "reschedule later on after I'm preempted". I don't think
my code wants to spin to the next HZ before it gives up the CPU. It
already knows that the hardware is not ready and has volunteered to
give up the CPU now. After the next HZ, the hardware would be ready.
The driver(s) count on the fact that most everybody sleeps (is I/O bound)
most of the while so it will probably be getting the CPU back in less
than a HZ most of the time.

> We really need high resolution timers, so that schedule_timeout() can be
> used for delays of less than one jiffy.
>

Maybe, but we really need a sleep_on_proc(procedure, timeout) where
procedure is a pointer to a procedure that returns 0 for okay, and
takes a pointer-to-void (so the caller can pass whatever parameters it
needs).

/*
* Returns 0 if the procedure returned 0.
* Returns -1 if it timed out.
*/
int sleep_on_proc(int(*procedure)(void *), size_t timeout);

The kernel can decide how to handle the scheduling and the drivers
are not affected by such changes.


Driver code would do something like:

int my_spinner(void *inf)
{
FOO *foo = (FOO *) inf; /* Get my parameters */
if(readl(foo->status) & READY)
return 0;
return -1;
}

To use this, the kernel sleeper would be called as:

if(sleep_on_proc(my_spinner(inf), TIMEOUT))
fail_thing();
else
good_thing();


Cheers,
Dick Johnson

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

111,111,111 * 111,111,111 = 12,345,678,987,654,321