]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Core/Dxe/Event/Timer.c
Code Scrub for Dxe Core.
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Event / Timer.c
... / ...
CommitLineData
1/** @file\r
2 Core Timer Services\r
3\r
4Copyright (c) 2006 - 2008, Intel Corporation. <BR>\r
5All rights reserved. This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15\r
16#include <DxeMain.h>\r
17\r
18//\r
19// Internal prototypes\r
20//\r
21/**\r
22 Returns the current system time.\r
23\r
24 @return The current system time\r
25\r
26**/\r
27UINT64\r
28CoreCurrentSystemTime (\r
29 VOID\r
30 );\r
31\r
32/**\r
33 Checks the sorted timer list against the current system time.\r
34 Signals any expired event timer.\r
35\r
36 @param CheckEvent Not used\r
37 @param Context Not used\r
38\r
39**/\r
40VOID\r
41EFIAPI\r
42CoreCheckTimers (\r
43 IN EFI_EVENT CheckEvent,\r
44 IN VOID *Context\r
45 );\r
46\r
47/**\r
48 Inserts the timer event.\r
49\r
50 @param Event Points to the internal structure of timer event\r
51 to be installed\r
52\r
53**/\r
54VOID\r
55CoreInsertEventTimer (\r
56 IN IEVENT *Event\r
57 );\r
58\r
59//\r
60// Internal data\r
61//\r
62\r
63LIST_ENTRY mEfiTimerList = INITIALIZE_LIST_HEAD_VARIABLE (mEfiTimerList);\r
64EFI_LOCK mEfiTimerLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL - 1);\r
65EFI_EVENT mEfiCheckTimerEvent = NULL;\r
66\r
67EFI_LOCK mEfiSystemTimeLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL);\r
68UINT64 mEfiSystemTime = 0;\r
69\r
70//\r
71// Timer functions\r
72//\r
73/**\r
74 Initializes timer support.\r
75\r
76**/\r
77VOID\r
78CoreInitializeTimer (\r
79 VOID\r
80 )\r
81{\r
82 EFI_STATUS Status;\r
83\r
84 Status = CoreCreateEvent (\r
85 EVT_NOTIFY_SIGNAL,\r
86 TPL_HIGH_LEVEL - 1,\r
87 CoreCheckTimers,\r
88 NULL,\r
89 &mEfiCheckTimerEvent\r
90 );\r
91 ASSERT_EFI_ERROR (Status);\r
92}\r
93\r
94\r
95/**\r
96 Returns the current system time.\r
97\r
98 @return The current system time\r
99\r
100**/\r
101UINT64\r
102CoreCurrentSystemTime (\r
103 VOID\r
104 )\r
105{\r
106 UINT64 SystemTime;\r
107\r
108 CoreAcquireLock (&mEfiSystemTimeLock);\r
109 SystemTime = mEfiSystemTime;\r
110 CoreReleaseLock (&mEfiSystemTimeLock);\r
111\r
112 return SystemTime;\r
113}\r
114\r
115\r
116/**\r
117 Called by the platform code to process a tick.\r
118\r
119 @param Duration The number of 100ns elasped since the last call\r
120 to TimerTick\r
121\r
122**/\r
123VOID\r
124EFIAPI\r
125CoreTimerTick (\r
126 IN UINT64 Duration\r
127 )\r
128{\r
129 IEVENT *Event;\r
130\r
131 //\r
132 // Check runtiem flag in case there are ticks while exiting boot services\r
133 //\r
134 CoreAcquireLock (&mEfiSystemTimeLock);\r
135\r
136 //\r
137 // Update the system time\r
138 //\r
139 mEfiSystemTime += Duration;\r
140\r
141 //\r
142 // If the head of the list is expired, fire the timer event\r
143 // to process it\r
144 //\r
145 if (!IsListEmpty (&mEfiTimerList)) {\r
146 Event = CR (mEfiTimerList.ForwardLink, IEVENT, u.Timer.Link, EVENT_SIGNATURE);\r
147\r
148 if (Event->u.Timer.TriggerTime <= mEfiSystemTime) {\r
149 CoreSignalEvent (mEfiCheckTimerEvent);\r
150 }\r
151 }\r
152\r
153 CoreReleaseLock (&mEfiSystemTimeLock);\r
154}\r
155\r
156\r
157/**\r
158 Checks the sorted timer list against the current system time.\r
159 Signals any expired event timer.\r
160\r
161 @param CheckEvent Not used\r
162 @param Context Not used\r
163\r
164**/\r
165VOID\r
166EFIAPI\r
167CoreCheckTimers (\r
168 IN EFI_EVENT CheckEvent,\r
169 IN VOID *Context\r
170 )\r
171{\r
172 UINT64 SystemTime;\r
173 IEVENT *Event;\r
174\r
175 //\r
176 // Check the timer database for expired timers\r
177 //\r
178 CoreAcquireLock (&mEfiTimerLock);\r
179 SystemTime = CoreCurrentSystemTime ();\r
180\r
181 while (!IsListEmpty (&mEfiTimerList)) {\r
182 Event = CR (mEfiTimerList.ForwardLink, IEVENT, u.Timer.Link, EVENT_SIGNATURE);\r
183\r
184 //\r
185 // If this timer is not expired, then we're done\r
186 //\r
187 if (Event->u.Timer.TriggerTime > SystemTime) {\r
188 break;\r
189 }\r
190\r
191 //\r
192 // Remove this timer from the timer queue\r
193 //\r
194\r
195 RemoveEntryList (&Event->u.Timer.Link);\r
196 Event->u.Timer.Link.ForwardLink = NULL;\r
197\r
198 //\r
199 // Signal it\r
200 //\r
201 CoreSignalEvent (Event);\r
202\r
203 //\r
204 // If this is a periodic timer, set it\r
205 //\r
206 if (Event->u.Timer.Period) {\r
207 //\r
208 // Compute the timers new trigger time\r
209 //\r
210 Event->u.Timer.TriggerTime = Event->u.Timer.TriggerTime + Event->u.Timer.Period;\r
211\r
212 //\r
213 // If that's before now, then reset the timer to start from now\r
214 //\r
215 if (Event->u.Timer.TriggerTime <= SystemTime) {\r
216 Event->u.Timer.TriggerTime = SystemTime;\r
217 CoreSignalEvent (mEfiCheckTimerEvent);\r
218 }\r
219\r
220 //\r
221 // Add the timer\r
222 //\r
223 CoreInsertEventTimer (Event);\r
224 }\r
225 }\r
226\r
227 CoreReleaseLock (&mEfiTimerLock);\r
228}\r
229\r
230\r
231/**\r
232 Inserts the timer event.\r
233\r
234 @param Event Points to the internal structure of timer event\r
235 to be installed\r
236\r
237**/\r
238VOID\r
239CoreInsertEventTimer (\r
240 IN IEVENT *Event\r
241 )\r
242{\r
243 UINT64 TriggerTime;\r
244 LIST_ENTRY *Link;\r
245 IEVENT *Event2;\r
246\r
247 ASSERT_LOCKED (&mEfiTimerLock);\r
248\r
249 //\r
250 // Get the timer's trigger time\r
251 //\r
252 TriggerTime = Event->u.Timer.TriggerTime;\r
253\r
254 //\r
255 // Insert the timer into the timer database in assending sorted order\r
256 //\r
257 for (Link = mEfiTimerList.ForwardLink; Link != &mEfiTimerList; Link = Link->ForwardLink) {\r
258 Event2 = CR (Link, IEVENT, u.Timer.Link, EVENT_SIGNATURE);\r
259\r
260 if (Event2->u.Timer.TriggerTime > TriggerTime) {\r
261 break;\r
262 }\r
263 }\r
264\r
265 InsertTailList (Link, &Event->u.Timer.Link);\r
266}\r
267\r
268\r
269\r
270/**\r
271 Sets the type of timer and the trigger time for a timer event.\r
272\r
273 @param UserEvent The timer event that is to be signaled at the\r
274 specified time\r
275 @param Type The type of time that is specified in\r
276 TriggerTime\r
277 @param TriggerTime The number of 100ns units until the timer\r
278 expires\r
279\r
280 @retval EFI_SUCCESS The event has been set to be signaled at the\r
281 requested time\r
282 @retval EFI_INVALID_PARAMETER Event or Type is not valid\r
283\r
284**/\r
285EFI_STATUS\r
286EFIAPI\r
287CoreSetTimer (\r
288 IN EFI_EVENT UserEvent,\r
289 IN EFI_TIMER_DELAY Type,\r
290 IN UINT64 TriggerTime\r
291 )\r
292{\r
293 IEVENT *Event;\r
294\r
295 Event = UserEvent;\r
296\r
297 if (Event == NULL) {\r
298 return EFI_INVALID_PARAMETER;\r
299 }\r
300\r
301 if (Event->Signature != EVENT_SIGNATURE) {\r
302 return EFI_INVALID_PARAMETER;\r
303 }\r
304\r
305 if (Type < 0 || Type > TimerRelative || !(Event->Type & EVT_TIMER)) {\r
306 return EFI_INVALID_PARAMETER;\r
307 }\r
308\r
309 CoreAcquireLock (&mEfiTimerLock);\r
310\r
311 //\r
312 // If the timer is queued to the timer database, remove it\r
313 //\r
314 if (Event->u.Timer.Link.ForwardLink != NULL) {\r
315 RemoveEntryList (&Event->u.Timer.Link);\r
316 Event->u.Timer.Link.ForwardLink = NULL;\r
317 }\r
318\r
319 Event->u.Timer.TriggerTime = 0;\r
320 Event->u.Timer.Period = 0;\r
321\r
322 if (Type != TimerCancel) {\r
323\r
324 if (Type == TimerPeriodic) {\r
325 Event->u.Timer.Period = TriggerTime;\r
326 }\r
327\r
328 Event->u.Timer.TriggerTime = CoreCurrentSystemTime () + TriggerTime;\r
329 CoreInsertEventTimer (Event);\r
330\r
331 if (TriggerTime == 0) {\r
332 CoreSignalEvent (mEfiCheckTimerEvent);\r
333 }\r
334 }\r
335\r
336 CoreReleaseLock (&mEfiTimerLock);\r
337\r
338 return EFI_SUCCESS;\r
339}\r