Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/um/os-Linux/time.c
49231 views
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 ([email protected])
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/signalfd.h>
15
#include <sys/time.h>
16
#include <kern_util.h>
17
#include <os.h>
18
#include <smp.h>
19
#include <string.h>
20
#include "internal.h"
21
22
static timer_t event_high_res_timer[CONFIG_NR_CPUS] = { 0 };
23
24
static inline long long timespec_to_ns(const struct timespec *ts)
25
{
26
return ((long long) ts->tv_sec * UM_NSEC_PER_SEC) + ts->tv_nsec;
27
}
28
29
long long os_persistent_clock_emulation(void)
30
{
31
struct timespec realtime_tp;
32
33
clock_gettime(CLOCK_REALTIME, &realtime_tp);
34
return timespec_to_ns(&realtime_tp);
35
}
36
37
#ifndef sigev_notify_thread_id
38
#define sigev_notify_thread_id _sigev_un._tid
39
#endif
40
41
/**
42
* os_timer_create() - create an new posix (interval) timer
43
*/
44
int os_timer_create(void)
45
{
46
int cpu = uml_curr_cpu();
47
timer_t *t = &event_high_res_timer[cpu];
48
struct sigevent sev = {
49
.sigev_notify = SIGEV_THREAD_ID,
50
.sigev_signo = SIGALRM,
51
.sigev_value.sival_ptr = t,
52
.sigev_notify_thread_id = gettid(),
53
};
54
55
if (timer_create(CLOCK_MONOTONIC, &sev, t) == -1)
56
return -1;
57
58
return 0;
59
}
60
61
int os_timer_set_interval(int cpu, unsigned long long nsecs)
62
{
63
struct itimerspec its;
64
65
its.it_value.tv_sec = nsecs / UM_NSEC_PER_SEC;
66
its.it_value.tv_nsec = nsecs % UM_NSEC_PER_SEC;
67
68
its.it_interval.tv_sec = nsecs / UM_NSEC_PER_SEC;
69
its.it_interval.tv_nsec = nsecs % UM_NSEC_PER_SEC;
70
71
if (timer_settime(event_high_res_timer[cpu], 0, &its, NULL) == -1)
72
return -errno;
73
74
return 0;
75
}
76
77
int os_timer_one_shot(int cpu, unsigned long long nsecs)
78
{
79
struct itimerspec its = {
80
.it_value.tv_sec = nsecs / UM_NSEC_PER_SEC,
81
.it_value.tv_nsec = nsecs % UM_NSEC_PER_SEC,
82
83
.it_interval.tv_sec = 0,
84
.it_interval.tv_nsec = 0, // we cheat here
85
};
86
87
timer_settime(event_high_res_timer[cpu], 0, &its, NULL);
88
return 0;
89
}
90
91
/**
92
* os_timer_disable() - disable the posix (interval) timer
93
* @cpu: the CPU for which the timer is to be disabled
94
*/
95
void os_timer_disable(int cpu)
96
{
97
struct itimerspec its;
98
99
memset(&its, 0, sizeof(struct itimerspec));
100
timer_settime(event_high_res_timer[cpu], 0, &its, NULL);
101
}
102
103
long long os_nsecs(void)
104
{
105
struct timespec ts;
106
107
clock_gettime(CLOCK_MONOTONIC,&ts);
108
return timespec_to_ns(&ts);
109
}
110
111
static __thread int wake_signals;
112
113
void os_idle_prepare(void)
114
{
115
sigset_t set;
116
117
sigemptyset(&set);
118
sigaddset(&set, SIGALRM);
119
sigaddset(&set, IPI_SIGNAL);
120
121
/*
122
* We need to use signalfd rather than sigsuspend in idle sleep
123
* because the IPI signal is a real-time signal that carries data,
124
* and unlike handling SIGALRM, we cannot simply flag it in
125
* signals_pending.
126
*/
127
wake_signals = signalfd(-1, &set, SFD_CLOEXEC);
128
if (wake_signals < 0)
129
panic("Failed to create signal FD, errno = %d", errno);
130
}
131
132
/**
133
* os_idle_sleep() - sleep until interrupted
134
*/
135
void os_idle_sleep(void)
136
{
137
sigset_t set;
138
139
/*
140
* Block SIGALRM while performing the need_resched check.
141
* Note that, because IRQs are disabled, the IPI signal is
142
* already blocked.
143
*/
144
sigemptyset(&set);
145
sigaddset(&set, SIGALRM);
146
sigprocmask(SIG_BLOCK, &set, NULL);
147
148
/*
149
* Because disabling IRQs does not block SIGALRM, it is also
150
* necessary to check for any pending timer alarms.
151
*/
152
if (!uml_need_resched() && !timer_alarm_pending())
153
os_poll(1, &wake_signals);
154
155
/* Restore the signal mask. */
156
sigprocmask(SIG_UNBLOCK, &set, NULL);
157
}
158
159