linux/arch/um/os-Linux/time.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2015 Anton Ivanov (aivanov@{brocade.com,kot-begemot.co.uk})
   4 * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
   5 * Copyright (C) 2012-2014 Cisco Systems
   6 * Copyright (C) 2000 - 2007 Jeff Dike (jdike{addtoit,linux.intel}.com)
   7 */
   8
   9#include <stddef.h>
  10#include <unistd.h>
  11#include <errno.h>
  12#include <signal.h>
  13#include <time.h>
  14#include <sys/time.h>
  15#include <kern_util.h>
  16#include <os.h>
  17#include <string.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) + ts->tv_nsec;
  30}
  31
  32long long os_persistent_clock_emulation(void)
  33{
  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)
  44{
  45        timer_t *t = &event_high_res_timer;
  46
  47        if (timer_create(CLOCK_MONOTONIC, NULL, t) == -1)
  48                return -1;
  49
  50        return 0;
  51}
  52
  53int os_timer_set_interval(unsigned long long nsecs)
  54{
  55        struct itimerspec its;
  56
  57        its.it_value.tv_sec = nsecs / UM_NSEC_PER_SEC;
  58        its.it_value.tv_nsec = nsecs % UM_NSEC_PER_SEC;
  59
  60        its.it_interval.tv_sec = nsecs / UM_NSEC_PER_SEC;
  61        its.it_interval.tv_nsec = nsecs % UM_NSEC_PER_SEC;
  62
  63        if (timer_settime(event_high_res_timer, 0, &its, NULL) == -1)
  64                return -errno;
  65
  66        return 0;
  67}
  68
  69int os_timer_one_shot(unsigned long long nsecs)
  70{
  71        struct itimerspec its = {
  72                .it_value.tv_sec = nsecs / UM_NSEC_PER_SEC,
  73                .it_value.tv_nsec = nsecs % UM_NSEC_PER_SEC,
  74
  75                .it_interval.tv_sec = 0,
  76                .it_interval.tv_nsec = 0, // we cheat here
  77        };
  78
  79        timer_settime(event_high_res_timer, 0, &its, NULL);
  80        return 0;
  81}
  82
  83/**
  84 * os_timer_disable() - disable the posix (interval) timer
  85 */
  86void os_timer_disable(void)
  87{
  88        struct itimerspec its;
  89
  90        memset(&its, 0, sizeof(struct itimerspec));
  91        timer_settime(event_high_res_timer, 0, &its, NULL);
  92}
  93
  94long long os_nsecs(void)
  95{
  96        struct timespec ts;
  97
  98        clock_gettime(CLOCK_MONOTONIC,&ts);
  99        return timespec_to_ns(&ts);
 100}
 101
 102/**
 103 * os_idle_sleep() - sleep until interrupted
 104 */
 105void os_idle_sleep(void)
 106{
 107        struct itimerspec its;
 108        sigset_t set, old;
 109
 110        /* block SIGALRM while we analyze the timer state */
 111        sigemptyset(&set);
 112        sigaddset(&set, SIGALRM);
 113        sigprocmask(SIG_BLOCK, &set, &old);
 114
 115        /* check the timer, and if it'll fire then wait for it */
 116        timer_gettime(event_high_res_timer, &its);
 117        if (its.it_value.tv_sec || its.it_value.tv_nsec)
 118                sigsuspend(&old);
 119        /* either way, restore the signal mask */
 120        sigprocmask(SIG_UNBLOCK, &set, NULL);
 121}
 122