EFI Group Event Callback Order


Li, Walon <walon.li@...>
 

Hi edk2,

 

As UEFI event group mechanism, we can register callbacks under event group. For example, register two event callbacks and will be signal in ReadyToBoot.

  Status = gBS->CreateEventEx (

                  EVT_NOTIFY_SIGNAL,

                  TPL_CALLBACK,

                  TestCallback1,

                  NULL,

                  &gEfiEventReadyToBootGuid,

                  &ReadyToBootEvent

                  );

  Status = gBS->CreateEventEx (

                  EVT_NOTIFY_SIGNAL,

                  TPL_CALLBACK,

                  TestCallback2,

                  NULL,

                  &gEfiEventReadyToBootGuid,

                  &ReadyToBootEvent

                  );

I'm curious the order of callback. In this case, the order is LIFO and TestCallback2 will be executed than TestCallback1.

As the UEFI spec page 152, only said "If the supplied Event is a part of an event group, then all of the events in the event group are also signaled and their notification functions are scheduled." It doesn't define order clearly.

 

However, edk2 has different implementation in EVT_RUNTIME / EVT_NOTIFY_SIGNAL attribute of group event. In Event.c, it inserts new event to Head in EVT_NOTIFY_SIGNAL queue (LIFO) and inserts to Tail in EVT_RUNTIME queue (FIFO).

I know the programmer shouldn't assume any order but want to know why is different implementation in group event. Have any history reason or limitation?

 

  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;

    //

    // Work around the bug in the Platform Init specification (v1.7), reported

    // as Mantis#2017: "EFI_RUNTIME_EVENT_ENTRY.Event" should have type

    // EFI_EVENT, not (EFI_EVENT*). The PI spec documents the field correctly

    // as "The EFI_EVENT returned by CreateEvent()", but the type of the field

    // doesn't match the natural language description. Therefore we need an

    // explicit cast here.

    //

   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);

  }

 

Thank you,

Walon


Laszlo Ersek
 

On 01/16/20 09:32, Li, Walon wrote:
Hi edk2,

As UEFI event group mechanism, we can register callbacks under event group. For example, register two event callbacks and will be signal in ReadyToBoot.
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
TestCallback1,
NULL,
&gEfiEventReadyToBootGuid,
&ReadyToBootEvent
);
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
TestCallback2,
NULL,
&gEfiEventReadyToBootGuid,
&ReadyToBootEvent
);
I'm curious the order of callback.
It's unspecified. Implementations may differ, and an implementation
isn't even required to be self-consistent wrt. the order.

Ordering is only specified in terms of TPLs.

Thanks
Laszlo


Li, Walon
 

Laszlo,

Yes, we can specific TPL to adjust callback order. But sometimes, an event has many callbacks like as ReadyToBoot and TPL level may not satisfy purpose.
In UEFI spec CreateEvent chapter, also mentioned "The functions in these queues are invoked in FIFO order". So, if it define clearly in UEFI spec, LIFO or FIFO, we may use driver dependency to decide which driver's event registration priority and specific callback order indirectly.

Thank you,
Walon

-----Original Message-----
From: Laszlo Ersek [mailto:lersek@redhat.com]
Sent: Friday, January 17, 2020 4:09 PM
To: discuss@edk2.groups.io; Li, Walon <walon.li@hpe.com>
Subject: Re: [edk2-discuss] EFI Group Event Callback Order

On 01/16/20 09:32, Li, Walon wrote:
Hi edk2,

As UEFI event group mechanism, we can register callbacks under event group. For example, register two event callbacks and will be signal in ReadyToBoot.
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
TestCallback1,
NULL,
&gEfiEventReadyToBootGuid,
&ReadyToBootEvent
);
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
TestCallback2,
NULL,
&gEfiEventReadyToBootGuid,
&ReadyToBootEvent
);
I'm curious the order of callback. In this case, the order is LIFO and TestCallback2 will be executed than TestCallback1.
As the UEFI spec page 152, only said "If the supplied Event is a part of an event group, then all of the events in the event group are also signaled and their notification functions are scheduled." It doesn't define order clearly.

However, edk2 has different implementation in EVT_RUNTIME / EVT_NOTIFY_SIGNAL attribute of group event. In Event.c, it inserts new event to Head in EVT_NOTIFY_SIGNAL queue (LIFO) and inserts to Tail in EVT_RUNTIME queue (FIFO).
I know the programmer shouldn't assume any order but want to know why is different implementation in group event. Have any history reason or limitation?

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;
//
// Work around the bug in the Platform Init specification (v1.7), reported
// as Mantis#2017: "EFI_RUNTIME_EVENT_ENTRY.Event" should have type
// EFI_EVENT, not (EFI_EVENT*). The PI spec documents the field correctly
// as "The EFI_EVENT returned by CreateEvent()", but the type of the field
// doesn't match the natural language description. Therefore we need an
// explicit cast here.
//
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);
}

Thank you,
Walon

It's unspecified. Implementations may differ, and an implementation isn't even required to be self-consistent wrt. the order.

Ordering is only specified in terms of TPLs.

Thanks
Laszlo


Tomas Pilar (tpilar)
 

I had to solve this for myself by creating a PostReadyToBoot event that is signalled by my ReadyToBoot callback. That meant that my PostReadyToBoot callbacks got executed after all the ReadyToBoot event functions.

Cheers,
Tom
________________________________________
From: discuss@edk2.groups.io <discuss@edk2.groups.io> on behalf of Li, Walon <walon.li@hpe.com>
Sent: 17 January 2020 13:24
To: discuss@edk2.groups.io; Laszlo Ersek
Cc: Wei, Kent (HPS SW); Wang, Sunny (HPS SW); Chang, Abner (HPS SW/FW Technologist); Spottswood, Jason; Shifflett, Joseph; Haskell, Darrell; Wiginton, Scott
Subject: Re: [edk2-discuss] EFI Group Event Callback Order

Laszlo,

Yes, we can specific TPL to adjust callback order. But sometimes, an event has many callbacks like as ReadyToBoot and TPL level may not satisfy purpose.
In UEFI spec CreateEvent chapter, also mentioned "The functions in these queues are invoked in FIFO order". So, if it define clearly in UEFI spec, LIFO or FIFO, we may use driver dependency to decide which driver's event registration priority and specific callback order indirectly.

Thank you,
Walon

-----Original Message-----
From: Laszlo Ersek [mailto:lersek@redhat.com]
Sent: Friday, January 17, 2020 4:09 PM
To: discuss@edk2.groups.io; Li, Walon <walon.li@hpe.com>
Subject: Re: [edk2-discuss] EFI Group Event Callback Order

On 01/16/20 09:32, Li, Walon wrote:
Hi edk2,

As UEFI event group mechanism, we can register callbacks under event group. For example, register two event callbacks and will be signal in ReadyToBoot.
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
TestCallback1,
NULL,
&gEfiEventReadyToBootGuid,
&ReadyToBootEvent
);
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
TestCallback2,
NULL,
&gEfiEventReadyToBootGuid,
&ReadyToBootEvent
);
I'm curious the order of callback. In this case, the order is LIFO and TestCallback2 will be executed than TestCallback1.
As the UEFI spec page 152, only said "If the supplied Event is a part of an event group, then all of the events in the event group are also signaled and their notification functions are scheduled." It doesn't define order clearly.

However, edk2 has different implementation in EVT_RUNTIME / EVT_NOTIFY_SIGNAL attribute of group event. In Event.c, it inserts new event to Head in EVT_NOTIFY_SIGNAL queue (LIFO) and inserts to Tail in EVT_RUNTIME queue (FIFO).
I know the programmer shouldn't assume any order but want to know why is different implementation in group event. Have any history reason or limitation?

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;
//
// Work around the bug in the Platform Init specification (v1.7), reported
// as Mantis#2017: "EFI_RUNTIME_EVENT_ENTRY.Event" should have type
// EFI_EVENT, not (EFI_EVENT*). The PI spec documents the field correctly
// as "The EFI_EVENT returned by CreateEvent()", but the type of the field
// doesn't match the natural language description. Therefore we need an
// explicit cast here.
//
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);
}

Thank you,
Walon

It's unspecified. Implementations may differ, and an implementation isn't even required to be self-consistent wrt. the order.

Ordering is only specified in terms of TPLs.

Thanks
Laszlo




The information contained in this message is confidential and is intended for the addressee(s) only. If you have received this message in error, please notify the sender immediately and delete the message. Unless you are an addressee (or authorized to receive for an addressee), you may not use, copy or disclose to anyone this message or any information contained in this message. The unauthorized use, disclosure, copying or alteration of this message is strictly prohibited.


Laszlo Ersek
 

On 01/17/20 14:24, Li, Walon wrote:
Laszlo,

Yes, we can specific TPL to adjust callback order. But sometimes, an
event has many callbacks like as ReadyToBoot and TPL level may not
satisfy purpose. In UEFI spec CreateEvent chapter, also mentioned
"The functions in these queues are invoked in FIFO order". So, if it
define clearly in UEFI spec, LIFO or FIFO, we may use driver
dependency to decide which driver's event registration priority and
specific callback order indirectly.
The FIFO order refers to something else. Here's a larger citation:

When the event is signaled, firmware changes its state to “signaled”
and, if EVT_NOTIFY_SIGNAL is specified, places a call to its
notification function in a FIFO queue. There is a queue for each of
the “basic” task priority levels defined in Section 7.1
(TPL_CALLBACK, and TPL_NOTIFY). The functions in these queues are
invoked in FIFO order, starting with the highest priority level
queue and proceeding to the lowest priority queue that is unmasked
by the current TPL.

It means that, within a given TPL, the notification function invocation
order will reflect the enqueueing (= signaling) order.

But the spec does not specify the *signaling* order for such events that
belong to the same event group, when one of those events is signaled.
The spec says,

Event groups are collections of events identified by a shared
EFI_GUID where, when one member event is signaled, all other events
are signaled and their individual notification actions are taken (as
described in CreateEvent). All events are guaranteed to be signaled
before the first notification action is taken. All notification
functions will be executed in the order specified by their
NotifyTpl.

So if you have two events, A and B, and they belong to the same event
group G, and NotifyTpl is the same for both, then if you signal either A
or B, then the notification functions may be queued, *and invoked*, in
either (A, B), or (B, A), order. The invocation order will reflect the
queueing order, yes, but the latter is unspecified, when you go through
an event group.

Thanks
Laszlo


Li, Walon
 

Thanks for your explanation, it's very clear.
Is it possible to update spec that makes unspecified behavior to specified? I know the implementation is in accordance with spec but add some comments can make programmer use this mechanism flexible.

Thanks!
Walon

-----Original Message-----
From: Laszlo Ersek [mailto:lersek@redhat.com]
Sent: Saturday, January 18, 2020 2:19 AM
To: Li, Walon <walon.li@hpe.com>; discuss@edk2.groups.io
Cc: Wei, Kent (HPS SW) <kent.wei@hpe.com>; Wang, Sunny (HPS SW) <sunnywang@hpe.com>; Chang, Abner (HPS SW/FW Technologist) <abner.chang@hpe.com>; Spottswood, Jason <jason.spottswood@hpe.com>; Shifflett, Joseph <joseph.shifflett@hpe.com>; Haskell, Darrell <darrell.haskell@hpe.com>; Wiginton, Scott <scott.wiginton@hpe.com>
Subject: Re: [edk2-discuss] EFI Group Event Callback Order

On 01/17/20 14:24, Li, Walon wrote:
Laszlo,

Yes, we can specific TPL to adjust callback order. But sometimes, an
event has many callbacks like as ReadyToBoot and TPL level may not
satisfy purpose. In UEFI spec CreateEvent chapter, also mentioned "The
functions in these queues are invoked in FIFO order". So, if it define
clearly in UEFI spec, LIFO or FIFO, we may use driver dependency to
decide which driver's event registration priority and specific
callback order indirectly.
The FIFO order refers to something else. Here's a larger citation:

When the event is signaled, firmware changes its state to "signaled"
and, if EVT_NOTIFY_SIGNAL is specified, places a call to its
notification function in a FIFO queue. There is a queue for each of
the "basic" task priority levels defined in Section 7.1
(TPL_CALLBACK, and TPL_NOTIFY). The functions in these queues are
invoked in FIFO order, starting with the highest priority level
queue and proceeding to the lowest priority queue that is unmasked
by the current TPL.

It means that, within a given TPL, the notification function invocation order will reflect the enqueueing (= signaling) order.

But the spec does not specify the *signaling* order for such events that belong to the same event group, when one of those events is signaled.
The spec says,

Event groups are collections of events identified by a shared
EFI_GUID where, when one member event is signaled, all other events
are signaled and their individual notification actions are taken (as
described in CreateEvent). All events are guaranteed to be signaled
before the first notification action is taken. All notification
functions will be executed in the order specified by their
NotifyTpl.

So if you have two events, A and B, and they belong to the same event group G, and NotifyTpl is the same for both, then if you signal either A or B, then the notification functions may be queued, *and invoked*, in either (A, B), or (B, A), order. The invocation order will reflect the queueing order, yes, but the latter is unspecified, when you go through an event group.

Thanks
Laszlo