linux/arch/um/os-Linux/time.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2000 - 2007 Jeff Dike (jdike{addtoit,linux.intel}.com)
   3 * Licensed under the GPL
   4 */
   5
   6#include <stddef.h>
   7#include <errno.h>
   8#include <signal.h>
   9#include <time.h>
  10#include <sys/time.h>
  11#include "kern_constants.h"
  12#include "os.h"
  13#include "user.h"
  14
  15int set_interval(void)
  16{
  17        int usec = UM_USEC_PER_SEC / UM_HZ;
  18        struct itimerval interval = ((struct itimerval) { { 0, usec },
  19                                                          { 0, usec } });
  20
  21        if (setitimer(ITIMER_VIRTUAL, &interval, NULL) == -1)
  22                return -errno;
  23
  24        return 0;
  25}
  26
  27int timer_one_shot(int ticks)
  28{
  29        unsigned long usec = ticks * UM_USEC_PER_SEC / UM_HZ;
  30        unsigned long sec = usec / UM_USEC_PER_SEC;
  31        struct itimerval interval;
  32
  33        usec %= UM_USEC_PER_SEC;
  34        interval = ((struct itimerval) { { 0, 0 }, { sec, usec } });
  35
  36        if (setitimer(ITIMER_VIRTUAL, &interval, NULL) == -1)
  37                return -errno;
  38
  39        return 0;
  40}
  41
  42/**
  43 * timeval_to_ns - Convert timeval to nanoseconds
  44 * @ts:         pointer to the timeval variable to be converted
  45 *
  46 * Returns the scalar nanosecond representation of the timeval
  47 * parameter.
  48 *
  49 * Ripped from linux/time.h because it's a kernel header, and thus
  50 * unusable from here.
  51 */
  52static inline long long timeval_to_ns(const struct timeval *tv)
  53{
  54        return ((long long) tv->tv_sec * UM_NSEC_PER_SEC) +
  55                tv->tv_usec * UM_NSEC_PER_USEC;
  56}
  57
  58long long disable_timer(void)
  59{
  60        struct itimerval time = ((struct itimerval) { { 0, 0 }, { 0, 0 } });
  61
  62        if (setitimer(ITIMER_VIRTUAL, &time, &time) < 0)
  63                printk(UM_KERN_ERR "disable_timer - setitimer failed, "
  64                       "errno = %d\n", errno);
  65
  66        return timeval_to_ns(&time.it_value);
  67}
  68
  69long long os_nsecs(void)
  70{
  71        struct timeval tv;
  72
  73        gettimeofday(&tv, NULL);
  74        return timeval_to_ns(&tv);
  75}
  76
  77#ifdef UML_CONFIG_NO_HZ
  78static int after_sleep_interval(struct timespec *ts)
  79{
  80        return 0;
  81}
  82#else
  83static inline long long timespec_to_us(const struct timespec *ts)
  84{
  85        return ((long long) ts->tv_sec * UM_USEC_PER_SEC) +
  86                ts->tv_nsec / UM_NSEC_PER_USEC;
  87}
  88
  89static int after_sleep_interval(struct timespec *ts)
  90{
  91        int usec = UM_USEC_PER_SEC / UM_HZ;
  92        long long start_usecs = timespec_to_us(ts);
  93        struct timeval tv;
  94        struct itimerval interval;
  95
  96        /*
  97         * It seems that rounding can increase the value returned from
  98         * setitimer to larger than the one passed in.  Over time,
  99         * this will cause the remaining time to be greater than the
 100         * tick interval.  If this happens, then just reduce the first
 101         * tick to the interval value.
 102         */
 103        if (start_usecs > usec)
 104                start_usecs = usec;
 105        tv = ((struct timeval) { .tv_sec  = start_usecs / UM_USEC_PER_SEC,
 106                                 .tv_usec = start_usecs % UM_USEC_PER_SEC });
 107        interval = ((struct itimerval) { { 0, usec }, tv });
 108
 109        if (setitimer(ITIMER_VIRTUAL, &interval, NULL) == -1)
 110                return -errno;
 111
 112        return 0;
 113}
 114#endif
 115
 116extern void alarm_handler(int sig, struct sigcontext *sc);
 117
 118void idle_sleep(unsigned long long nsecs)
 119{
 120        struct timespec ts;
 121
 122        /*
 123         * nsecs can come in as zero, in which case, this starts a
 124         * busy loop.  To prevent this, reset nsecs to the tick
 125         * interval if it is zero.
 126         */
 127        if (nsecs == 0)
 128                nsecs = UM_NSEC_PER_SEC / UM_HZ;
 129        ts = ((struct timespec) { .tv_sec       = nsecs / UM_NSEC_PER_SEC,
 130                                  .tv_nsec      = nsecs % UM_NSEC_PER_SEC });
 131
 132        if (nanosleep(&ts, &ts) == 0)
 133                alarm_handler(SIGVTALRM, NULL);
 134        after_sleep_interval(&ts);
 135}
 136