File Index
Files and directories
Sign in
FILE

time.c

File preview with syntax highlighting.

linux-6.19.14/arch/um/os-Linux/time.c C
  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/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
 22static timer_t event_high_res_timer[CONFIG_NR_CPUS] = { 0 };
 23
 24static 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
 29long 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 */
 44int 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
 61int 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
 77int 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 */
 95void 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
103long long os_nsecs(void)
104{
105	struct timespec ts;
106
107	clock_gettime(CLOCK_MONOTONIC,&ts);
108	return timespec_to_ns(&ts);
109}
110
111static __thread int wake_signals;
112
113void 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 */
135void 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}
~/ Read-only file preview.