Logo Search packages:      
Sourcecode: linux version File versions  Download package

time.c

/*
 * Copyright (C) 2000 - 2007 Jeff Dike (jdike{addtoit,linux.intel}.com)
 * Licensed under the GPL
 */

#include <stddef.h>
#include <errno.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include "kern_constants.h"
#include "os.h"
#include "user.h"

int set_interval(void)
{
      int usec = UM_USEC_PER_SEC / UM_HZ;
      struct itimerval interval = ((struct itimerval) { { 0, usec },
                                            { 0, usec } });

      if (setitimer(ITIMER_VIRTUAL, &interval, NULL) == -1)
            return -errno;

      return 0;
}

int timer_one_shot(int ticks)
{
      unsigned long usec = ticks * UM_USEC_PER_SEC / UM_HZ;
      unsigned long sec = usec / UM_USEC_PER_SEC;
      struct itimerval interval;

      usec %= UM_USEC_PER_SEC;
      interval = ((struct itimerval) { { 0, 0 }, { sec, usec } });

      if (setitimer(ITIMER_VIRTUAL, &interval, NULL) == -1)
            return -errno;

      return 0;
}

/**
 * timeval_to_ns - Convert timeval to nanoseconds
 * @ts:           pointer to the timeval variable to be converted
 *
 * Returns the scalar nanosecond representation of the timeval
 * parameter.
 *
 * Ripped from linux/time.h because it's a kernel header, and thus
 * unusable from here.
 */
static inline long long timeval_to_ns(const struct timeval *tv)
{
      return ((long long) tv->tv_sec * UM_NSEC_PER_SEC) +
            tv->tv_usec * UM_NSEC_PER_USEC;
}

long long disable_timer(void)
{
      struct itimerval time = ((struct itimerval) { { 0, 0 }, { 0, 0 } });

      if (setitimer(ITIMER_VIRTUAL, &time, &time) < 0)
            printk(UM_KERN_ERR "disable_timer - setitimer failed, "
                   "errno = %d\n", errno);

      return timeval_to_ns(&time.it_value);
}

long long os_nsecs(void)
{
      struct timeval tv;

      gettimeofday(&tv, NULL);
      return timeval_to_ns(&tv);
}

#ifdef UML_CONFIG_NO_HZ
static int after_sleep_interval(struct timespec *ts)
{
      return 0;
}
#else
static inline long long timespec_to_us(const struct timespec *ts)
{
      return ((long long) ts->tv_sec * UM_USEC_PER_SEC) +
            ts->tv_nsec / UM_NSEC_PER_USEC;
}

static int after_sleep_interval(struct timespec *ts)
{
      int usec = UM_USEC_PER_SEC / UM_HZ;
      long long start_usecs = timespec_to_us(ts);
      struct timeval tv;
      struct itimerval interval;

      /*
       * It seems that rounding can increase the value returned from
       * setitimer to larger than the one passed in.  Over time,
       * this will cause the remaining time to be greater than the
       * tick interval.  If this happens, then just reduce the first
       * tick to the interval value.
       */
      if (start_usecs > usec)
            start_usecs = usec;
      tv = ((struct timeval) { .tv_sec  = start_usecs / UM_USEC_PER_SEC,
                         .tv_usec = start_usecs % UM_USEC_PER_SEC });
      interval = ((struct itimerval) { { 0, usec }, tv });

      if (setitimer(ITIMER_VIRTUAL, &interval, NULL) == -1)
            return -errno;

      return 0;
}
#endif

extern void alarm_handler(int sig, struct sigcontext *sc);

void idle_sleep(unsigned long long nsecs)
{
      struct timespec ts;

      /*
       * nsecs can come in as zero, in which case, this starts a
       * busy loop.  To prevent this, reset nsecs to the tick
       * interval if it is zero.
       */
      if (nsecs == 0)
            nsecs = UM_NSEC_PER_SEC / UM_HZ;
      ts = ((struct timespec) { .tv_sec   = nsecs / UM_NSEC_PER_SEC,
                          .tv_nsec  = nsecs % UM_NSEC_PER_SEC });

      if (nanosleep(&ts, &ts) == 0)
            alarm_handler(SIGVTALRM, NULL);
      after_sleep_interval(&ts);
}

Generated by  Doxygen 1.6.0   Back to index