]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/Event/Event.c
MdeModulePkg DxeCore: Avoid the closed event to be signaled wrongly
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Event / Event.c
CommitLineData
23c98c94 1/** @file\r
504214c4
LG
2 UEFI Event support functions implemented in this file.\r
3\r
1a4acc11 4Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>\r
82f3edf2 5(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>\r
cd5ebaa0 6This program and the accompanying materials\r
28a00297 7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
504214c4 14**/\r
28a00297 15\r
16\r
9c4ac31c 17#include "DxeMain.h"\r
ec90508b 18#include "Event.h"\r
28a00297 19\r
1947c70c 20///\r
21/// gEfiCurrentTpl - Current Task priority level\r
22///\r
23EFI_TPL gEfiCurrentTpl = TPL_APPLICATION;\r
24\r
25///\r
d613c2a8 26/// gEventQueueLock - Protects the event queues\r
1947c70c 27///\r
28EFI_LOCK gEventQueueLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL);\r
29\r
30///\r
31/// gEventQueue - A list of event's to notify for each priority level\r
32///\r
33LIST_ENTRY gEventQueue[TPL_HIGH_LEVEL + 1];\r
34\r
35///\r
36/// gEventPending - A bitmask of the EventQueues that are pending\r
37///\r
38UINTN gEventPending = 0;\r
39\r
40///\r
41/// gEventSignalQueue - A list of events to signal based on EventGroup type\r
42///\r
43LIST_ENTRY gEventSignalQueue = INITIALIZE_LIST_HEAD_VARIABLE (gEventSignalQueue);\r
44\r
45///\r
46/// Enumerate the valid types\r
47///\r
28a00297 48UINT32 mEventTable[] = {\r
1947c70c 49 ///\r
50 /// 0x80000200 Timer event with a notification function that is\r
51 /// queue when the event is signaled with SignalEvent()\r
52 ///\r
28a00297 53 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
1947c70c 54 ///\r
55 /// 0x80000000 Timer event without a notification function. It can be\r
56 /// signaled with SignalEvent() and checked with CheckEvent() or WaitForEvent().\r
57 ///\r
28a00297 58 EVT_TIMER,\r
1947c70c 59 ///\r
60 /// 0x00000100 Generic event with a notification function that\r
61 /// can be waited on with CheckEvent() or WaitForEvent()\r
62 ///\r
28a00297 63 EVT_NOTIFY_WAIT,\r
1947c70c 64 ///\r
65 /// 0x00000200 Generic event with a notification function that\r
66 /// is queue when the event is signaled with SignalEvent()\r
67 ///\r
28a00297 68 EVT_NOTIFY_SIGNAL,\r
1947c70c 69 ///\r
70 /// 0x00000201 ExitBootServicesEvent.\r
71 ///\r
28a00297 72 EVT_SIGNAL_EXIT_BOOT_SERVICES,\r
1947c70c 73 ///\r
74 /// 0x60000202 SetVirtualAddressMapEvent.\r
75 ///\r
28a00297 76 EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,\r
77\r
1947c70c 78 ///\r
79 /// 0x00000000 Generic event without a notification function.\r
80 /// It can be signaled with SignalEvent() and checked with CheckEvent()\r
81 /// or WaitForEvent().\r
82 ///\r
28a00297 83 0x00000000,\r
1947c70c 84 ///\r
85 /// 0x80000100 Timer event with a notification function that can be\r
86 /// waited on with CheckEvent() or WaitForEvent()\r
87 ///\r
28a00297 88 EVT_TIMER | EVT_NOTIFY_WAIT,\r
89};\r
90\r
54cd17e9 91///\r
92/// gIdleLoopEvent - Event which is signalled when the core is idle\r
93///\r
94EFI_EVENT gIdleLoopEvent = NULL;\r
95\r
162ed594 96\r
97/**\r
98 Enter critical section by acquiring the lock on gEventQueueLock.\r
99\r
100**/\r
28a00297 101VOID\r
102CoreAcquireEventLock (\r
103 VOID\r
104 )\r
28a00297 105{\r
106 CoreAcquireLock (&gEventQueueLock);\r
107}\r
108\r
162ed594 109\r
110/**\r
111 Exit critical section by releasing the lock on gEventQueueLock.\r
112\r
113**/\r
28a00297 114VOID\r
115CoreReleaseEventLock (\r
116 VOID\r
117 )\r
28a00297 118{\r
119 CoreReleaseLock (&gEventQueueLock);\r
120}\r
121\r
122\r
28a00297 123\r
162ed594 124/**\r
c18f12d3 125 Initializes "event" support.\r
28a00297 126\r
162ed594 127 @retval EFI_SUCCESS Always return success\r
28a00297 128\r
162ed594 129**/\r
130EFI_STATUS\r
131CoreInitializeEventServices (\r
132 VOID\r
133 )\r
28a00297 134{\r
135 UINTN Index;\r
136\r
137 for (Index=0; Index <= TPL_HIGH_LEVEL; Index++) {\r
138 InitializeListHead (&gEventQueue[Index]);\r
139 }\r
140\r
141 CoreInitializeTimer ();\r
142\r
54cd17e9 143 CoreCreateEventEx (\r
144 EVT_NOTIFY_SIGNAL,\r
145 TPL_NOTIFY,\r
146 CoreEmptyCallbackFunction,\r
147 NULL,\r
148 &gIdleLoopEventGuid,\r
149 &gIdleLoopEvent\r
150 );\r
151\r
28a00297 152 return EFI_SUCCESS;\r
153}\r
154\r
155\r
28a00297 156\r
162ed594 157/**\r
28a00297 158 Dispatches all pending events.\r
159\r
022c6d45 160 @param Priority The task priority level of event notifications\r
162ed594 161 to dispatch\r
28a00297 162\r
162ed594 163**/\r
164VOID\r
165CoreDispatchEventNotifies (\r
166 IN EFI_TPL Priority\r
167 )\r
28a00297 168{\r
169 IEVENT *Event;\r
170 LIST_ENTRY *Head;\r
171\r
172 CoreAcquireEventLock ();\r
173 ASSERT (gEventQueueLock.OwnerTpl == Priority);\r
174 Head = &gEventQueue[Priority];\r
175\r
176 //\r
177 // Dispatch all the pending notifications\r
178 //\r
179 while (!IsListEmpty (Head)) {\r
180\r
181 Event = CR (Head->ForwardLink, IEVENT, NotifyLink, EVENT_SIGNATURE);\r
182 RemoveEntryList (&Event->NotifyLink);\r
183\r
184 Event->NotifyLink.ForwardLink = NULL;\r
185\r
186 //\r
187 // Only clear the SIGNAL status if it is a SIGNAL type event.\r
188 // WAIT type events are only cleared in CheckEvent()\r
189 //\r
6e536468 190 if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) {\r
28a00297 191 Event->SignalCount = 0;\r
192 }\r
193\r
194 CoreReleaseEventLock ();\r
195\r
196 //\r
197 // Notify this event\r
198 //\r
199 ASSERT (Event->NotifyFunction != NULL);\r
200 Event->NotifyFunction (Event, Event->NotifyContext);\r
201\r
202 //\r
203 // Check for next pending event\r
204 //\r
205 CoreAcquireEventLock ();\r
206 }\r
207\r
6e1e5405 208 gEventPending &= ~(UINTN)(1 << Priority);\r
28a00297 209 CoreReleaseEventLock ();\r
210}\r
211\r
212\r
162ed594 213\r
214/**\r
215 Queues the event's notification function to fire.\r
216\r
217 @param Event The Event to notify\r
218\r
219**/\r
28a00297 220VOID\r
221CoreNotifyEvent (\r
222 IN IEVENT *Event\r
223 )\r
28a00297 224{\r
225\r
226 //\r
227 // Event database must be locked\r
228 //\r
229 ASSERT_LOCKED (&gEventQueueLock);\r
230\r
231 //\r
232 // If the event is queued somewhere, remove it\r
233 //\r
234\r
235 if (Event->NotifyLink.ForwardLink != NULL) {\r
236 RemoveEntryList (&Event->NotifyLink);\r
237 Event->NotifyLink.ForwardLink = NULL;\r
238 }\r
239\r
240 //\r
241 // Queue the event to the pending notification list\r
242 //\r
243\r
244 InsertTailList (&gEventQueue[Event->NotifyTpl], &Event->NotifyLink);\r
245 gEventPending |= (UINTN)(1 << Event->NotifyTpl);\r
246}\r
247\r
248\r
249\r
162ed594 250\r
251/**\r
252 Signals all events in the EventGroup.\r
253\r
254 @param EventGroup The list to signal\r
255\r
256**/\r
28a00297 257VOID\r
258CoreNotifySignalList (\r
259 IN EFI_GUID *EventGroup\r
260 )\r
28a00297 261{\r
262 LIST_ENTRY *Link;\r
263 LIST_ENTRY *Head;\r
264 IEVENT *Event;\r
265\r
266 CoreAcquireEventLock ();\r
267\r
268 Head = &gEventSignalQueue;\r
269 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
270 Event = CR (Link, IEVENT, SignalLink, EVENT_SIGNATURE);\r
271 if (CompareGuid (&Event->EventGroup, EventGroup)) {\r
272 CoreNotifyEvent (Event);\r
273 }\r
274 }\r
275\r
276 CoreReleaseEventLock ();\r
277}\r
278\r
162ed594 279\r
280/**\r
670d4d88 281 Creates an event.\r
162ed594 282\r
022c6d45 283 @param Type The type of event to create and its mode and\r
284 attributes\r
285 @param NotifyTpl The task priority level of event notifications\r
286 @param NotifyFunction Pointer to the events notification function\r
287 @param NotifyContext Pointer to the notification functions context;\r
288 corresponds to parameter "Context" in the\r
289 notification function\r
290 @param Event Pointer to the newly created event if the call\r
291 succeeds; undefined otherwise\r
292\r
293 @retval EFI_SUCCESS The event structure was created\r
294 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value\r
162ed594 295 @retval EFI_OUT_OF_RESOURCES The event could not be allocated\r
296\r
297**/\r
28a00297 298EFI_STATUS\r
299EFIAPI\r
300CoreCreateEvent (\r
301 IN UINT32 Type,\r
302 IN EFI_TPL NotifyTpl,\r
303 IN EFI_EVENT_NOTIFY NotifyFunction, OPTIONAL\r
304 IN VOID *NotifyContext, OPTIONAL\r
305 OUT EFI_EVENT *Event\r
306 )\r
28a00297 307{\r
bb8ffffd 308 return CoreCreateEventEx (Type, NotifyTpl, NotifyFunction, NotifyContext, NULL, Event);\r
28a00297 309}\r
310\r
311\r
162ed594 312\r
313/**\r
670d4d88 314 Creates an event in a group.\r
162ed594 315\r
022c6d45 316 @param Type The type of event to create and its mode and\r
317 attributes\r
318 @param NotifyTpl The task priority level of event notifications\r
319 @param NotifyFunction Pointer to the events notification function\r
320 @param NotifyContext Pointer to the notification functions context;\r
321 corresponds to parameter "Context" in the\r
322 notification function\r
323 @param EventGroup GUID for EventGroup if NULL act the same as\r
324 gBS->CreateEvent().\r
325 @param Event Pointer to the newly created event if the call\r
326 succeeds; undefined otherwise\r
327\r
328 @retval EFI_SUCCESS The event structure was created\r
329 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value\r
162ed594 330 @retval EFI_OUT_OF_RESOURCES The event could not be allocated\r
331\r
332**/\r
28a00297 333EFI_STATUS\r
334EFIAPI\r
335CoreCreateEventEx (\r
336 IN UINT32 Type,\r
337 IN EFI_TPL NotifyTpl,\r
338 IN EFI_EVENT_NOTIFY NotifyFunction, OPTIONAL\r
339 IN CONST VOID *NotifyContext, OPTIONAL\r
340 IN CONST EFI_GUID *EventGroup, OPTIONAL\r
341 OUT EFI_EVENT *Event\r
342 )\r
670d4d88
SZ
343{\r
344 //\r
345 // If it's a notify type of event, check for invalid NotifyTpl\r
346 //\r
347 if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) {\r
348 if (NotifyTpl != TPL_APPLICATION &&\r
349 NotifyTpl != TPL_CALLBACK &&\r
350 NotifyTpl != TPL_NOTIFY) {\r
351 return EFI_INVALID_PARAMETER;\r
352 }\r
353 }\r
354\r
355 return CoreCreateEventInternal (Type, NotifyTpl, NotifyFunction, NotifyContext, EventGroup, Event);\r
356}\r
357\r
358/**\r
359 Creates a general-purpose event structure\r
360\r
361 @param Type The type of event to create and its mode and\r
362 attributes\r
363 @param NotifyTpl The task priority level of event notifications\r
364 @param NotifyFunction Pointer to the events notification function\r
365 @param NotifyContext Pointer to the notification functions context;\r
366 corresponds to parameter "Context" in the\r
367 notification function\r
368 @param EventGroup GUID for EventGroup if NULL act the same as\r
369 gBS->CreateEvent().\r
370 @param Event Pointer to the newly created event if the call\r
371 succeeds; undefined otherwise\r
372\r
373 @retval EFI_SUCCESS The event structure was created\r
374 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value\r
375 @retval EFI_OUT_OF_RESOURCES The event could not be allocated\r
376\r
377**/\r
378EFI_STATUS\r
379EFIAPI\r
380CoreCreateEventInternal (\r
381 IN UINT32 Type,\r
382 IN EFI_TPL NotifyTpl,\r
383 IN EFI_EVENT_NOTIFY NotifyFunction, OPTIONAL\r
384 IN CONST VOID *NotifyContext, OPTIONAL\r
385 IN CONST EFI_GUID *EventGroup, OPTIONAL\r
386 OUT EFI_EVENT *Event\r
387 )\r
28a00297 388{\r
389 EFI_STATUS Status;\r
390 IEVENT *IEvent;\r
391 INTN Index;\r
392\r
393\r
51b02d81 394 if (Event == NULL) {\r
28a00297 395 return EFI_INVALID_PARAMETER;\r
396 }\r
397\r
398 //\r
399 // Check to make sure no reserved flags are set\r
400 //\r
401 Status = EFI_INVALID_PARAMETER;\r
402 for (Index = 0; Index < (sizeof (mEventTable) / sizeof (UINT32)); Index++) {\r
403 if (Type == mEventTable[Index]) {\r
404 Status = EFI_SUCCESS;\r
405 break;\r
406 }\r
407 }\r
408 if(EFI_ERROR (Status)) {\r
409 return EFI_INVALID_PARAMETER;\r
410 }\r
411\r
bb8ffffd 412 //\r
413 // Convert Event type for pre-defined Event groups\r
414 //\r
415 if (EventGroup != NULL) {\r
416 //\r
417 // For event group, type EVT_SIGNAL_EXIT_BOOT_SERVICES and EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE\r
418 // are not valid\r
419 //\r
420 if ((Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) || (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE)) {\r
421 return EFI_INVALID_PARAMETER;\r
422 }\r
423 if (CompareGuid (EventGroup, &gEfiEventExitBootServicesGuid)) {\r
424 Type = EVT_SIGNAL_EXIT_BOOT_SERVICES;\r
425 } else if (CompareGuid (EventGroup, &gEfiEventVirtualAddressChangeGuid)) {\r
426 Type = EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE;\r
427 }\r
428 } else {\r
429 //\r
430 // Convert EFI 1.10 Events to their UEFI 2.0 CreateEventEx mapping\r
431 //\r
432 if (Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) {\r
433 EventGroup = &gEfiEventExitBootServicesGuid;\r
434 } else if (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) {\r
435 EventGroup = &gEfiEventVirtualAddressChangeGuid;\r
436 }\r
437 }\r
438\r
28a00297 439 //\r
440 // If it's a notify type of event, check its parameters\r
441 //\r
71f68914 442 if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) {\r
28a00297 443 //\r
444 // Check for an invalid NotifyFunction or NotifyTpl\r
445 //\r
446 if ((NotifyFunction == NULL) ||\r
51b02d81 447 (NotifyTpl <= TPL_APPLICATION) ||\r
28a00297 448 (NotifyTpl >= TPL_HIGH_LEVEL)) {\r
449 return EFI_INVALID_PARAMETER;\r
450 }\r
451\r
452 } else {\r
453 //\r
454 // No notification needed, zero ignored values\r
455 //\r
456 NotifyTpl = 0;\r
457 NotifyFunction = NULL;\r
458 NotifyContext = NULL;\r
459 }\r
460\r
461 //\r
b364eeb0 462 // Allocate and initialize a new event structure.\r
28a00297 463 //\r
b364eeb0 464 if ((Type & EVT_RUNTIME) != 0) {\r
465 IEvent = AllocateRuntimeZeroPool (sizeof (IEVENT));\r
466 } else {\r
467 IEvent = AllocateZeroPool (sizeof (IEVENT));\r
468 }\r
469 if (IEvent == NULL) {\r
28a00297 470 return EFI_OUT_OF_RESOURCES;\r
471 }\r
472\r
28a00297 473 IEvent->Signature = EVENT_SIGNATURE;\r
474 IEvent->Type = Type;\r
475\r
476 IEvent->NotifyTpl = NotifyTpl;\r
477 IEvent->NotifyFunction = NotifyFunction;\r
478 IEvent->NotifyContext = (VOID *)NotifyContext;\r
479 if (EventGroup != NULL) {\r
480 CopyGuid (&IEvent->EventGroup, EventGroup);\r
82f3edf2 481 IEvent->ExFlag |= EVT_EXFLAG_EVENT_GROUP;\r
28a00297 482 }\r
483\r
484 *Event = IEvent;\r
485\r
71f68914 486 if ((Type & EVT_RUNTIME) != 0) {\r
28a00297 487 //\r
488 // Keep a list of all RT events so we can tell the RT AP.\r
489 //\r
490 IEvent->RuntimeData.Type = Type;\r
491 IEvent->RuntimeData.NotifyTpl = NotifyTpl;\r
492 IEvent->RuntimeData.NotifyFunction = NotifyFunction;\r
493 IEvent->RuntimeData.NotifyContext = (VOID *) NotifyContext;\r
494 IEvent->RuntimeData.Event = (EFI_EVENT *) IEvent;\r
495 InsertTailList (&gRuntime->EventHead, &IEvent->RuntimeData.Link);\r
496 }\r
497\r
498 CoreAcquireEventLock ();\r
499\r
500 if ((Type & EVT_NOTIFY_SIGNAL) != 0x00000000) {\r
501 //\r
502 // The Event's NotifyFunction must be queued whenever the event is signaled\r
503 //\r
504 InsertHeadList (&gEventSignalQueue, &IEvent->SignalLink);\r
505 }\r
506\r
507 CoreReleaseEventLock ();\r
508\r
509 //\r
510 // Done\r
511 //\r
512 return EFI_SUCCESS;\r
513}\r
514\r
515\r
516\r
28a00297 517\r
162ed594 518/**\r
e94a9ff7 519 Signals the event. Queues the event to be notified if needed.\r
28a00297 520\r
e94a9ff7 521 @param UserEvent The event to signal .\r
28a00297 522\r
022c6d45 523 @retval EFI_INVALID_PARAMETER Parameters are not valid.\r
162ed594 524 @retval EFI_SUCCESS The event was signaled.\r
28a00297 525\r
162ed594 526**/\r
527EFI_STATUS\r
528EFIAPI\r
529CoreSignalEvent (\r
530 IN EFI_EVENT UserEvent\r
531 )\r
28a00297 532{\r
533 IEVENT *Event;\r
534\r
535 Event = UserEvent;\r
536\r
537 if (Event == NULL) {\r
538 return EFI_INVALID_PARAMETER;\r
539 }\r
540\r
541 if (Event->Signature != EVENT_SIGNATURE) {\r
542 return EFI_INVALID_PARAMETER;\r
543 }\r
544\r
545 CoreAcquireEventLock ();\r
546\r
547 //\r
548 // If the event is not already signalled, do so\r
549 //\r
550\r
551 if (Event->SignalCount == 0x00000000) {\r
552 Event->SignalCount++;\r
553\r
554 //\r
555 // If signalling type is a notify function, queue it\r
556 //\r
6e536468 557 if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) {\r
82f3edf2 558 if ((Event->ExFlag & EVT_EXFLAG_EVENT_GROUP) != 0) {\r
28a00297 559 //\r
560 // The CreateEventEx() style requires all members of the Event Group\r
561 // to be signaled.\r
562 //\r
563 CoreReleaseEventLock ();\r
564 CoreNotifySignalList (&Event->EventGroup);\r
565 CoreAcquireEventLock ();\r
566 } else {\r
567 CoreNotifyEvent (Event);\r
568 }\r
569 }\r
570 }\r
571\r
572 CoreReleaseEventLock ();\r
573 return EFI_SUCCESS;\r
574}\r
575\r
576\r
162ed594 577\r
578/**\r
579 Check the status of an event.\r
580\r
022c6d45 581 @param UserEvent The event to check\r
162ed594 582\r
022c6d45 583 @retval EFI_SUCCESS The event is in the signaled state\r
584 @retval EFI_NOT_READY The event is not in the signaled state\r
162ed594 585 @retval EFI_INVALID_PARAMETER Event is of type EVT_NOTIFY_SIGNAL\r
586\r
587**/\r
28a00297 588EFI_STATUS\r
589EFIAPI\r
590CoreCheckEvent (\r
591 IN EFI_EVENT UserEvent\r
592 )\r
28a00297 593{\r
594 IEVENT *Event;\r
595 EFI_STATUS Status;\r
596\r
597 Event = UserEvent;\r
598\r
599 if (Event == NULL) {\r
600 return EFI_INVALID_PARAMETER;\r
601 }\r
602\r
603 if (Event->Signature != EVENT_SIGNATURE) {\r
604 return EFI_INVALID_PARAMETER;\r
605 }\r
606\r
e94a9ff7 607 if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) {\r
28a00297 608 return EFI_INVALID_PARAMETER;\r
609 }\r
610\r
611 Status = EFI_NOT_READY;\r
612\r
6e536468 613 if ((Event->SignalCount == 0) && ((Event->Type & EVT_NOTIFY_WAIT) != 0)) {\r
28a00297 614\r
615 //\r
616 // Queue the wait notify function\r
617 //\r
28a00297 618 CoreAcquireEventLock ();\r
6e536468 619 if (Event->SignalCount == 0) {\r
28a00297 620 CoreNotifyEvent (Event);\r
621 }\r
622 CoreReleaseEventLock ();\r
623 }\r
624\r
625 //\r
626 // If the even looks signalled, get the lock and clear it\r
627 //\r
628\r
6e536468 629 if (Event->SignalCount != 0) {\r
28a00297 630 CoreAcquireEventLock ();\r
631\r
6e536468 632 if (Event->SignalCount != 0) {\r
28a00297 633 Event->SignalCount = 0;\r
634 Status = EFI_SUCCESS;\r
635 }\r
636\r
637 CoreReleaseEventLock ();\r
638 }\r
639\r
640 return Status;\r
641}\r
642\r
643\r
644\r
162ed594 645/**\r
646 Stops execution until an event is signaled.\r
647\r
022c6d45 648 @param NumberOfEvents The number of events in the UserEvents array\r
649 @param UserEvents An array of EFI_EVENT\r
650 @param UserIndex Pointer to the index of the event which\r
651 satisfied the wait condition\r
162ed594 652\r
022c6d45 653 @retval EFI_SUCCESS The event indicated by Index was signaled.\r
654 @retval EFI_INVALID_PARAMETER The event indicated by Index has a notification\r
655 function or Event was not a valid type\r
162ed594 656 @retval EFI_UNSUPPORTED The current TPL is not TPL_APPLICATION\r
657\r
658**/\r
28a00297 659EFI_STATUS\r
660EFIAPI\r
661CoreWaitForEvent (\r
662 IN UINTN NumberOfEvents,\r
663 IN EFI_EVENT *UserEvents,\r
664 OUT UINTN *UserIndex\r
665 )\r
28a00297 666{\r
667 EFI_STATUS Status;\r
668 UINTN Index;\r
669\r
670 //\r
671 // Can only WaitForEvent at TPL_APPLICATION\r
672 //\r
673 if (gEfiCurrentTpl != TPL_APPLICATION) {\r
674 return EFI_UNSUPPORTED;\r
675 }\r
676\r
720f84a9
OM
677 if (NumberOfEvents == 0) {\r
678 return EFI_INVALID_PARAMETER;\r
679 }\r
680\r
681 if (UserEvents == NULL) {\r
682 return EFI_INVALID_PARAMETER;\r
683 }\r
684\r
28a00297 685 for(;;) {\r
686\r
687 for(Index = 0; Index < NumberOfEvents; Index++) {\r
688\r
689 Status = CoreCheckEvent (UserEvents[Index]);\r
690\r
691 //\r
692 // provide index of event that caused problem\r
693 //\r
694 if (Status != EFI_NOT_READY) {\r
720f84a9
OM
695 if (UserIndex != NULL) {\r
696 *UserIndex = Index;\r
697 }\r
28a00297 698 return Status;\r
699 }\r
700 }\r
701\r
702 //\r
54cd17e9 703 // Signal the Idle event\r
28a00297 704 //\r
54cd17e9 705 CoreSignalEvent (gIdleLoopEvent);\r
28a00297 706 }\r
707}\r
708\r
709\r
162ed594 710/**\r
28a00297 711 Closes an event and frees the event structure.\r
712\r
022c6d45 713 @param UserEvent Event to close\r
28a00297 714\r
022c6d45 715 @retval EFI_INVALID_PARAMETER Parameters are not valid.\r
162ed594 716 @retval EFI_SUCCESS The event has been closed\r
28a00297 717\r
162ed594 718**/\r
719EFI_STATUS\r
720EFIAPI\r
721CoreCloseEvent (\r
722 IN EFI_EVENT UserEvent\r
723 )\r
28a00297 724{\r
725 EFI_STATUS Status;\r
726 IEVENT *Event;\r
727\r
728 Event = UserEvent;\r
729\r
730 if (Event == NULL) {\r
731 return EFI_INVALID_PARAMETER;\r
732 }\r
733\r
734 if (Event->Signature != EVENT_SIGNATURE) {\r
735 return EFI_INVALID_PARAMETER;\r
736 }\r
737\r
738 //\r
739 // If it's a timer event, make sure it's not pending\r
740 //\r
e94a9ff7 741 if ((Event->Type & EVT_TIMER) != 0) {\r
28a00297 742 CoreSetTimer (Event, TimerCancel, 0);\r
743 }\r
744\r
745 CoreAcquireEventLock ();\r
746\r
747 //\r
748 // If the event is queued somewhere, remove it\r
749 //\r
750\r
751 if (Event->RuntimeData.Link.ForwardLink != NULL) {\r
752 RemoveEntryList (&Event->RuntimeData.Link);\r
753 }\r
754\r
755 if (Event->NotifyLink.ForwardLink != NULL) {\r
756 RemoveEntryList (&Event->NotifyLink);\r
757 }\r
758\r
759 if (Event->SignalLink.ForwardLink != NULL) {\r
760 RemoveEntryList (&Event->SignalLink);\r
761 }\r
762\r
763 CoreReleaseEventLock ();\r
764\r
765 //\r
766 // If the event is registered on a protocol notify, then remove it from the protocol database\r
767 //\r
82f3edf2
SEHM
768 if ((Event->ExFlag & EVT_EXFLAG_EVENT_PROTOCOL_NOTIFICATION) != 0) {\r
769 CoreUnregisterProtocolNotify (Event);\r
770 }\r
28a00297 771\r
1a4acc11
SZ
772 //\r
773 // To avoid the Event to be signalled wrongly after closed,\r
774 // clear the Signature of Event before free pool.\r
775 //\r
776 Event->Signature = 0;\r
28a00297 777 Status = CoreFreePool (Event);\r
778 ASSERT_EFI_ERROR (Status);\r
779\r
780 return Status;\r
781}\r
54cd17e9 782\r