Eugene,
I think this is the way it works. CoreCheckEvent() and CoreSignalEven() both
have locks that raise to TPL_HIGH_LEVEL. But we never signal (call an events
Notify Function) an event at TPL_HIGH_LEVEL.
What if NumberOfEvents > 1 and the 1st event is checked, and then a timer tick
happens that makes the 1st event complete? So your ">> what if a timer tick
happens here?? <<" window is quite large. It seems like a tradeoff of masking
interrupts for a very very long time or realizing that you may delay an entire
timer tick. Given the point is to save power waiting a little extra time helps
save power. There will always be a tradeoff between saving power and
performance.
You could chose not to implement the gIdleLoopEventGuid for your platform if
you are concerned about high performance in a WaitForEvent(). You could also
crank up your timer period.
The common case for WaitForEvent() would be sitting at the shell prompt (or the
message loop for some GUI UI). You burn a lot of power doing nothing (running
C code that will not accomplish anything until the next tick). Since you are
generally waiting for a human they generally will not notice that you were in a
lower power state for an extra tick. We are boot firmware and not an RTOS after
all ,and we have a signal model, not threads.
Andrew Fish
https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2/MdeModulePkg/Core/Dxe/Event/Event.c
On Feb 12, 2013, at 11:05 AM, "Cohen, Eugene" <eug...@hp.com> wrote:
> It appears that there is a race condition in WaitForEvent... after all events
> are checked the idle event is signaled. But if a timer tick interrupt comes
> in and schedules work (SignalEvent) after the loop is done but before the
> event is signaled, we will delay unnecessarily for an additional timer tick
> interrupt (due to an HLT or WFI) before the event is recognized. This could
> have a performance impact if WaitForEvent is used in a tight loop waiting for
> IO.
>
> for(;;) {
>
> for(Index = 0; Index < NumberOfEvents; Index++) {
>
> Status = CoreCheckEvent (UserEvents[Index]);
>
> //
> // provide index of event that caused problem
> //
> if (Status != EFI_NOT_READY) {
> *UserIndex = Index;
> return Status;
> }
> }
>
> >> what if a timer tick happens here?? <<
>
> //
> // Signal the Idle event
> //
> CoreSignalEvent (gIdleLoopEvent);
> }
> }
>
> I think the solution is that interrupts must be disabled while deciding if
> there is work to do. It looks like ARM, IA32, and X64 architectures have
> this exposure.
>
> I researched if it possible to do WFI/HLT with interrupts masked off. On ARM
> it is valid to issue a WFI with IRQ and FIQ masked off since it will unblock
> with pending (but masked interrupts). On IA it’s a bit trickier since HLT
> will hang forever if interrupts are masked off. From what I’ve read
> (although I could not find an authoritative statement in the IA
> documentation), the solution is that an ‘STI; HLT’ together will allow the
> halt to be bypassed if an interrupt is pending (see
> http://lists.freebsd.org/pipermail/freebsd-current/2004-June/029369.html ).
>
If you have more knowledge about the X64 processor you can do better than Halt
, also called C1 (C0 is running). That CPU specific driver can also set up P
states, basically how much power gets used in C0.
> Eugene
>
------------------------------------------------------------------------------
Free Next-Gen Firewall Hardware Offer
Buy your Sophos next-gen firewall before the end March 2013
and get the hardware for free! Learn more.
http://p.sf.net/sfu/sophos-d2d-feb
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/edk2-devel