Home | History | Annotate | Download | only in Time
      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
     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
     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
    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
    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 
    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 **/
    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