Signal a closed event will still invoke the event notification function,
it could only be exposed when no the DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED
bit set in PcdDebugPropertyMask.
For example:
  gBS->CreateEvent (
                EVT_NOTIFY_SIGNAL,
                TPL_CALLBACK,
                CallbackFun,
                NULL,
                &Event
                );
  gBS->CloseEvent (Event);
  gBS->SignalEvent (Event);      <- CallbackFun still be invoked
Although the case to signal a closed event is abnormal, the code could
still be enhanced to avoid it.
Cc: Liming Gao <liming.gao@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Thomas Palmer <thomas.palmer@hpe.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Star Zeng <star.zeng@intel.com>
Reviewed-by: Liming Gao <liming.gao@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@19754 6f19259b-4bc3-4df7-8a09-765794883524
		
	
		
			
				
	
	
		
			783 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			783 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  UEFI Event support functions implemented in this file.
 | 
						|
 | 
						|
Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
 | 
						|
(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
 | 
						|
This program and the accompanying materials
 | 
						|
are licensed and made available under the terms and conditions of the BSD License
 | 
						|
which accompanies this distribution.  The full text of the license may be found at
 | 
						|
http://opensource.org/licenses/bsd-license.php
 | 
						|
 | 
						|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
 | 
						|
#include "DxeMain.h"
 | 
						|
#include "Event.h"
 | 
						|
 | 
						|
///
 | 
						|
/// gEfiCurrentTpl - Current Task priority level
 | 
						|
///
 | 
						|
EFI_TPL  gEfiCurrentTpl = TPL_APPLICATION;
 | 
						|
 | 
						|
///
 | 
						|
/// gEventQueueLock - Protects the event queues
 | 
						|
///
 | 
						|
EFI_LOCK gEventQueueLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL);
 | 
						|
 | 
						|
///
 | 
						|
/// gEventQueue - A list of event's to notify for each priority level
 | 
						|
///
 | 
						|
LIST_ENTRY      gEventQueue[TPL_HIGH_LEVEL + 1];
 | 
						|
 | 
						|
///
 | 
						|
/// gEventPending - A bitmask of the EventQueues that are pending
 | 
						|
///
 | 
						|
UINTN           gEventPending = 0;
 | 
						|
 | 
						|
///
 | 
						|
/// gEventSignalQueue - A list of events to signal based on EventGroup type
 | 
						|
///
 | 
						|
LIST_ENTRY      gEventSignalQueue = INITIALIZE_LIST_HEAD_VARIABLE (gEventSignalQueue);
 | 
						|
 | 
						|
///
 | 
						|
/// Enumerate the valid types
 | 
						|
///
 | 
						|
UINT32 mEventTable[] = {
 | 
						|
  ///
 | 
						|
  /// 0x80000200       Timer event with a notification function that is
 | 
						|
  /// queue when the event is signaled with SignalEvent()
 | 
						|
  ///
 | 
						|
  EVT_TIMER | EVT_NOTIFY_SIGNAL,
 | 
						|
  ///
 | 
						|
  /// 0x80000000       Timer event without a notification function. It can be
 | 
						|
  /// signaled with SignalEvent() and checked with CheckEvent() or WaitForEvent().
 | 
						|
  ///
 | 
						|
  EVT_TIMER,
 | 
						|
  ///
 | 
						|
  /// 0x00000100       Generic event with a notification function that
 | 
						|
  /// can be waited on with CheckEvent() or WaitForEvent()
 | 
						|
  ///
 | 
						|
  EVT_NOTIFY_WAIT,
 | 
						|
  ///
 | 
						|
  /// 0x00000200       Generic event with a notification function that
 | 
						|
  /// is queue when the event is signaled with SignalEvent()
 | 
						|
  ///
 | 
						|
  EVT_NOTIFY_SIGNAL,
 | 
						|
  ///
 | 
						|
  /// 0x00000201       ExitBootServicesEvent.
 | 
						|
  ///
 | 
						|
  EVT_SIGNAL_EXIT_BOOT_SERVICES,
 | 
						|
  ///
 | 
						|
  /// 0x60000202       SetVirtualAddressMapEvent.
 | 
						|
  ///
 | 
						|
  EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
 | 
						|
 | 
						|
  ///
 | 
						|
  /// 0x00000000       Generic event without a notification function.
 | 
						|
  /// It can be signaled with SignalEvent() and checked with CheckEvent()
 | 
						|
  /// or WaitForEvent().
 | 
						|
  ///
 | 
						|
  0x00000000,
 | 
						|
  ///
 | 
						|
  /// 0x80000100       Timer event with a notification function that can be
 | 
						|
  /// waited on with CheckEvent() or WaitForEvent()
 | 
						|
  ///
 | 
						|
  EVT_TIMER | EVT_NOTIFY_WAIT,
 | 
						|
};
 | 
						|
 | 
						|
///
 | 
						|
/// gIdleLoopEvent - Event which is signalled when the core is idle
 | 
						|
///
 | 
						|
EFI_EVENT       gIdleLoopEvent = NULL;
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Enter critical section by acquiring the lock on gEventQueueLock.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
CoreAcquireEventLock (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  CoreAcquireLock (&gEventQueueLock);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Exit critical section by releasing the lock on gEventQueueLock.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
CoreReleaseEventLock (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  CoreReleaseLock (&gEventQueueLock);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Initializes "event" support.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            Always return success
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
CoreInitializeEventServices (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN        Index;
 | 
						|
 | 
						|
  for (Index=0; Index <= TPL_HIGH_LEVEL; Index++) {
 | 
						|
    InitializeListHead (&gEventQueue[Index]);
 | 
						|
  }
 | 
						|
 | 
						|
  CoreInitializeTimer ();
 | 
						|
 | 
						|
  CoreCreateEventEx (
 | 
						|
    EVT_NOTIFY_SIGNAL,
 | 
						|
    TPL_NOTIFY,
 | 
						|
    CoreEmptyCallbackFunction,
 | 
						|
    NULL,
 | 
						|
    &gIdleLoopEventGuid,
 | 
						|
    &gIdleLoopEvent
 | 
						|
    );
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Dispatches all pending events.
 | 
						|
 | 
						|
  @param  Priority               The task priority level of event notifications
 | 
						|
                                 to dispatch
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
CoreDispatchEventNotifies (
 | 
						|
  IN EFI_TPL      Priority
 | 
						|
  )
 | 
						|
{
 | 
						|
  IEVENT          *Event;
 | 
						|
  LIST_ENTRY      *Head;
 | 
						|
 | 
						|
  CoreAcquireEventLock ();
 | 
						|
  ASSERT (gEventQueueLock.OwnerTpl == Priority);
 | 
						|
  Head = &gEventQueue[Priority];
 | 
						|
 | 
						|
  //
 | 
						|
  // Dispatch all the pending notifications
 | 
						|
  //
 | 
						|
  while (!IsListEmpty (Head)) {
 | 
						|
 | 
						|
    Event = CR (Head->ForwardLink, IEVENT, NotifyLink, EVENT_SIGNATURE);
 | 
						|
    RemoveEntryList (&Event->NotifyLink);
 | 
						|
 | 
						|
    Event->NotifyLink.ForwardLink = NULL;
 | 
						|
 | 
						|
    //
 | 
						|
    // Only clear the SIGNAL status if it is a SIGNAL type event.
 | 
						|
    // WAIT type events are only cleared in CheckEvent()
 | 
						|
    //
 | 
						|
    if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) {
 | 
						|
      Event->SignalCount = 0;
 | 
						|
    }
 | 
						|
 | 
						|
    CoreReleaseEventLock ();
 | 
						|
 | 
						|
    //
 | 
						|
    // Notify this event
 | 
						|
    //
 | 
						|
    ASSERT (Event->NotifyFunction != NULL);
 | 
						|
    Event->NotifyFunction (Event, Event->NotifyContext);
 | 
						|
 | 
						|
    //
 | 
						|
    // Check for next pending event
 | 
						|
    //
 | 
						|
    CoreAcquireEventLock ();
 | 
						|
  }
 | 
						|
 | 
						|
  gEventPending &= ~(UINTN)(1 << Priority);
 | 
						|
  CoreReleaseEventLock ();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Queues the event's notification function to fire.
 | 
						|
 | 
						|
  @param  Event                  The Event to notify
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
CoreNotifyEvent (
 | 
						|
  IN  IEVENT      *Event
 | 
						|
  )
 | 
						|
{
 | 
						|
 | 
						|
  //
 | 
						|
  // Event database must be locked
 | 
						|
  //
 | 
						|
  ASSERT_LOCKED (&gEventQueueLock);
 | 
						|
 | 
						|
  //
 | 
						|
  // If the event is queued somewhere, remove it
 | 
						|
  //
 | 
						|
 | 
						|
  if (Event->NotifyLink.ForwardLink != NULL) {
 | 
						|
    RemoveEntryList (&Event->NotifyLink);
 | 
						|
    Event->NotifyLink.ForwardLink = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Queue the event to the pending notification list
 | 
						|
  //
 | 
						|
 | 
						|
  InsertTailList (&gEventQueue[Event->NotifyTpl], &Event->NotifyLink);
 | 
						|
  gEventPending |= (UINTN)(1 << Event->NotifyTpl);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Signals all events in the EventGroup.
 | 
						|
 | 
						|
  @param  EventGroup             The list to signal
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
CoreNotifySignalList (
 | 
						|
  IN EFI_GUID     *EventGroup
 | 
						|
  )
 | 
						|
{
 | 
						|
  LIST_ENTRY              *Link;
 | 
						|
  LIST_ENTRY              *Head;
 | 
						|
  IEVENT                  *Event;
 | 
						|
 | 
						|
  CoreAcquireEventLock ();
 | 
						|
 | 
						|
  Head = &gEventSignalQueue;
 | 
						|
  for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
 | 
						|
    Event = CR (Link, IEVENT, SignalLink, EVENT_SIGNATURE);
 | 
						|
    if (CompareGuid (&Event->EventGroup, EventGroup)) {
 | 
						|
      CoreNotifyEvent (Event);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  CoreReleaseEventLock ();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Creates an event.
 | 
						|
 | 
						|
  @param  Type                   The type of event to create and its mode and
 | 
						|
                                 attributes
 | 
						|
  @param  NotifyTpl              The task priority level of event notifications
 | 
						|
  @param  NotifyFunction         Pointer to the events notification function
 | 
						|
  @param  NotifyContext          Pointer to the notification functions context;
 | 
						|
                                 corresponds to parameter "Context" in the
 | 
						|
                                 notification function
 | 
						|
  @param  Event                  Pointer to the newly created event if the call
 | 
						|
                                 succeeds; undefined otherwise
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The event structure was created
 | 
						|
  @retval EFI_INVALID_PARAMETER  One of the parameters has an invalid value
 | 
						|
  @retval EFI_OUT_OF_RESOURCES   The event could not be allocated
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
CoreCreateEvent (
 | 
						|
  IN UINT32                   Type,
 | 
						|
  IN EFI_TPL                  NotifyTpl,
 | 
						|
  IN EFI_EVENT_NOTIFY         NotifyFunction, OPTIONAL
 | 
						|
  IN VOID                     *NotifyContext, OPTIONAL
 | 
						|
  OUT EFI_EVENT               *Event
 | 
						|
  )
 | 
						|
{
 | 
						|
  return CoreCreateEventEx (Type, NotifyTpl, NotifyFunction, NotifyContext, NULL, Event);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Creates an event in a group.
 | 
						|
 | 
						|
  @param  Type                   The type of event to create and its mode and
 | 
						|
                                 attributes
 | 
						|
  @param  NotifyTpl              The task priority level of event notifications
 | 
						|
  @param  NotifyFunction         Pointer to the events notification function
 | 
						|
  @param  NotifyContext          Pointer to the notification functions context;
 | 
						|
                                 corresponds to parameter "Context" in the
 | 
						|
                                 notification function
 | 
						|
  @param  EventGroup             GUID for EventGroup if NULL act the same as
 | 
						|
                                 gBS->CreateEvent().
 | 
						|
  @param  Event                  Pointer to the newly created event if the call
 | 
						|
                                 succeeds; undefined otherwise
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The event structure was created
 | 
						|
  @retval EFI_INVALID_PARAMETER  One of the parameters has an invalid value
 | 
						|
  @retval EFI_OUT_OF_RESOURCES   The event could not be allocated
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
CoreCreateEventEx (
 | 
						|
  IN UINT32                   Type,
 | 
						|
  IN EFI_TPL                  NotifyTpl,
 | 
						|
  IN EFI_EVENT_NOTIFY         NotifyFunction, OPTIONAL
 | 
						|
  IN CONST VOID               *NotifyContext, OPTIONAL
 | 
						|
  IN CONST EFI_GUID           *EventGroup,    OPTIONAL
 | 
						|
  OUT EFI_EVENT               *Event
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // If it's a notify type of event, check for invalid NotifyTpl
 | 
						|
  //
 | 
						|
  if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) {
 | 
						|
    if (NotifyTpl != TPL_APPLICATION &&
 | 
						|
        NotifyTpl != TPL_CALLBACK &&
 | 
						|
        NotifyTpl != TPL_NOTIFY) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return CoreCreateEventInternal (Type, NotifyTpl, NotifyFunction, NotifyContext, EventGroup, Event);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Creates a general-purpose event structure
 | 
						|
 | 
						|
  @param  Type                   The type of event to create and its mode and
 | 
						|
                                 attributes
 | 
						|
  @param  NotifyTpl              The task priority level of event notifications
 | 
						|
  @param  NotifyFunction         Pointer to the events notification function
 | 
						|
  @param  NotifyContext          Pointer to the notification functions context;
 | 
						|
                                 corresponds to parameter "Context" in the
 | 
						|
                                 notification function
 | 
						|
  @param  EventGroup             GUID for EventGroup if NULL act the same as
 | 
						|
                                 gBS->CreateEvent().
 | 
						|
  @param  Event                  Pointer to the newly created event if the call
 | 
						|
                                 succeeds; undefined otherwise
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The event structure was created
 | 
						|
  @retval EFI_INVALID_PARAMETER  One of the parameters has an invalid value
 | 
						|
  @retval EFI_OUT_OF_RESOURCES   The event could not be allocated
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
CoreCreateEventInternal (
 | 
						|
  IN UINT32                   Type,
 | 
						|
  IN EFI_TPL                  NotifyTpl,
 | 
						|
  IN EFI_EVENT_NOTIFY         NotifyFunction, OPTIONAL
 | 
						|
  IN CONST VOID               *NotifyContext, OPTIONAL
 | 
						|
  IN CONST EFI_GUID           *EventGroup,    OPTIONAL
 | 
						|
  OUT EFI_EVENT               *Event
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS      Status;
 | 
						|
  IEVENT          *IEvent;
 | 
						|
  INTN            Index;
 | 
						|
 | 
						|
 | 
						|
  if (Event == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check to make sure no reserved flags are set
 | 
						|
  //
 | 
						|
  Status = EFI_INVALID_PARAMETER;
 | 
						|
  for (Index = 0; Index < (sizeof (mEventTable) / sizeof (UINT32)); Index++) {
 | 
						|
     if (Type == mEventTable[Index]) {
 | 
						|
       Status = EFI_SUCCESS;
 | 
						|
       break;
 | 
						|
     }
 | 
						|
  }
 | 
						|
  if(EFI_ERROR (Status)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Convert Event type for pre-defined Event groups
 | 
						|
  //
 | 
						|
  if (EventGroup != NULL) {
 | 
						|
    //
 | 
						|
    // For event group, type EVT_SIGNAL_EXIT_BOOT_SERVICES and EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
 | 
						|
    // are not valid
 | 
						|
    //
 | 
						|
    if ((Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) || (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE)) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
    if (CompareGuid (EventGroup, &gEfiEventExitBootServicesGuid)) {
 | 
						|
      Type = EVT_SIGNAL_EXIT_BOOT_SERVICES;
 | 
						|
    } else if (CompareGuid (EventGroup, &gEfiEventVirtualAddressChangeGuid)) {
 | 
						|
      Type = EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // Convert EFI 1.10 Events to their UEFI 2.0 CreateEventEx mapping
 | 
						|
    //
 | 
						|
    if (Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) {
 | 
						|
      EventGroup = &gEfiEventExitBootServicesGuid;
 | 
						|
    } else if (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) {
 | 
						|
      EventGroup = &gEfiEventVirtualAddressChangeGuid;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // If it's a notify type of event, check its parameters
 | 
						|
  //
 | 
						|
  if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) {
 | 
						|
    //
 | 
						|
    // Check for an invalid NotifyFunction or NotifyTpl
 | 
						|
    //
 | 
						|
    if ((NotifyFunction == NULL) ||
 | 
						|
        (NotifyTpl <= TPL_APPLICATION) ||
 | 
						|
       (NotifyTpl >= TPL_HIGH_LEVEL)) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // No notification needed, zero ignored values
 | 
						|
    //
 | 
						|
    NotifyTpl = 0;
 | 
						|
    NotifyFunction = NULL;
 | 
						|
    NotifyContext = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Allocate and initialize a new event structure.
 | 
						|
  //
 | 
						|
  if ((Type & EVT_RUNTIME) != 0) {
 | 
						|
    IEvent = AllocateRuntimeZeroPool (sizeof (IEVENT));
 | 
						|
  } else {
 | 
						|
    IEvent = AllocateZeroPool (sizeof (IEVENT));
 | 
						|
  }
 | 
						|
  if (IEvent == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  IEvent->Signature = EVENT_SIGNATURE;
 | 
						|
  IEvent->Type = Type;
 | 
						|
 | 
						|
  IEvent->NotifyTpl      = NotifyTpl;
 | 
						|
  IEvent->NotifyFunction = NotifyFunction;
 | 
						|
  IEvent->NotifyContext  = (VOID *)NotifyContext;
 | 
						|
  if (EventGroup != NULL) {
 | 
						|
    CopyGuid (&IEvent->EventGroup, EventGroup);
 | 
						|
    IEvent->ExFlag |= EVT_EXFLAG_EVENT_GROUP;
 | 
						|
  }
 | 
						|
 | 
						|
  *Event = IEvent;
 | 
						|
 | 
						|
  if ((Type & EVT_RUNTIME) != 0) {
 | 
						|
    //
 | 
						|
    // Keep a list of all RT events so we can tell the RT AP.
 | 
						|
    //
 | 
						|
    IEvent->RuntimeData.Type           = Type;
 | 
						|
    IEvent->RuntimeData.NotifyTpl      = NotifyTpl;
 | 
						|
    IEvent->RuntimeData.NotifyFunction = NotifyFunction;
 | 
						|
    IEvent->RuntimeData.NotifyContext  = (VOID *) NotifyContext;
 | 
						|
    IEvent->RuntimeData.Event          = (EFI_EVENT *) IEvent;
 | 
						|
    InsertTailList (&gRuntime->EventHead, &IEvent->RuntimeData.Link);
 | 
						|
  }
 | 
						|
 | 
						|
  CoreAcquireEventLock ();
 | 
						|
 | 
						|
  if ((Type & EVT_NOTIFY_SIGNAL) != 0x00000000) {
 | 
						|
    //
 | 
						|
    // The Event's NotifyFunction must be queued whenever the event is signaled
 | 
						|
    //
 | 
						|
    InsertHeadList (&gEventSignalQueue, &IEvent->SignalLink);
 | 
						|
  }
 | 
						|
 | 
						|
  CoreReleaseEventLock ();
 | 
						|
 | 
						|
  //
 | 
						|
  // Done
 | 
						|
  //
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Signals the event.  Queues the event to be notified if needed.
 | 
						|
 | 
						|
  @param  UserEvent              The event to signal .
 | 
						|
 | 
						|
  @retval EFI_INVALID_PARAMETER  Parameters are not valid.
 | 
						|
  @retval EFI_SUCCESS            The event was signaled.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
CoreSignalEvent (
 | 
						|
  IN EFI_EVENT    UserEvent
 | 
						|
  )
 | 
						|
{
 | 
						|
  IEVENT          *Event;
 | 
						|
 | 
						|
  Event = UserEvent;
 | 
						|
 | 
						|
  if (Event == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Event->Signature != EVENT_SIGNATURE) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  CoreAcquireEventLock ();
 | 
						|
 | 
						|
  //
 | 
						|
  // If the event is not already signalled, do so
 | 
						|
  //
 | 
						|
 | 
						|
  if (Event->SignalCount == 0x00000000) {
 | 
						|
    Event->SignalCount++;
 | 
						|
 | 
						|
    //
 | 
						|
    // If signalling type is a notify function, queue it
 | 
						|
    //
 | 
						|
    if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) {
 | 
						|
      if ((Event->ExFlag & EVT_EXFLAG_EVENT_GROUP) != 0) {
 | 
						|
        //
 | 
						|
        // The CreateEventEx() style requires all members of the Event Group
 | 
						|
        //  to be signaled.
 | 
						|
        //
 | 
						|
        CoreReleaseEventLock ();
 | 
						|
        CoreNotifySignalList (&Event->EventGroup);
 | 
						|
        CoreAcquireEventLock ();
 | 
						|
       } else {
 | 
						|
        CoreNotifyEvent (Event);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  CoreReleaseEventLock ();
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Check the status of an event.
 | 
						|
 | 
						|
  @param  UserEvent              The event to check
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The event is in the signaled state
 | 
						|
  @retval EFI_NOT_READY          The event is not in the signaled state
 | 
						|
  @retval EFI_INVALID_PARAMETER  Event is of type EVT_NOTIFY_SIGNAL
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
CoreCheckEvent (
 | 
						|
  IN EFI_EVENT        UserEvent
 | 
						|
  )
 | 
						|
{
 | 
						|
  IEVENT      *Event;
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  Event = UserEvent;
 | 
						|
 | 
						|
  if (Event == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Event->Signature != EVENT_SIGNATURE) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = EFI_NOT_READY;
 | 
						|
 | 
						|
  if ((Event->SignalCount == 0) && ((Event->Type & EVT_NOTIFY_WAIT) != 0)) {
 | 
						|
 | 
						|
    //
 | 
						|
    // Queue the wait notify function
 | 
						|
    //
 | 
						|
    CoreAcquireEventLock ();
 | 
						|
    if (Event->SignalCount == 0) {
 | 
						|
      CoreNotifyEvent (Event);
 | 
						|
    }
 | 
						|
    CoreReleaseEventLock ();
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // If the even looks signalled, get the lock and clear it
 | 
						|
  //
 | 
						|
 | 
						|
  if (Event->SignalCount != 0) {
 | 
						|
    CoreAcquireEventLock ();
 | 
						|
 | 
						|
    if (Event->SignalCount != 0) {
 | 
						|
      Event->SignalCount = 0;
 | 
						|
      Status = EFI_SUCCESS;
 | 
						|
    }
 | 
						|
 | 
						|
    CoreReleaseEventLock ();
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Stops execution until an event is signaled.
 | 
						|
 | 
						|
  @param  NumberOfEvents         The number of events in the UserEvents array
 | 
						|
  @param  UserEvents             An array of EFI_EVENT
 | 
						|
  @param  UserIndex              Pointer to the index of the event which
 | 
						|
                                 satisfied the wait condition
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The event indicated by Index was signaled.
 | 
						|
  @retval EFI_INVALID_PARAMETER  The event indicated by Index has a notification
 | 
						|
                                 function or Event was not a valid type
 | 
						|
  @retval EFI_UNSUPPORTED        The current TPL is not TPL_APPLICATION
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
CoreWaitForEvent (
 | 
						|
  IN UINTN        NumberOfEvents,
 | 
						|
  IN EFI_EVENT    *UserEvents,
 | 
						|
  OUT UINTN       *UserIndex
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS      Status;
 | 
						|
  UINTN           Index;
 | 
						|
 | 
						|
  //
 | 
						|
  // Can only WaitForEvent at TPL_APPLICATION
 | 
						|
  //
 | 
						|
  if (gEfiCurrentTpl != TPL_APPLICATION) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  if (NumberOfEvents == 0) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (UserEvents == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  for(;;) {
 | 
						|
 | 
						|
    for(Index = 0; Index < NumberOfEvents; Index++) {
 | 
						|
 | 
						|
      Status = CoreCheckEvent (UserEvents[Index]);
 | 
						|
 | 
						|
      //
 | 
						|
      // provide index of event that caused problem
 | 
						|
      //
 | 
						|
      if (Status != EFI_NOT_READY) {
 | 
						|
        if (UserIndex != NULL) {
 | 
						|
          *UserIndex = Index;
 | 
						|
        }
 | 
						|
        return Status;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Signal the Idle event
 | 
						|
    //
 | 
						|
    CoreSignalEvent (gIdleLoopEvent);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Closes an event and frees the event structure.
 | 
						|
 | 
						|
  @param  UserEvent              Event to close
 | 
						|
 | 
						|
  @retval EFI_INVALID_PARAMETER  Parameters are not valid.
 | 
						|
  @retval EFI_SUCCESS            The event has been closed
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
CoreCloseEvent (
 | 
						|
  IN EFI_EVENT    UserEvent
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  IEVENT      *Event;
 | 
						|
 | 
						|
  Event = UserEvent;
 | 
						|
 | 
						|
  if (Event == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Event->Signature != EVENT_SIGNATURE) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // If it's a timer event, make sure it's not pending
 | 
						|
  //
 | 
						|
  if ((Event->Type & EVT_TIMER) != 0) {
 | 
						|
    CoreSetTimer (Event, TimerCancel, 0);
 | 
						|
  }
 | 
						|
 | 
						|
  CoreAcquireEventLock ();
 | 
						|
 | 
						|
  //
 | 
						|
  // If the event is queued somewhere, remove it
 | 
						|
  //
 | 
						|
 | 
						|
  if (Event->RuntimeData.Link.ForwardLink != NULL) {
 | 
						|
    RemoveEntryList (&Event->RuntimeData.Link);
 | 
						|
  }
 | 
						|
 | 
						|
  if (Event->NotifyLink.ForwardLink != NULL) {
 | 
						|
    RemoveEntryList (&Event->NotifyLink);
 | 
						|
  }
 | 
						|
 | 
						|
  if (Event->SignalLink.ForwardLink != NULL) {
 | 
						|
    RemoveEntryList (&Event->SignalLink);
 | 
						|
  }
 | 
						|
 | 
						|
  CoreReleaseEventLock ();
 | 
						|
 | 
						|
  //
 | 
						|
  // If the event is registered on a protocol notify, then remove it from the protocol database
 | 
						|
  //
 | 
						|
  if ((Event->ExFlag & EVT_EXFLAG_EVENT_PROTOCOL_NOTIFICATION) != 0) {
 | 
						|
    CoreUnregisterProtocolNotify (Event);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // To avoid the Event to be signalled wrongly after closed,
 | 
						|
  // clear the Signature of Event before free pool.
 | 
						|
  //
 | 
						|
  Event->Signature = 0;
 | 
						|
  Status = CoreFreePool (Event);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 |