summaryrefslogtreecommitdiff
path: root/StdLib/LibC/Time/itimer.c
diff options
context:
space:
mode:
Diffstat (limited to 'StdLib/LibC/Time/itimer.c')
-rw-r--r--StdLib/LibC/Time/itimer.c277
1 files changed, 277 insertions, 0 deletions
diff --git a/StdLib/LibC/Time/itimer.c b/StdLib/LibC/Time/itimer.c
new file mode 100644
index 0000000000..d6f6ab44c0
--- /dev/null
+++ b/StdLib/LibC/Time/itimer.c
@@ -0,0 +1,277 @@
+/** @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/EfiSysCall.h>
+#include <sys/time.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/signal.h>
+#include <signal.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;
+} \ No newline at end of file