time.c 2.7 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0
2
/*
A
Anton Ivanov 已提交
3 4 5
 * 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
J
Jeff Dike 已提交
6
 * Copyright (C) 2000 - 2007 Jeff Dike (jdike{addtoit,linux.intel}.com)
7 8
 */

J
Jeff Dike 已提交
9
#include <stddef.h>
10
#include <unistd.h>
J
Jeff Dike 已提交
11 12
#include <errno.h>
#include <signal.h>
13
#include <time.h>
L
Linus Torvalds 已提交
14
#include <sys/time.h>
15 16
#include <kern_util.h>
#include <os.h>
A
Anton Ivanov 已提交
17
#include <string.h>
18

A
Anton Ivanov 已提交
19
static timer_t event_high_res_timer = 0;
J
Jeff Dike 已提交
20

A
Anton Ivanov 已提交
21 22 23 24
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;
25 26
}

A
Anton Ivanov 已提交
27
static inline long long timespec_to_ns(const struct timespec *ts)
J
Jeff Dike 已提交
28
{
J
Johannes Berg 已提交
29
	return ((long long) ts->tv_sec * UM_NSEC_PER_SEC) + ts->tv_nsec;
A
Anton Ivanov 已提交
30
}
J
Jeff Dike 已提交
31

J
Johannes Berg 已提交
32 33
long long os_persistent_clock_emulation(void)
{
A
Anton Ivanov 已提交
34
	struct timespec realtime_tp;
J
Jeff Dike 已提交
35

A
Anton Ivanov 已提交
36 37
	clock_gettime(CLOCK_REALTIME, &realtime_tp);
	return timespec_to_ns(&realtime_tp);
J
Jeff Dike 已提交
38 39
}

J
Jeff Dike 已提交
40
/**
A
Anton Ivanov 已提交
41
 * os_timer_create() - create an new posix (interval) timer
J
Jeff Dike 已提交
42
 */
J
Johannes Berg 已提交
43 44 45
int os_timer_create(void)
{
	timer_t *t = &event_high_res_timer;
A
Anton Ivanov 已提交
46

J
Johannes Berg 已提交
47
	if (timer_create(CLOCK_MONOTONIC, NULL, t) == -1)
A
Anton Ivanov 已提交
48
		return -1;
J
Johannes Berg 已提交
49

A
Anton Ivanov 已提交
50
	return 0;
J
Jeff Dike 已提交
51 52
}

53
int os_timer_set_interval(unsigned long long nsecs)
54
{
A
Anton Ivanov 已提交
55
	struct itimerspec its;
J
Jeff Dike 已提交
56

57 58
	its.it_value.tv_sec = nsecs / UM_NSEC_PER_SEC;
	its.it_value.tv_nsec = nsecs % UM_NSEC_PER_SEC;
J
Jeff Dike 已提交
59

60 61
	its.it_interval.tv_sec = nsecs / UM_NSEC_PER_SEC;
	its.it_interval.tv_nsec = nsecs % UM_NSEC_PER_SEC;
L
Linus Torvalds 已提交
62

J
Johannes Berg 已提交
63
	if (timer_settime(event_high_res_timer, 0, &its, NULL) == -1)
A
Anton Ivanov 已提交
64
		return -errno;
L
Linus Torvalds 已提交
65

66
	return 0;
J
Jeff Dike 已提交
67
}
J
Jeff Dike 已提交
68

69
int os_timer_one_shot(unsigned long long nsecs)
A
Anton Ivanov 已提交
70
{
J
Johannes Berg 已提交
71
	struct itimerspec its = {
72 73
		.it_value.tv_sec = nsecs / UM_NSEC_PER_SEC,
		.it_value.tv_nsec = nsecs % UM_NSEC_PER_SEC,
74

J
Johannes Berg 已提交
75 76 77
		.it_interval.tv_sec = 0,
		.it_interval.tv_nsec = 0, // we cheat here
	};
J
Jeff Dike 已提交
78

A
Anton Ivanov 已提交
79 80
	timer_settime(event_high_res_timer, 0, &its, NULL);
	return 0;
J
Jeff Dike 已提交
81 82
}

A
Anton Ivanov 已提交
83 84 85
/**
 * os_timer_disable() - disable the posix (interval) timer
 */
J
Johannes Berg 已提交
86
void os_timer_disable(void)
J
Jeff Dike 已提交
87
{
A
Anton Ivanov 已提交
88
	struct itimerspec its;
J
Jeff Dike 已提交
89

A
Anton Ivanov 已提交
90
	memset(&its, 0, sizeof(struct itimerspec));
J
Johannes Berg 已提交
91
	timer_settime(event_high_res_timer, 0, &its, NULL);
A
Anton Ivanov 已提交
92
}
J
Jeff Dike 已提交
93

A
Anton Ivanov 已提交
94 95 96
long long os_nsecs(void)
{
	struct timespec ts;
J
Jeff Dike 已提交
97

A
Anton Ivanov 已提交
98 99
	clock_gettime(CLOCK_MONOTONIC,&ts);
	return timespec_to_ns(&ts);
J
Jeff Dike 已提交
100 101
}

A
Anton Ivanov 已提交
102
/**
103
 * os_idle_sleep() - sleep until interrupted
A
Anton Ivanov 已提交
104
 */
105
void os_idle_sleep(void)
106
{
107 108 109 110 111 112 113 114 115 116 117 118 119 120
	struct itimerspec its;
	sigset_t set, old;

	/* block SIGALRM while we analyze the timer state */
	sigemptyset(&set);
	sigaddset(&set, SIGALRM);
	sigprocmask(SIG_BLOCK, &set, &old);

	/* check the timer, and if it'll fire then wait for it */
	timer_gettime(event_high_res_timer, &its);
	if (its.it_value.tv_sec || its.it_value.tv_nsec)
		sigsuspend(&old);
	/* either way, restore the signal mask */
	sigprocmask(SIG_UNBLOCK, &set, NULL);
121
}