blob: e9231fa3ab81b8be06ddf1e7d072f223b456748f [file] [log] [blame]
Andy Ross987c0e52018-09-27 16:50:00 -07001/*
2 * Copyright (c) 2018 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
Stephanos Ioannidis2d746042019-10-25 00:08:21 +09006
Gerard Marull-Paretascffefc82022-05-06 11:04:23 +02007#include <zephyr/kernel.h>
8#include <zephyr/spinlock.h>
Andy Ross987c0e52018-09-27 16:50:00 -07009#include <ksched.h>
Anas Nashiffcf50ed2023-08-29 19:32:46 +000010#include <timeout_q.h>
Anas Nashif4e396172023-09-26 22:46:01 +000011#include <zephyr/internal/syscall_handler.h>
Gerard Marull-Paretascffefc82022-05-06 11:04:23 +020012#include <zephyr/drivers/timer/system_timer.h>
13#include <zephyr/sys_clock.h>
Andy Ross987c0e52018-09-27 16:50:00 -070014
Kumar Galaa1b77fd2020-05-27 11:26:57 -050015static uint64_t curr_tick;
Andy Ross987c0e52018-09-27 16:50:00 -070016
17static sys_dlist_t timeout_list = SYS_DLIST_STATIC_INIT(&timeout_list);
18
Peter Mitsis90e24982025-01-09 13:50:38 -080019/*
20 * The timeout code shall take no locks other than its own (timeout_lock), nor
21 * shall it call any other subsystem while holding this lock.
22 */
Andy Ross987c0e52018-09-27 16:50:00 -070023static struct k_spinlock timeout_lock;
24
Andy Ross1db9f182019-06-25 10:09:45 -070025#define MAX_WAIT (IS_ENABLED(CONFIG_SYSTEM_CLOCK_SLOPPY_IDLE) \
Andy Ross78327382020-03-05 15:18:14 -080026 ? K_TICKS_FOREVER : INT_MAX)
Andy Ross987c0e52018-09-27 16:50:00 -070027
Florian Grandel5fa55342023-06-28 23:17:45 +020028/* Ticks left to process in the currently-executing sys_clock_announce() */
Andy Ross1cfff072018-10-03 08:50:52 -070029static int announce_remaining;
Andy Ross987c0e52018-09-27 16:50:00 -070030
31#if defined(CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME)
Anisetti Avinash Krishna13921172025-03-25 21:04:02 +053032unsigned int z_clock_hw_cycles_per_sec = CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC;
Andrew Boiefd49cf72019-05-21 14:02:26 -070033
34#ifdef CONFIG_USERSPACE
Anisetti Avinash Krishna13921172025-03-25 21:04:02 +053035static inline unsigned int z_vrfy_sys_clock_hw_cycles_per_sec_runtime_get(void)
Andrew Boiefd49cf72019-05-21 14:02:26 -070036{
Anas Nashifa3872212021-03-13 08:16:53 -050037 return z_impl_sys_clock_hw_cycles_per_sec_runtime_get();
Andrew Boiefd49cf72019-05-21 14:02:26 -070038}
Yong Cong Sinbbe5e1e2024-01-24 17:35:04 +080039#include <zephyr/syscalls/sys_clock_hw_cycles_per_sec_runtime_get_mrsh.c>
Andrew Boiefd49cf72019-05-21 14:02:26 -070040#endif /* CONFIG_USERSPACE */
41#endif /* CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME */
Andy Ross987c0e52018-09-27 16:50:00 -070042
43static struct _timeout *first(void)
44{
45 sys_dnode_t *t = sys_dlist_peek_head(&timeout_list);
46
Hess Nathan6d417d52024-04-30 13:26:35 +020047 return (t == NULL) ? NULL : CONTAINER_OF(t, struct _timeout, node);
Andy Ross987c0e52018-09-27 16:50:00 -070048}
49
50static struct _timeout *next(struct _timeout *t)
51{
52 sys_dnode_t *n = sys_dlist_peek_next(&timeout_list, &t->node);
53
Hess Nathan6d417d52024-04-30 13:26:35 +020054 return (n == NULL) ? NULL : CONTAINER_OF(n, struct _timeout, node);
Andy Ross987c0e52018-09-27 16:50:00 -070055}
56
Andy Ross386894c2018-10-17 08:29:19 -070057static void remove_timeout(struct _timeout *t)
Andy Ross987c0e52018-09-27 16:50:00 -070058{
Peter A. Bigot25fbe7b2018-12-30 06:05:03 -060059 if (next(t) != NULL) {
60 next(t)->dticks += t->dticks;
Andy Ross71f5e562018-12-06 15:39:28 -080061 }
Peter A. Bigot25fbe7b2018-12-30 06:05:03 -060062
63 sys_dlist_remove(&t->node);
Andy Ross987c0e52018-09-27 16:50:00 -070064}
65
Kumar Galaa1b77fd2020-05-27 11:26:57 -050066static int32_t elapsed(void)
Andy Ross987c0e52018-09-27 16:50:00 -070067{
Florian Grandel5fa55342023-06-28 23:17:45 +020068 /* While sys_clock_announce() is executing, new relative timeouts will be
69 * scheduled relatively to the currently firing timeout's original tick
70 * value (=curr_tick) rather than relative to the current
71 * sys_clock_elapsed().
72 *
73 * This means that timeouts being scheduled from within timeout callbacks
74 * will be scheduled at well-defined offsets from the currently firing
75 * timeout.
76 *
77 * As a side effect, the same will happen if an ISR with higher priority
78 * preempts a timeout callback and schedules a timeout.
79 *
80 * The distinction is implemented by looking at announce_remaining which
81 * will be non-zero while sys_clock_announce() is executing and zero
82 * otherwise.
83 */
Anas Nashif9c1efe62021-02-25 15:33:15 -050084 return announce_remaining == 0 ? sys_clock_elapsed() : 0U;
Andy Ross987c0e52018-09-27 16:50:00 -070085}
86
Krzysztof Chruścińskie7d59052025-03-31 13:25:03 +020087static int32_t next_timeout(int32_t ticks_elapsed)
Andy Rosse664c782019-01-16 08:54:38 -080088{
Andy Rosse664c782019-01-16 08:54:38 -080089 struct _timeout *to = first();
Flavio Ceolin47b7c2e2022-02-08 15:28:09 -080090 int32_t ret;
91
92 if ((to == NULL) ||
93 ((int64_t)(to->dticks - ticks_elapsed) > (int64_t)INT_MAX)) {
94 ret = MAX_WAIT;
95 } else {
96 ret = MAX(0, to->dticks - ticks_elapsed);
97 }
Andy Rosse664c782019-01-16 08:54:38 -080098
Andy Rosse664c782019-01-16 08:54:38 -080099 return ret;
100}
101
Andy Ross78327382020-03-05 15:18:14 -0800102void z_add_timeout(struct _timeout *to, _timeout_func_t fn,
103 k_timeout_t timeout)
Andy Ross987c0e52018-09-27 16:50:00 -0700104{
Andy Ross12bd1872020-04-21 11:07:07 -0700105 if (K_TIMEOUT_EQ(timeout, K_FOREVER)) {
106 return;
107 }
108
Anas Nashif39f632e2020-12-07 13:15:42 -0500109#ifdef CONFIG_KERNEL_COHERENCE
Andy Rossf6d32ab2020-05-13 15:34:04 +0000110 __ASSERT_NO_MSG(arch_mem_coherent(to));
Simon Heinbcd1d192024-03-08 12:00:10 +0100111#endif /* CONFIG_KERNEL_COHERENCE */
Andy Rossf6d32ab2020-05-13 15:34:04 +0000112
Peter A. Bigotb4ece0a2019-01-02 08:29:43 -0600113 __ASSERT(!sys_dnode_is_linked(&to->node), "");
Andy Ross987c0e52018-09-27 16:50:00 -0700114 to->fn = fn;
115
Florian Grandele256b7d2023-07-07 09:12:38 +0200116 K_SPINLOCK(&timeout_lock) {
Andy Ross987c0e52018-09-27 16:50:00 -0700117 struct _timeout *t;
Krzysztof Chruścińskie7d59052025-03-31 13:25:03 +0200118 int32_t ticks_elapsed;
119 bool has_elapsed = false;
Andy Ross987c0e52018-09-27 16:50:00 -0700120
Peter Mitsis701aab92025-02-25 16:02:46 -0800121 if (Z_IS_TIMEOUT_RELATIVE(timeout)) {
Krzysztof Chruścińskie7d59052025-03-31 13:25:03 +0200122 ticks_elapsed = elapsed();
123 has_elapsed = true;
124 to->dticks = timeout.ticks + 1 + ticks_elapsed;
Peter Mitsis701aab92025-02-25 16:02:46 -0800125 } else {
Andrzej Głąbek59b21a22021-05-24 11:24:13 +0200126 k_ticks_t ticks = Z_TICK_ABS(timeout.ticks) - curr_tick;
127
128 to->dticks = MAX(1, ticks);
Andrzej Głąbek59b21a22021-05-24 11:24:13 +0200129 }
130
Andy Ross987c0e52018-09-27 16:50:00 -0700131 for (t = first(); t != NULL; t = next(t)) {
Andy Ross987c0e52018-09-27 16:50:00 -0700132 if (t->dticks > to->dticks) {
133 t->dticks -= to->dticks;
Andy Rosseda4c022019-01-28 09:35:27 -0800134 sys_dlist_insert(&t->node, &to->node);
Andy Ross987c0e52018-09-27 16:50:00 -0700135 break;
136 }
137 to->dticks -= t->dticks;
138 }
139
140 if (t == NULL) {
141 sys_dlist_append(&timeout_list, &to->node);
142 }
Andy Ross987c0e52018-09-27 16:50:00 -0700143
Krzysztof Chruścińskiaee8dd12024-03-26 16:33:06 +0100144 if (to == first() && announce_remaining == 0) {
Krzysztof Chruścińskie7d59052025-03-31 13:25:03 +0200145 if (!has_elapsed) {
146 /* In case of absolute timeout that is first to expire
147 * elapsed need to be read from the system clock.
148 */
149 ticks_elapsed = elapsed();
150 }
151 sys_clock_set_timeout(next_timeout(ticks_elapsed), false);
Pawel Dunajbaea2242018-11-22 11:49:32 +0100152 }
Andy Ross02165d72018-11-20 08:26:34 -0800153 }
Andy Ross987c0e52018-09-27 16:50:00 -0700154}
155
Patrik Flykt4344e272019-03-08 14:19:05 -0700156int z_abort_timeout(struct _timeout *to)
Andy Ross987c0e52018-09-27 16:50:00 -0700157{
Peter A. Bigotb4ece0a2019-01-02 08:29:43 -0600158 int ret = -EINVAL;
Andy Ross987c0e52018-09-27 16:50:00 -0700159
Florian Grandele256b7d2023-07-07 09:12:38 +0200160 K_SPINLOCK(&timeout_lock) {
Peter A. Bigot25fbe7b2018-12-30 06:05:03 -0600161 if (sys_dnode_is_linked(&to->node)) {
Dong Wangdd5f11c2025-01-02 13:48:40 +0800162 bool is_first = (to == first());
163
Andy Ross386894c2018-10-17 08:29:19 -0700164 remove_timeout(to);
Andy Ross987c0e52018-09-27 16:50:00 -0700165 ret = 0;
Dong Wangdd5f11c2025-01-02 13:48:40 +0800166 if (is_first) {
Krzysztof Chruścińskie7d59052025-03-31 13:25:03 +0200167 sys_clock_set_timeout(next_timeout(elapsed()), false);
Dong Wangdd5f11c2025-01-02 13:48:40 +0800168 }
Andy Ross987c0e52018-09-27 16:50:00 -0700169 }
170 }
171
172 return ret;
173}
174
Andy Ross5a5d3da2020-03-09 13:59:15 -0700175/* must be locked */
Peter A. Bigot16a40812020-09-18 16:24:57 -0500176static k_ticks_t timeout_rem(const struct _timeout *timeout)
Andy Ross987c0e52018-09-27 16:50:00 -0700177{
Andy Ross5a5d3da2020-03-09 13:59:15 -0700178 k_ticks_t ticks = 0;
Andy Ross987c0e52018-09-27 16:50:00 -0700179
Andy Ross5a5d3da2020-03-09 13:59:15 -0700180 for (struct _timeout *t = first(); t != NULL; t = next(t)) {
181 ticks += t->dticks;
182 if (timeout == t) {
183 break;
Andy Ross987c0e52018-09-27 16:50:00 -0700184 }
185 }
186
Nicolas Pitrec31d6462024-03-06 11:12:42 -0500187 return ticks;
Andy Ross987c0e52018-09-27 16:50:00 -0700188}
189
Peter A. Bigot16a40812020-09-18 16:24:57 -0500190k_ticks_t z_timeout_remaining(const struct _timeout *timeout)
Andy Ross5a5d3da2020-03-09 13:59:15 -0700191{
192 k_ticks_t ticks = 0;
193
Florian Grandele256b7d2023-07-07 09:12:38 +0200194 K_SPINLOCK(&timeout_lock) {
Nicolas Pitrec31d6462024-03-06 11:12:42 -0500195 if (!z_is_inactive_timeout(timeout)) {
196 ticks = timeout_rem(timeout) - elapsed();
197 }
Andy Ross5a5d3da2020-03-09 13:59:15 -0700198 }
199
200 return ticks;
201}
202
Peter A. Bigot16a40812020-09-18 16:24:57 -0500203k_ticks_t z_timeout_expires(const struct _timeout *timeout)
Andy Ross5a5d3da2020-03-09 13:59:15 -0700204{
205 k_ticks_t ticks = 0;
206
Florian Grandele256b7d2023-07-07 09:12:38 +0200207 K_SPINLOCK(&timeout_lock) {
Nicolas Pitrec31d6462024-03-06 11:12:42 -0500208 ticks = curr_tick;
209 if (!z_is_inactive_timeout(timeout)) {
210 ticks += timeout_rem(timeout);
211 }
Andy Ross5a5d3da2020-03-09 13:59:15 -0700212 }
213
214 return ticks;
215}
216
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500217int32_t z_get_next_timeout_expiry(void)
Andy Ross987c0e52018-09-27 16:50:00 -0700218{
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500219 int32_t ret = (int32_t) K_TICKS_FOREVER;
Andy Ross987c0e52018-09-27 16:50:00 -0700220
Florian Grandele256b7d2023-07-07 09:12:38 +0200221 K_SPINLOCK(&timeout_lock) {
Krzysztof Chruścińskie7d59052025-03-31 13:25:03 +0200222 ret = next_timeout(elapsed());
Andy Ross987c0e52018-09-27 16:50:00 -0700223 }
Andy Ross987c0e52018-09-27 16:50:00 -0700224 return ret;
225}
226
Anas Nashif9c1efe62021-02-25 15:33:15 -0500227void sys_clock_announce(int32_t ticks)
Andy Ross43ab8da2018-12-20 09:23:31 -0800228{
Andy Ross43ab8da2018-12-20 09:23:31 -0800229 k_spinlock_key_t key = k_spin_lock(&timeout_lock);
230
Andy Ross0b2ed382022-04-12 09:52:39 -0700231 /* We release the lock around the callbacks below, so on SMP
232 * systems someone might be already running the loop. Don't
Pisit Sawangvonganan5ed3cd42024-07-06 01:12:07 +0700233 * race (which will cause parallel execution of "sequential"
Andy Ross0b2ed382022-04-12 09:52:39 -0700234 * timeouts and confuse apps), just increment the tick count
235 * and return.
236 */
Peter Mitsis3e2f30a2022-07-29 09:29:32 -0400237 if (IS_ENABLED(CONFIG_SMP) && (announce_remaining != 0)) {
Andy Ross0b2ed382022-04-12 09:52:39 -0700238 announce_remaining += ticks;
239 k_spin_unlock(&timeout_lock, key);
240 return;
241 }
242
Andy Ross43ab8da2018-12-20 09:23:31 -0800243 announce_remaining = ticks;
244
Andrei Emeltchenko9551f272023-08-21 16:00:22 +0300245 struct _timeout *t;
Peter Mitsis42db0962022-12-14 11:53:58 -0500246
247 for (t = first();
248 (t != NULL) && (t->dticks <= announce_remaining);
249 t = first()) {
Andy Ross43ab8da2018-12-20 09:23:31 -0800250 int dt = t->dticks;
251
252 curr_tick += dt;
Andy Ross43ab8da2018-12-20 09:23:31 -0800253 t->dticks = 0;
254 remove_timeout(t);
255
256 k_spin_unlock(&timeout_lock, key);
257 t->fn(t);
258 key = k_spin_lock(&timeout_lock);
Peter Mitsis3e2f30a2022-07-29 09:29:32 -0400259 announce_remaining -= dt;
Andy Ross43ab8da2018-12-20 09:23:31 -0800260 }
261
Peter Mitsis42db0962022-12-14 11:53:58 -0500262 if (t != NULL) {
263 t->dticks -= announce_remaining;
Andy Ross43ab8da2018-12-20 09:23:31 -0800264 }
265
266 curr_tick += announce_remaining;
267 announce_remaining = 0;
268
Krzysztof Chruścińskie7d59052025-03-31 13:25:03 +0200269 sys_clock_set_timeout(next_timeout(0), false);
Andy Ross43ab8da2018-12-20 09:23:31 -0800270
271 k_spin_unlock(&timeout_lock, key);
Andy Rossf3afd5a2023-03-06 14:31:35 -0800272
273#ifdef CONFIG_TIMESLICING
274 z_time_slice();
Simon Heinbcd1d192024-03-08 12:00:10 +0100275#endif /* CONFIG_TIMESLICING */
Andy Ross43ab8da2018-12-20 09:23:31 -0800276}
277
Anas Nashiffe0872c2021-03-13 08:21:21 -0500278int64_t sys_clock_tick_get(void)
Andy Ross987c0e52018-09-27 16:50:00 -0700279{
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500280 uint64_t t = 0U;
Andy Ross987c0e52018-09-27 16:50:00 -0700281
Florian Grandele256b7d2023-07-07 09:12:38 +0200282 K_SPINLOCK(&timeout_lock) {
Peter Mitsis71ef6692022-08-03 16:11:32 -0400283 t = curr_tick + elapsed();
Andy Ross987c0e52018-09-27 16:50:00 -0700284 }
285 return t;
286}
287
Anas Nashif5c90ceb2021-03-13 08:19:53 -0500288uint32_t sys_clock_tick_get_32(void)
Andy Ross987c0e52018-09-27 16:50:00 -0700289{
Andy Rossd8421ad2018-10-02 11:12:08 -0700290#ifdef CONFIG_TICKLESS_KERNEL
Anas Nashiffe0872c2021-03-13 08:21:21 -0500291 return (uint32_t)sys_clock_tick_get();
Andy Rossd8421ad2018-10-02 11:12:08 -0700292#else
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500293 return (uint32_t)curr_tick;
Simon Heinbcd1d192024-03-08 12:00:10 +0100294#endif /* CONFIG_TICKLESS_KERNEL */
Andy Ross987c0e52018-09-27 16:50:00 -0700295}
296
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500297int64_t z_impl_k_uptime_ticks(void)
Andy Ross987c0e52018-09-27 16:50:00 -0700298{
Anas Nashiffe0872c2021-03-13 08:21:21 -0500299 return sys_clock_tick_get();
Andy Ross987c0e52018-09-27 16:50:00 -0700300}
301
302#ifdef CONFIG_USERSPACE
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500303static inline int64_t z_vrfy_k_uptime_ticks(void)
Andy Ross987c0e52018-09-27 16:50:00 -0700304{
Andy Ross914205c2020-03-10 15:26:38 -0700305 return z_impl_k_uptime_ticks();
Andy Ross987c0e52018-09-27 16:50:00 -0700306}
Yong Cong Sinbbe5e1e2024-01-24 17:35:04 +0800307#include <zephyr/syscalls/k_uptime_ticks_mrsh.c>
Simon Heinbcd1d192024-03-08 12:00:10 +0100308#endif /* CONFIG_USERSPACE */
Andy Ross78327382020-03-05 15:18:14 -0800309
Nicolas Pitre52e2f832023-07-06 13:56:01 -0400310k_timepoint_t sys_timepoint_calc(k_timeout_t timeout)
Andy Ross78327382020-03-05 15:18:14 -0800311{
Nicolas Pitre52e2f832023-07-06 13:56:01 -0400312 k_timepoint_t timepoint;
Andy Ross78327382020-03-05 15:18:14 -0800313
314 if (K_TIMEOUT_EQ(timeout, K_FOREVER)) {
Nicolas Pitre52e2f832023-07-06 13:56:01 -0400315 timepoint.tick = UINT64_MAX;
Andy Ross78327382020-03-05 15:18:14 -0800316 } else if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {
Nicolas Pitre52e2f832023-07-06 13:56:01 -0400317 timepoint.tick = 0;
Jennifer Williamsdc11ffb2021-03-20 00:36:55 +0200318 } else {
Nicolas Pitre52e2f832023-07-06 13:56:01 -0400319 k_ticks_t dt = timeout.ticks;
Andy Ross4c7b77a2020-03-09 09:35:35 -0700320
Peter Mitsis701aab92025-02-25 16:02:46 -0800321 if (Z_IS_TIMEOUT_RELATIVE(timeout)) {
Nicolas Pitre52e2f832023-07-06 13:56:01 -0400322 timepoint.tick = sys_clock_tick_get() + MAX(1, dt);
Peter Mitsis701aab92025-02-25 16:02:46 -0800323 } else {
324 timepoint.tick = Z_TICK_ABS(dt);
Jennifer Williamsdc11ffb2021-03-20 00:36:55 +0200325 }
Andy Ross4c7b77a2020-03-09 09:35:35 -0700326 }
Nicolas Pitre52e2f832023-07-06 13:56:01 -0400327
328 return timepoint;
329}
330
331k_timeout_t sys_timepoint_timeout(k_timepoint_t timepoint)
332{
333 uint64_t now, remaining;
334
335 if (timepoint.tick == UINT64_MAX) {
336 return K_FOREVER;
337 }
338 if (timepoint.tick == 0) {
339 return K_NO_WAIT;
340 }
341
342 now = sys_clock_tick_get();
343 remaining = (timepoint.tick > now) ? (timepoint.tick - now) : 0;
344 return K_TICKS(remaining);
Andy Ross78327382020-03-05 15:18:14 -0800345}
Chris Friedt4108e142022-12-15 10:14:43 -0800346
347#ifdef CONFIG_ZTEST
348void z_impl_sys_clock_tick_set(uint64_t tick)
349{
350 curr_tick = tick;
351}
352
353void z_vrfy_sys_clock_tick_set(uint64_t tick)
354{
355 z_impl_sys_clock_tick_set(tick);
356}
Simon Heinbcd1d192024-03-08 12:00:10 +0100357#endif /* CONFIG_ZTEST */