1 /** @file
2 setitimer and getitimer functions.
3
4 Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials are licensed and made available under
6 the terms and conditions of the BSD License that accompanies this distribution.
7 The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php.
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 **/
13 #include <LibConfig.h>
14 #include <sys/time.h>
15 #include <time.h>
16 #include <errno.h>
17 #include <sys/signal.h>
18 #include <signal.h>
19 #include <unistd.h>
20 #include <Library/UefiBootServicesTableLib.h>
21 #include <Library/BaseMemoryLib.h>
22 #include <Library/UefiLib.h>
23
24 STATIC EFI_EVENT RealTimer = NULL;
25 STATIC EFI_EVENT VirtualTimer = NULL;
26 STATIC EFI_EVENT ProfTimer = NULL;
27
28 STATIC struct itimerval RealTimerInfo = {{0,0},{0,0}};
29 STATIC struct itimerval VirtualTimerInfo = {{0,0},{0,0}};
30 STATIC struct itimerval ProfTimerInfo = {{0,0},{0,0}};
31
32 /**
33 Function to queue the next iteration of the timer.
34
35 This will copy the interval part of the struct into the value and (if
36 non-zero), then queue the next timer event.
37
38 @param[in] TimerInfo The timer info structure.
39 @param[in] Event The EFI timer event.
40 **/
41 VOID
42 EFIAPI
SetNext(IN struct itimerval * TimerInfo,IN EFI_EVENT Event)43 SetNext (
44 IN struct itimerval *TimerInfo,
45 IN EFI_EVENT Event
46 )
47 {
48 EFI_STATUS Status;
49
50 CopyMem(&(TimerInfo->it_value), &(TimerInfo->it_interval), sizeof(struct timeval));
51
52 //
53 // If now zero then close and be done.
54 //
55 if (TimerInfo->it_value.tv_sec+TimerInfo->it_value.tv_usec == 0) {
56 if (Event != NULL) {
57 gBS->CloseEvent(Event);
58 Event = NULL;
59 }
60 return;
61 }
62
63 //
64 // Set up for the next loop.
65 //
66 Status = gBS->SetTimer (
67 Event,
68 TimerRelative,
69 TimerInfo->it_value.tv_sec*10000000+TimerInfo->it_value.tv_usec*1000);
70
71 if (EFI_ERROR(Status)) {
72 gBS->CloseEvent(Event);
73 Event = NULL;
74 }
75 }
76
77 /**
78 Notification function for real timer.
79
80 @param[in] Event The event.
81 @param[in] Context Ignored.
82 **/
83 VOID
84 EFIAPI
iTimerRealNotifyFunction(IN EFI_EVENT Event,IN VOID * Context)85 iTimerRealNotifyFunction (
86 IN EFI_EVENT Event,
87 IN VOID *Context
88 )
89 {
90 raise(SIGALRM);
91 SetNext(&RealTimerInfo, RealTimer);
92 }
93
94 /**
95 Notification function for virtual timer.
96
97 @param[in] Event The event.
98 @param[in] Context Ignored.
99 **/
100 VOID
101 EFIAPI
iTimerVirtualNotifyFunction(IN EFI_EVENT Event,IN VOID * Context)102 iTimerVirtualNotifyFunction (
103 IN EFI_EVENT Event,
104 IN VOID *Context
105 )
106 {
107 raise(SIGVTALRM);
108 SetNext(&VirtualTimerInfo, VirtualTimer);
109 }
110
111 /**
112 Notification function for prof timer.
113
114 @param[in] Event The event.
115 @param[in] Context Ignored.
116 **/
117 VOID
118 EFIAPI
iTimerProfNotifyFunction(IN EFI_EVENT Event,IN VOID * Context)119 iTimerProfNotifyFunction (
120 IN EFI_EVENT Event,
121 IN VOID *Context
122 )
123 {
124 raise(SIGPROF);
125 SetNext(&ProfTimerInfo, ProfTimer);
126 }
127
128 /**
129 The setitimer() function sets the timer specified by which to the value
130 specified in the structure pointed to by value, and if ovalue is not a null
131 pointer, stores the previous value of the timer in the structure pointed to
132 by ovalue.
133
134 A timer value is defined by the itimerval structure. If it_value is non-zero,
135 it indicates the time to the next timer expiration. If it_interval is
136 non-zero, it specifies a value to be used in reloading it_value when the
137 timer expires. Setting it_value to 0 disables a timer, regardless of the
138 value of it_interval. Setting it_interval to 0 disables a timer after its
139 next expiration (assuming it_value is non-zero).
140
141 ITIMER_REAL
142 Decrements in real time. A SIGALRM signal is delivered when this timer
143 expires.
144
145 ITIMER_VIRTUAL
146 Decrements in process virtual time. It runs only when the process is
147 executing. A SIGVTALRM signal is delivered when it expires.
148
149 ITIMER_PROF
150 Decrements both in process virtual time and when the system is running on
151 behalf of the process. It is designed to be used by interpreters in
152 statistically profiling the execution of interpreted programs. Each time
153 the ITIMER_PROF timer expires, the SIGPROF signal is delivered.
154
155 @param[in] which Which timer to set. Possible values are described above.
156 @param[in] value The new value for this timer.
157 @param[out] ovalue The old value for this timer.
158
159 @retval 0 The operation was successful.
160 @retval -1 The operation failed. see errno for more details.
161 **/
162
setitimer(int which,const struct itimerval * value,struct itimerval * ovalue)163 int setitimer(
164 int which,
165 const struct itimerval *value,
166 struct itimerval *ovalue
167 )
168 {
169 EFI_EVENT *EventPointer;
170 EFI_EVENT_NOTIFY NotifyFunction;
171 EFI_STATUS Status;
172
173 if (value == NULL) {
174 errno = EINVAL;
175 return (-1);
176 }
177
178 if (which == ITIMER_REAL) {
179 EventPointer = &RealTimer;
180 NotifyFunction = iTimerRealNotifyFunction;
181 if (ovalue != NULL) {
182 CopyMem(ovalue, &RealTimerInfo, sizeof(struct itimerval));
183 }
184 CopyMem(&RealTimerInfo, value, sizeof(struct itimerval));
185 } else if (which == ITIMER_VIRTUAL) {
186 EventPointer = &VirtualTimer;
187 NotifyFunction = iTimerVirtualNotifyFunction;
188 if (ovalue != NULL) {
189 CopyMem(ovalue, &VirtualTimerInfo, sizeof(struct itimerval));
190 }
191 CopyMem(&VirtualTimerInfo, value, sizeof(struct itimerval));
192 } else if (which == ITIMER_PROF) {
193 EventPointer = &ProfTimer;
194 NotifyFunction = iTimerProfNotifyFunction;
195 if (ovalue != NULL) {
196 CopyMem(ovalue, &ProfTimerInfo, sizeof(struct itimerval));
197 }
198 CopyMem(&ProfTimerInfo, value, sizeof(struct itimerval));
199 } else {
200 errno = EINVAL;
201 return (-1);
202 }
203
204 if (*EventPointer != NULL) {
205 gBS->CloseEvent(*EventPointer);
206 *EventPointer = NULL;
207 }
208
209 //
210 // This was a 'please cancel me' request.
211 //
212 if (value->it_value.tv_sec+value->it_value.tv_usec == 0) {
213 return 0;
214 }
215
216 Status = gBS->CreateEvent (
217 EVT_TIMER|EVT_NOTIFY_SIGNAL,
218 EfiGetCurrentTpl(),
219 NotifyFunction,
220 NULL, // no context
221 EventPointer);
222
223 if (EFI_ERROR(Status)) {
224 errno = EINVAL;
225 return (-1);
226 }
227
228 Status = gBS->SetTimer (
229 *EventPointer,
230 TimerRelative,
231 value->it_value.tv_sec*10000000+value->it_value.tv_usec*1000);
232
233 if (EFI_ERROR(Status)) {
234 gBS->CloseEvent(*EventPointer);
235 *EventPointer = NULL;
236 errno = EINVAL;
237 return (-1);
238 }
239
240 return 0;
241 }
242
243 /**
244 Function to get the current state of a timer.
245
246 @param[in] which The identifier of the timer to get. See setitimer for
247 details.
248 @param[in] value The pointer to populate. must be pre-allocated to size.
249
250 @return 0 The operation was successful.
251 @return -1 The operation failed.
252 This means that value or which had an invalid value.
253 **/
getitimer(int which,struct itimerval * value)254 int getitimer(
255 int which,
256 struct itimerval *value
257 )
258 {
259
260 if (value == NULL) {
261 errno = EINVAL;
262 return (-1);
263 }
264
265 if (which == ITIMER_REAL) {
266 CopyMem(value, &RealTimerInfo, sizeof(struct itimerval));
267 } else if (which == ITIMER_VIRTUAL) {
268 CopyMem(value, &VirtualTimerInfo, sizeof(struct itimerval));
269 } else if (which == ITIMER_PROF) {
270 CopyMem(value, &ProfTimerInfo, sizeof(struct itimerval));
271 } else {
272 errno = EINVAL;
273 return (-1);
274 }
275
276 return 0;
277 }
278