linux/arch/um/os-Linux/time.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2015 Anton Ivanov (aivanov@{brocade.com,kot-begemot.co.uk})
   3 * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
   4 * Copyright (C) 2012-2014 Cisco Systems
   5 * Copyright (C) 2000 - 2007 Jeff Dike (jdike{addtoit,linux.intel}.com)
   6 * Licensed under the GPL
   7 */
   8
   9#include <stddef.h>
  10#include <errno.h>
  11#include <signal.h>
  12#include <time.h>
  13#include <sys/time.h>
  14#include <kern_util.h>
  15#include <os.h>
  16#include <string.h>
  17#include <timer-internal.h>
  18
  19static timer_t event_high_res_timer = 0;
  20
  21static inline long long timeval_to_ns(const struct timeval *tv)
  22{
  23        return ((long long) tv->tv_sec * UM_NSEC_PER_SEC) +
  24                tv->tv_usec * UM_NSEC_PER_USEC;
  25}
  26
  27static inline long long timespec_to_ns(const struct timespec *ts)
  28{
  29        return ((long long) ts->tv_sec * UM_NSEC_PER_SEC) +
  30                ts->tv_nsec;
  31}
  32
  33long long os_persistent_clock_emulation (void) {
  34        struct timespec realtime_tp;
  35
  36        clock_gettime(CLOCK_REALTIME, &realtime_tp);
  37        return timespec_to_ns(&realtime_tp);
  38}
  39
  40/**
  41 * os_timer_create() - create an new posix (interval) timer
  42 */
  43int os_timer_create(void* timer) {
  44
  45        timer_t* t = timer;
  46
  47        if(t == NULL) {
  48                t = &event_high_res_timer;
  49        }
  50
  51        if (timer_create(
  52                CLOCK_MONOTONIC,
  53                NULL,
  54                t) == -1) {
  55                return -1;
  56        }
  57        return 0;
  58}
  59
  60int os_timer_set_interval(void* timer, void* i)
  61{
  62        struct itimerspec its;
  63        unsigned long long nsec;
  64        timer_t* t = timer;
  65        struct itimerspec* its_in = i;
  66
  67        if(t == NULL) {
  68                t = &event_high_res_timer;
  69        }
  70
  71        nsec = UM_NSEC_PER_SEC / UM_HZ;
  72
  73        if(its_in != NULL) {
  74                its.it_value.tv_sec = its_in->it_value.tv_sec;
  75                its.it_value.tv_nsec = its_in->it_value.tv_nsec;
  76        } else {
  77                its.it_value.tv_sec = 0;
  78                its.it_value.tv_nsec = nsec;
  79        }
  80
  81        its.it_interval.tv_sec = 0;
  82        its.it_interval.tv_nsec = nsec;
  83
  84        if(timer_settime(*t, 0, &its, NULL) == -1) {
  85                return -errno;
  86        }
  87
  88        return 0;
  89}
  90
  91/**
  92 * os_timer_remain() - returns the remaining nano seconds of the given interval
  93 *                     timer
  94 * Because this is the remaining time of an interval timer, which correspondends
  95 * to HZ, this value can never be bigger than one second. Just
  96 * the nanosecond part of the timer is returned.
  97 * The returned time is relative to the start time of the interval timer.
  98 * Return an negative value in an error case.
  99 */
 100long os_timer_remain(void* timer)
 101{
 102        struct itimerspec its;
 103        timer_t* t = timer;
 104
 105        if(t == NULL) {
 106                t = &event_high_res_timer;
 107        }
 108
 109        if(timer_gettime(t, &its) == -1) {
 110                return -errno;
 111        }
 112
 113        return its.it_value.tv_nsec;
 114}
 115
 116int os_timer_one_shot(int ticks)
 117{
 118        struct itimerspec its;
 119        unsigned long long nsec;
 120        unsigned long sec;
 121
 122    nsec = (ticks + 1);
 123    sec = nsec / UM_NSEC_PER_SEC;
 124        nsec = nsec % UM_NSEC_PER_SEC;
 125
 126        its.it_value.tv_sec = nsec / UM_NSEC_PER_SEC;
 127        its.it_value.tv_nsec = nsec;
 128
 129        its.it_interval.tv_sec = 0;
 130        its.it_interval.tv_nsec = 0; // we cheat here
 131
 132        timer_settime(event_high_res_timer, 0, &its, NULL);
 133        return 0;
 134}
 135
 136/**
 137 * os_timer_disable() - disable the posix (interval) timer
 138 * Returns the remaining interval timer time in nanoseconds
 139 */
 140long long os_timer_disable(void)
 141{
 142        struct itimerspec its;
 143
 144        memset(&its, 0, sizeof(struct itimerspec));
 145        timer_settime(event_high_res_timer, 0, &its, &its);
 146
 147        return its.it_value.tv_sec * UM_NSEC_PER_SEC + its.it_value.tv_nsec;
 148}
 149
 150long long os_vnsecs(void)
 151{
 152        struct timespec ts;
 153
 154        clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&ts);
 155        return timespec_to_ns(&ts);
 156}
 157
 158long long os_nsecs(void)
 159{
 160        struct timespec ts;
 161
 162        clock_gettime(CLOCK_MONOTONIC,&ts);
 163        return timespec_to_ns(&ts);
 164}
 165
 166/**
 167 * os_idle_sleep() - sleep for a given time of nsecs
 168 * @nsecs: nanoseconds to sleep
 169 */
 170void os_idle_sleep(unsigned long long nsecs)
 171{
 172        struct timespec ts;
 173
 174        if (nsecs <= 0) {
 175                return;
 176        }
 177
 178        ts = ((struct timespec) {
 179                        .tv_sec  = nsecs / UM_NSEC_PER_SEC,
 180                        .tv_nsec = nsecs % UM_NSEC_PER_SEC
 181        });
 182
 183        /*
 184         * Relay the signal if clock_nanosleep is interrupted.
 185         */
 186        if (clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL)) {
 187                deliver_alarm();
 188        }
 189}
 190