guess…it works bcoz…of very low systems resources usage…i a heavy usage scenario…u r certain to get a crash…
I think wat Don Scott and Max said is right…
guess…it works bcoz…of very low systems resources usage…i a heavy usage scenario…u r certain to get a crash…
I think wat Don Scott and Max said is right…
>> Note that scheduler does not need the concept of time just plain and simple.
This is a true “masterpiece” - no more comments needed…
Exactly so, the Windows scheduler only concerned about time if a) KTIMER is signaled b) quantum ends.
Really??? What about the foreground window ending its wait???
How a window can wait?
What about GUI thread after wake up ??
Oh, sorry, forgot this. user32/win32k raises the priority of the thread which owns the foreground window.
BTW - this is switchable off by “Optimize for… Background Services” in the Control Panel, which is a default for server OSes.
Does it have to wait until process in the background (probably, with no user interaction at all) works out
its quantum???
Working out a quantum occurs very rarely. Usually, the process stops at some blocking path - read() or GetMessage or such.
But if it yields the CPU voluntarily its remaining quantum gets saved, and thread gets subsequent
short-term priority boost.
Where is it described? never heard about this boost in actual Windows. KeSetEvent boosts are yes, really here.
–
Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com
> Certainly one can imagine a scheduler that acted only on thread yields
or interrupt state change and did not concern itself with clock ticks.
You forgot the actual main source of preemption - thread awakening by KeSetEvent or a similar call.
This - and not the timer IRQ itself - is the main source of preemptions in Windows.
–
Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com
> Actually there are a number of old real-time OS’es which did just that. So
before you slam the concept understand the goals of the system, it makes
sense in some cases.
His main wrong point is the statement that, after KeSetEvent and similar calls, Windows waits for the next timer tick to actually switch to the just-awake thread.
This statement contradicts my real-world practice in optimizing multi-threaded code (to saturate the hard disk, for instance) a lot.
–
Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com
>> But if it yields the CPU voluntarily its remaining quantum gets saved, and thread gets subsequent >>short-term priority boost.
Where is it described? never heard about this boost in actual Windows.
IIRC, in “Windows Internals”…
.
His main wrong point is the statement that, after KeSetEvent and similar calls, Windows waits
for the next timer tick to actually switch to the just-awake thread.
Actually, I haven’t said anything about KeSetEvent(), but it is really good that you mentioned it, because this function is callable at elevated IRQL. Let’s say lower-priority thread unblocks higher-priority one in DPC routine. It is understandable that context switch cannot occur at this point - instead, KeSetEvent() has to queue a DPC to do this part.
What I had apparently overlooked here is that DPC that performs context switches may get queued not only by timer interrupt - instead, yielding thread may set just IRQL to DPC level, insert this lowest-priority DPC into a queue and switch to the idle thread…
Anton Bassov
>ority one in DPC routine. It is understandable that context switch cannot occur at this point - instead,
KeSetEvent() has to queue a DPC to do this part.
No need for a DPC for this, the dispatcher can have some special heuristic for this, which is not DPC.
Actually, this is what PCR::StandbyThread is for. KeSetEvent chooses the new StandbyThread. If several KeSetEvents are called in a row still on DISPATCH_LEVEL - then StandbyThread is updated several times, but CurrentThread is not.
At IRQL lower to < DISPATCH, just before releasing the dispatcher lock, StandbyThread is actually switched into.
What I had apparently overlooked here is that DPC that performs context switches may get queued
not only by timer interrupt
Yes, your main wrong point was that the new thread is picked for execution only after a timer tick, which contradicts the practical measurements on a heavy-loaded multithreaded software.
–
Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com
> No need for a DPC for this, the dispatcher can have some special heuristic for this, which is not DPC.
Actually, this is what PCR::StandbyThread is for. KeSetEvent chooses the new StandbyThread.
If several KeSetEvents are called in a row still on DISPATCH_LEVEL - then StandbyThread
is updated several times, but CurrentThread is not.
Is not it easier just to set an event to a signaled state and to add it to the list of dispatcher objects
that have to be processed more thoroughly (i.e checking the list of threads that wait on it and setting
thread to a ready state if all wait conditions have been satisfied ) before any “real” thread is allowed to proceed on a given CPU???
Anton Bassov
> Is not it easier just to set an event to a signaled state and to add it to the list of dispatcher objects
that have to be processed more thoroughly
No, because KEVENT has no field for the node of this list
–
Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com
>
If the contract says you can’t do it, and you do it anyway, is the
resulting behaviour really a bug? This is kernel space not user space,
so it is up to the caller to check the inputs, not the callee.That said, the docs for KeRaiseIrql say “If the new IRQL is less than
the current IRQL, a bug check occurs”, and it clearly doesn’t under
2K3,
even when the verifier is running (just tried it [1]). If the first
line
in KeDelayExecutionThread was KeRaiseIrql(APC_LEVEL, &old_irql) and
KeDelayExecutionThread was called at HIGH_LEVEL, the the current IRQL
would be changed to APC_LEVEL and old_irql = HIGH_LEVEL without any
fuss
at all (aside from the obvious[1] The code I tested this with, which starts at APC_LEVEL is:
KIRQL old_irql1, old_irql2;
KdPrint((" A Irql = %d\n", KeGetCurrentIrql()));
KeRaiseIrql(HIGH_LEVEL, &old_irql1);
KdPrint((" B Irql = %d\n", KeGetCurrentIrql()));
KeRaiseIrql(PASSIVE_LEVEL, &old_irql2);
KdPrint((" C Irql = %d\n", KeGetCurrentIrql()));
KeLowerIrql(old_irql2);
KdPrint((" D Irql = %d\n", KeGetCurrentIrql()));
KeLowerIrql(old_irql1);
KdPrint((" E Irql = %d\n", KeGetCurrentIrql()));And the output was:
A Irql = 1
B Irql = 31
C Irql = 0
D Irql = 31
E Irql = 1
Daniel Mihai from Microsoft just tried to reproduce the above with the
verifier running and got a BSoD. I tried again and also got a BSoD.
Embarassingly, I now suspect that the verifier wasn’t actually running
when I did those tests.
Without the verifier, the BSoD does not occur. Sorry for the confusion.
James