Skip to contentSkip to conversation

how to let all others run

DISCUSSION Oliver Neukum 4 participants 8 messages Apr 2, 2001 – Apr 5, 2001

lore
Share & tools
lore
#0 lore raw

Hi,

is there a way to let all other runable tasks run until they block or return to user space, before the task wishing to do so is run again ?

TIA
Oliver

#1 lore raw

Hi Oliver!

Quoted 3 lines · Oliver Neukum

is there a way to let all other runable tasks run until they block or return to user space, before the task wishing to do so is run again ?

Are you trying to do this in kernel or something? From userspace you can use nice(2) then sched_yield(2), though I don't know if the linux implementations will guarrantee anything.

Signature · 1 line
	http://www.penguinpowered.com/~vii
#2 lore raw
Quoted 5 lines · John Fremlin

Hi Oliver!

Oliver Neukum <[email protected]> writes:

Quoted 8 lines
Quoted 3 lines

is there a way to let all other runable tasks run until they block or return to user space, before the task wishing to do so is run again ?

Are you trying to do this in kernel or something? From userspace you can use nice(2) then sched_yield(2), though I don't know if the linux implementations will guarrantee anything.

I recommend using usleep(0) instead of sched_yield(). Last time I checked, sched_yield() seemed to spin and eat CPU cycles, usleep(0) always gives up the CPU.

Try:

	for(;;) usleep();

and

	for(;;) sched_yield();

.. you'll see a quiet behavior under top for usleep(0), and over 80% with sched_yield().

Cheers,
Dick Johnson

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

"Memory is like gasoline. You use it up when you are running. Of course you get it all back when you reboot..."; Actual explanation obtained from the Micro$oft help desk.

#3 lore raw
Quoted 10 lines · Richard B. Johnson
Quoted 9 lines · John Fremlin

Hi Oliver!

Quoted 3 lines · Oliver Neukum

is there a way to let all other runable tasks run until they block or return to user space, before the task wishing to do so is run again ?

Quoted 8 lines
Quoted 4 lines

Are you trying to do this in kernel or something? From userspace you can use nice(2) then sched_yield(2), though I don't know if the linux implementations will guarrantee anything.

I recommend using usleep(0) instead of sched_yield(). Last time I checked, sched_yield() seemed to spin and eat CPU cycles, usleep(0) always gives up the CPU.

What is wrong with this? sched_yield only yields to processes with lower priority (hence suggestion to use nice(2)). Does sched_yield() fail to yield in cases when a higher priority process wants to run? usleep() wastes time if no other such process is waiting, surely?

[...]

Signature · 1 line
	http://www.penguinpowered.com/~vii
#4 lore raw
Quoted 21 lines · John Fremlin
Quoted 10 lines · Richard B. Johnson
Quoted 9 lines · John Fremlin

Hi Oliver!

Quoted 3 lines · Oliver Neukum

is there a way to let all other runable tasks run until they block or return to user space, before the task wishing to do so is run again ?

Quoted 8 lines
Quoted 4 lines

Are you trying to do this in kernel or something? From userspace you can use nice(2) then sched_yield(2), though I don't know if the linux implementations will guarrantee anything.

I recommend using usleep(0) instead of sched_yield(). Last time I checked, sched_yield() seemed to spin and eat CPU cycles, usleep(0) always gives up the CPU.

Quoted 6 lines

What is wrong with this? sched_yield only yields to processes with lower priority (hence suggestion to use nice(2)). Does sched_yield() fail to yield in cases when a higher priority process wants to run? usleep() wastes time if no other such process is waiting, surely?

[...]

Only an observation:

main()

{
    nice(19);
    for(;;)
        sched_yield(); 
}

does...

 12:45pm up 19:10, 6 users, load average: 0.66, 0.19, 0.06 31 processes: 29 sleeping, 2 running, 0 zombie, 0 stopped

CPU states: 44.1% user, 56.9% system, 99.1% nice,  0.0% idle
Mem:  320368K av, 309608K used,  10760K free,      0K shrd,  12688K buff
Swap:      0K av,      0K used,      0K free                188272K cached

  PID USER     PRI  NI  SIZE  RSS SHARE STAT  LIB %CPU %MEM   TIME COMMAND
15902 root      20  19   212  212   176 R N     0 99.1  0.0   1:05 xxx
15921 root      13   0   568  568   432 R       0  1.9  0.1   0:00 top
    1 root       8   0   148  148   116 S       0  0.0  0.0   0:00 init

It consumes 99.1 percent CPU, just spinning.

However,

	for(;;)
            usleep(0);

Doesn't even show on top. Further, it gets the CPU about 100 times a second (HZ). This is normally what you want for something that polls, buts needs to give up the CPU so that whatever it's waiting for can get done as soon as possible.

Cheers,
Dick Johnson

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

"Memory is like gasoline. You use it up when you are running. Of course you get it all back when you reboot..."; Actual explanation obtained from the Micro$oft help desk.

#5 lore raw
Quoted 4 lines

Doesn't even show on top. Further, it gets the CPU about 100 times a second (HZ). This is normally what you want for something that polls, buts needs to give up the CPU so that whatever it's waiting for can get done as soon as possible.

Hi,

first of all I want to do this in kernel.
I need to do this to prevent a race. To handle removal of a hotpluggable scsi device. On SMP there's a race between the task blocking the scsi device and killing obsolete requests and other tasks queueing no requests. If a task has passed the block before it comes into effect, but the killing task is done with killing requests before the new request can be queued the system will oops.
Simply calling the kernel equivalent of sched_yield() is not an option as the number of runnable tasks can be smaller than the number of CPUs in which case sched_yield is a nop.

Regards
Oliver

#6 lore raw
Quoted 7 lines · On Thu, 5 Apr 2001 [email protected] wrote:
Quoted 4 lines

Doesn't even show on top. Further, it gets the CPU about 100 times a second (HZ). This is normally what you want for something that polls, buts needs to give up the CPU so that whatever it's waiting for can get done as soon as possible.

Hi,

Quoted 11 lines

first of all I want to do this in kernel.
I need to do this to prevent a race. To handle removal of a hotpluggable scsi device. On SMP there's a race between the task blocking the scsi device and killing obsolete requests and other tasks queueing no requests. If a task has passed the block before it comes into effect, but the killing task is done with killing requests before the new request can be queued the system will oops.
Simply calling the kernel equivalent of sched_yield() is not an option as the number of runnable tasks can be smaller than the number of CPUs in which case sched_yield is a nop.

You never mentioned doing things within the kernel. It's a lot easier within the kernel.

cd ../linux/drivers/char
grep schedule *.c | more

This will give an idea of the many options available. In the simpist case, you can spin-lock entry into your code, set a semaphore, then schedule() until it changes. You have down(&semaphore) to do the whole thing, or you can do it yourself as in serial.c:

		When the last requst to the device has been
		aborted, your code sets "my_semaphore" to FALSE.
		You have to do in under the "my_lock" lock to
		be free of all races.

		spin_lock_irqsave(&my_lock, flags);
                my_semaphore = FALSE;
                spin_lock_irqrestore(&my_lock, flags);


		driver wait-thread does:
		spin_lock_irqsave(&my_lock, flags);
                my_semaphore = TRUE;
                spin_lock_irqrestore(&my_lock, flags);

		set_current_state(TASK_INTERRUPTIBLE);
                while(my_semaphore == TRUE)
                    schedule();

Note that you can even schedule with the interrupts OFF, but you can't schedule from an interrupt-service routine. There is a difference!

Even if queued requests get cleared before you even look at your semaphore, there is no race.

Cheers,
Dick Johnson

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

"Memory is like gasoline. You use it up when you are running. Of course you get it all back when you reboot..."; Actual explanation obtained from the Micro$oft help desk.

#7 lore raw
In reply to Richard B. Johnson
Quoted 12 lines · Richard B. Johnson

Only an observation:

main()

{
   nice(19);
   for(;;)
       sched_yield(); 
}

does...

[...]

Quoted 2 lines

It consumes 99.1 percent CPU, just spinning.

And, umm, what *exactly* would you expect it to do? It's the only process consuming cpu, and sched_yield() certainly doesn't yield to the idle task. So it's basically the same as a "for(;;);" program, except it spends more time in kernel space and schedules faster when something else needs the cpu.

It's 100% expected behavior.

Ion

Signature · 2 lines
  It is better to keep your mouth shut and be thought a fool,
            than to open it and remove all doubt.