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