blob: 00712b824793bbe7ae1c9d52c04c97d4682a4a38 [file] [log] [blame]
Vishal Bhoj82c80712015-12-15 21:13:33 +05301/** @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
24STATIC EFI_EVENT RealTimer = NULL;
25STATIC EFI_EVENT VirtualTimer = NULL;
26STATIC EFI_EVENT ProfTimer = NULL;
27
28STATIC struct itimerval RealTimerInfo = {{0,0},{0,0}};
29STATIC struct itimerval VirtualTimerInfo = {{0,0},{0,0}};
30STATIC 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**/
41VOID
42EFIAPI
43SetNext (
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**/
83VOID
84EFIAPI
85iTimerRealNotifyFunction (
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**/
100VOID
101EFIAPI
102iTimerVirtualNotifyFunction (
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**/
117VOID
118EFIAPI
119iTimerProfNotifyFunction (
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
163int 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**/
254int 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}