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