There really is no reason to pass the amount of time we should sleep, especially since it's just hard-coded to one second. Additionally, one second isn't really all that long, and as we are expecting to be woken up by a signal, we can sleep longer and avoid doing some work every second, so replace the current clock_nanosleep() with just an empty select() that can _only_ be woken up by a signal. We can also remove the deliver_alarm() since we don't need to do that when we got e.g. SIGIO that woke us up, and if we got SIGALRM the signal handler will actually (have) run, so it's just unnecessary extra work. Similarly, in time-travel mode, just program the wakeup event from idle to be S64_MAX, which is basically the most you could ever simulate to. Of course, you should already have an event in the list that's earlier and will cause a wakeup, normally that's the regular timer interrupt, though in suspend it may (later) also be an RTC event. Since actually getting to this point would be a bug and you can't ever get out again, panic() on it in the time control code. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Acked-By: Anton Ivanov <anton.ivanov@cambridgegreys.com> Signed-off-by: Richard Weinberger <richard@nod.at>
109 lines
2.3 KiB
C
109 lines
2.3 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (C) 2015 Anton Ivanov (aivanov@{brocade.com,kot-begemot.co.uk})
|
|
* Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
|
|
* Copyright (C) 2012-2014 Cisco Systems
|
|
* Copyright (C) 2000 - 2007 Jeff Dike (jdike{addtoit,linux.intel}.com)
|
|
*/
|
|
|
|
#include <stddef.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
#include <time.h>
|
|
#include <sys/time.h>
|
|
#include <kern_util.h>
|
|
#include <os.h>
|
|
#include <string.h>
|
|
|
|
static timer_t event_high_res_timer = 0;
|
|
|
|
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;
|
|
}
|
|
|
|
static inline long long timespec_to_ns(const struct timespec *ts)
|
|
{
|
|
return ((long long) ts->tv_sec * UM_NSEC_PER_SEC) + ts->tv_nsec;
|
|
}
|
|
|
|
long long os_persistent_clock_emulation(void)
|
|
{
|
|
struct timespec realtime_tp;
|
|
|
|
clock_gettime(CLOCK_REALTIME, &realtime_tp);
|
|
return timespec_to_ns(&realtime_tp);
|
|
}
|
|
|
|
/**
|
|
* os_timer_create() - create an new posix (interval) timer
|
|
*/
|
|
int os_timer_create(void)
|
|
{
|
|
timer_t *t = &event_high_res_timer;
|
|
|
|
if (timer_create(CLOCK_MONOTONIC, NULL, t) == -1)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int os_timer_set_interval(unsigned long long nsecs)
|
|
{
|
|
struct itimerspec its;
|
|
|
|
its.it_value.tv_sec = nsecs / UM_NSEC_PER_SEC;
|
|
its.it_value.tv_nsec = nsecs % UM_NSEC_PER_SEC;
|
|
|
|
its.it_interval.tv_sec = nsecs / UM_NSEC_PER_SEC;
|
|
its.it_interval.tv_nsec = nsecs % UM_NSEC_PER_SEC;
|
|
|
|
if (timer_settime(event_high_res_timer, 0, &its, NULL) == -1)
|
|
return -errno;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int os_timer_one_shot(unsigned long long nsecs)
|
|
{
|
|
struct itimerspec its = {
|
|
.it_value.tv_sec = nsecs / UM_NSEC_PER_SEC,
|
|
.it_value.tv_nsec = nsecs % UM_NSEC_PER_SEC,
|
|
|
|
.it_interval.tv_sec = 0,
|
|
.it_interval.tv_nsec = 0, // we cheat here
|
|
};
|
|
|
|
timer_settime(event_high_res_timer, 0, &its, NULL);
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* os_timer_disable() - disable the posix (interval) timer
|
|
*/
|
|
void os_timer_disable(void)
|
|
{
|
|
struct itimerspec its;
|
|
|
|
memset(&its, 0, sizeof(struct itimerspec));
|
|
timer_settime(event_high_res_timer, 0, &its, NULL);
|
|
}
|
|
|
|
long long os_nsecs(void)
|
|
{
|
|
struct timespec ts;
|
|
|
|
clock_gettime(CLOCK_MONOTONIC,&ts);
|
|
return timespec_to_ns(&ts);
|
|
}
|
|
|
|
/**
|
|
* os_idle_sleep() - sleep until interrupted
|
|
*/
|
|
void os_idle_sleep(void)
|
|
{
|
|
pause();
|
|
}
|