| /** @file | |
| setitimer and getitimer functions. | |
| Copyright (c) 2011, Intel Corporation. All rights reserved.<BR> | |
| This program and the accompanying materials are licensed and made available under | |
| the terms and conditions of the BSD License that accompanies this distribution. | |
| The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php. | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include <LibConfig.h> | |
| #include <sys/time.h> | |
| #include <time.h> | |
| #include <errno.h> | |
| #include <sys/signal.h> | |
| #include <signal.h> | |
| #include <unistd.h> | |
| #include <Library/UefiBootServicesTableLib.h> | |
| #include <Library/BaseMemoryLib.h> | |
| #include <Library/UefiLib.h> | |
| STATIC EFI_EVENT RealTimer = NULL; | |
| STATIC EFI_EVENT VirtualTimer = NULL; | |
| STATIC EFI_EVENT ProfTimer = NULL; | |
| STATIC struct itimerval RealTimerInfo = {{0,0},{0,0}}; | |
| STATIC struct itimerval VirtualTimerInfo = {{0,0},{0,0}}; | |
| STATIC struct itimerval ProfTimerInfo = {{0,0},{0,0}}; | |
| /** | |
| Function to queue the next iteration of the timer. | |
| This will copy the interval part of the struct into the value and (if | |
| non-zero), then queue the next timer event. | |
| @param[in] TimerInfo The timer info structure. | |
| @param[in] Event The EFI timer event. | |
| **/ | |
| VOID | |
| EFIAPI | |
| SetNext ( | |
| IN struct itimerval *TimerInfo, | |
| IN EFI_EVENT Event | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| CopyMem(&(TimerInfo->it_value), &(TimerInfo->it_interval), sizeof(struct timeval)); | |
| // | |
| // If now zero then close and be done. | |
| // | |
| if (TimerInfo->it_value.tv_sec+TimerInfo->it_value.tv_usec == 0) { | |
| if (Event != NULL) { | |
| gBS->CloseEvent(Event); | |
| Event = NULL; | |
| } | |
| return; | |
| } | |
| // | |
| // Set up for the next loop. | |
| // | |
| Status = gBS->SetTimer ( | |
| Event, | |
| TimerRelative, | |
| TimerInfo->it_value.tv_sec*10000000+TimerInfo->it_value.tv_usec*1000); | |
| if (EFI_ERROR(Status)) { | |
| gBS->CloseEvent(Event); | |
| Event = NULL; | |
| } | |
| } | |
| /** | |
| Notification function for real timer. | |
| @param[in] Event The event. | |
| @param[in] Context Ignored. | |
| **/ | |
| VOID | |
| EFIAPI | |
| iTimerRealNotifyFunction ( | |
| IN EFI_EVENT Event, | |
| IN VOID *Context | |
| ) | |
| { | |
| raise(SIGALRM); | |
| SetNext(&RealTimerInfo, RealTimer); | |
| } | |
| /** | |
| Notification function for virtual timer. | |
| @param[in] Event The event. | |
| @param[in] Context Ignored. | |
| **/ | |
| VOID | |
| EFIAPI | |
| iTimerVirtualNotifyFunction ( | |
| IN EFI_EVENT Event, | |
| IN VOID *Context | |
| ) | |
| { | |
| raise(SIGVTALRM); | |
| SetNext(&VirtualTimerInfo, VirtualTimer); | |
| } | |
| /** | |
| Notification function for prof timer. | |
| @param[in] Event The event. | |
| @param[in] Context Ignored. | |
| **/ | |
| VOID | |
| EFIAPI | |
| iTimerProfNotifyFunction ( | |
| IN EFI_EVENT Event, | |
| IN VOID *Context | |
| ) | |
| { | |
| raise(SIGPROF); | |
| SetNext(&ProfTimerInfo, ProfTimer); | |
| } | |
| /** | |
| The setitimer() function sets the timer specified by which to the value | |
| specified in the structure pointed to by value, and if ovalue is not a null | |
| pointer, stores the previous value of the timer in the structure pointed to | |
| by ovalue. | |
| A timer value is defined by the itimerval structure. If it_value is non-zero, | |
| it indicates the time to the next timer expiration. If it_interval is | |
| non-zero, it specifies a value to be used in reloading it_value when the | |
| timer expires. Setting it_value to 0 disables a timer, regardless of the | |
| value of it_interval. Setting it_interval to 0 disables a timer after its | |
| next expiration (assuming it_value is non-zero). | |
| ITIMER_REAL | |
| Decrements in real time. A SIGALRM signal is delivered when this timer | |
| expires. | |
| ITIMER_VIRTUAL | |
| Decrements in process virtual time. It runs only when the process is | |
| executing. A SIGVTALRM signal is delivered when it expires. | |
| ITIMER_PROF | |
| Decrements both in process virtual time and when the system is running on | |
| behalf of the process. It is designed to be used by interpreters in | |
| statistically profiling the execution of interpreted programs. Each time | |
| the ITIMER_PROF timer expires, the SIGPROF signal is delivered. | |
| @param[in] which Which timer to set. Possible values are described above. | |
| @param[in] value The new value for this timer. | |
| @param[out] ovalue The old value for this timer. | |
| @retval 0 The operation was successful. | |
| @retval -1 The operation failed. see errno for more details. | |
| **/ | |
| int setitimer( | |
| int which, | |
| const struct itimerval *value, | |
| struct itimerval *ovalue | |
| ) | |
| { | |
| EFI_EVENT *EventPointer; | |
| EFI_EVENT_NOTIFY NotifyFunction; | |
| EFI_STATUS Status; | |
| if (value == NULL) { | |
| errno = EINVAL; | |
| return (-1); | |
| } | |
| if (which == ITIMER_REAL) { | |
| EventPointer = &RealTimer; | |
| NotifyFunction = iTimerRealNotifyFunction; | |
| if (ovalue != NULL) { | |
| CopyMem(ovalue, &RealTimerInfo, sizeof(struct itimerval)); | |
| } | |
| CopyMem(&RealTimerInfo, value, sizeof(struct itimerval)); | |
| } else if (which == ITIMER_VIRTUAL) { | |
| EventPointer = &VirtualTimer; | |
| NotifyFunction = iTimerVirtualNotifyFunction; | |
| if (ovalue != NULL) { | |
| CopyMem(ovalue, &VirtualTimerInfo, sizeof(struct itimerval)); | |
| } | |
| CopyMem(&VirtualTimerInfo, value, sizeof(struct itimerval)); | |
| } else if (which == ITIMER_PROF) { | |
| EventPointer = &ProfTimer; | |
| NotifyFunction = iTimerProfNotifyFunction; | |
| if (ovalue != NULL) { | |
| CopyMem(ovalue, &ProfTimerInfo, sizeof(struct itimerval)); | |
| } | |
| CopyMem(&ProfTimerInfo, value, sizeof(struct itimerval)); | |
| } else { | |
| errno = EINVAL; | |
| return (-1); | |
| } | |
| if (*EventPointer != NULL) { | |
| gBS->CloseEvent(*EventPointer); | |
| *EventPointer = NULL; | |
| } | |
| // | |
| // This was a 'please cancel me' request. | |
| // | |
| if (value->it_value.tv_sec+value->it_value.tv_usec == 0) { | |
| return 0; | |
| } | |
| Status = gBS->CreateEvent ( | |
| EVT_TIMER|EVT_NOTIFY_SIGNAL, | |
| EfiGetCurrentTpl(), | |
| NotifyFunction, | |
| NULL, // no context | |
| EventPointer); | |
| if (EFI_ERROR(Status)) { | |
| errno = EINVAL; | |
| return (-1); | |
| } | |
| Status = gBS->SetTimer ( | |
| *EventPointer, | |
| TimerRelative, | |
| value->it_value.tv_sec*10000000+value->it_value.tv_usec*1000); | |
| if (EFI_ERROR(Status)) { | |
| gBS->CloseEvent(*EventPointer); | |
| *EventPointer = NULL; | |
| errno = EINVAL; | |
| return (-1); | |
| } | |
| return 0; | |
| } | |
| /** | |
| Function to get the current state of a timer. | |
| @param[in] which The identifier of the timer to get. See setitimer for | |
| details. | |
| @param[in] value The pointer to populate. must be pre-allocated to size. | |
| @return 0 The operation was successful. | |
| @return -1 The operation failed. | |
| This means that value or which had an invalid value. | |
| **/ | |
| int getitimer( | |
| int which, | |
| struct itimerval *value | |
| ) | |
| { | |
| if (value == NULL) { | |
| errno = EINVAL; | |
| return (-1); | |
| } | |
| if (which == ITIMER_REAL) { | |
| CopyMem(value, &RealTimerInfo, sizeof(struct itimerval)); | |
| } else if (which == ITIMER_VIRTUAL) { | |
| CopyMem(value, &VirtualTimerInfo, sizeof(struct itimerval)); | |
| } else if (which == ITIMER_PROF) { | |
| CopyMem(value, &ProfTimerInfo, sizeof(struct itimerval)); | |
| } else { | |
| errno = EINVAL; | |
| return (-1); | |
| } | |
| return 0; | |
| } |