blob: 972d971c0b85cd761701b92a20837c8d774249b4 [file] [log] [blame]
Benjamin Walsh456c6da2016-09-02 18:55:39 -04001/*
2 * Copyright (c) 1997-2016 Wind River Systems, Inc.
3 *
David B. Kinderac74d8b2017-01-18 17:01:01 -08004 * SPDX-License-Identifier: Apache-2.0
Benjamin Walsh456c6da2016-09-02 18:55:39 -04005 */
6
Allan Stephens45bfa372016-10-12 12:39:42 -05007#include <kernel.h>
Anas Nashif569f0b42016-12-17 13:18:45 -05008#include <debug/object_tracing_common.h>
Allan Stephense7d2cc22016-10-19 16:10:46 -05009#include <init.h>
Benjamin Walsh456c6da2016-09-02 18:55:39 -040010#include <wait_q.h>
Andrew Boiea354d492017-09-29 16:22:28 -070011#include <syscall_handler.h>
Flavio Ceolin76b35182018-12-16 12:48:29 -080012#include <stdbool.h>
Andy Rossb29fb222019-02-05 16:19:30 -080013#include <spinlock.h>
Benjamin Walsh456c6da2016-09-02 18:55:39 -040014
Andy Rossb29fb222019-02-05 16:19:30 -080015static struct k_spinlock lock;
16
Anas Nashif2f203c22016-12-18 06:57:45 -050017#ifdef CONFIG_OBJECT_TRACING
Allan Stephense7d2cc22016-10-19 16:10:46 -050018
Maciek Borzecki059544d2017-05-18 12:16:45 +020019struct k_timer *_trace_list_k_timer;
20
Allan Stephense7d2cc22016-10-19 16:10:46 -050021/*
22 * Complete initialization of statically defined timers.
23 */
24static int init_timer_module(struct device *dev)
25{
26 ARG_UNUSED(dev);
27
Nicolas Pitreaa9228852019-06-03 13:01:43 -040028 Z_STRUCT_SECTION_FOREACH(k_timer, timer) {
Allan Stephense7d2cc22016-10-19 16:10:46 -050029 SYS_TRACING_OBJ_INIT(k_timer, timer);
30 }
31 return 0;
32}
33
Andrew Boie0b474ee2016-11-08 11:06:55 -080034SYS_INIT(init_timer_module, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_OBJECTS);
Allan Stephense7d2cc22016-10-19 16:10:46 -050035
Anas Nashif2f203c22016-12-18 06:57:45 -050036#endif /* CONFIG_OBJECT_TRACING */
Allan Stephense7d2cc22016-10-19 16:10:46 -050037
Benjamin Walsh456c6da2016-09-02 18:55:39 -040038/**
Allan Stephens45bfa372016-10-12 12:39:42 -050039 * @brief Handle expiration of a kernel timer object.
Benjamin Walsh456c6da2016-09-02 18:55:39 -040040 *
Allan Stephens45bfa372016-10-12 12:39:42 -050041 * @param t Timeout used by the timer.
Benjamin Walsh456c6da2016-09-02 18:55:39 -040042 *
43 * @return N/A
44 */
Patrik Flykt4344e272019-03-08 14:19:05 -070045void z_timer_expiration_handler(struct _timeout *t)
Benjamin Walsh456c6da2016-09-02 18:55:39 -040046{
Benjamin Walsh456c6da2016-09-02 18:55:39 -040047 struct k_timer *timer = CONTAINER_OF(t, struct k_timer, timeout);
Benjamin Walshb889fa82016-12-07 22:39:31 -050048 struct k_thread *thread;
Benjamin Walsh456c6da2016-09-02 18:55:39 -040049
Allan Stephens6c98c4d2016-10-17 14:34:53 -050050 /*
51 * if the timer is periodic, start it again; don't add _TICK_ALIGN
52 * since we're already aligned to a tick boundary
53 */
Benjamin Walsh456c6da2016-09-02 18:55:39 -040054 if (timer->period > 0) {
Patrik Flykt4344e272019-03-08 14:19:05 -070055 z_add_timeout(&timer->timeout, z_timer_expiration_handler,
Andy Rossfe82f1c2018-09-26 15:14:21 -070056 timer->period);
Benjamin Walsh456c6da2016-09-02 18:55:39 -040057 }
58
Allan Stephens45bfa372016-10-12 12:39:42 -050059 /* update timer's status */
Patrik Flykt24d71432019-03-26 19:57:45 -060060 timer->status += 1U;
Allan Stephens45bfa372016-10-12 12:39:42 -050061
62 /* invoke timer expiry function */
Flavio Ceolin76b35182018-12-16 12:48:29 -080063 if (timer->expiry_fn != NULL) {
Allan Stephens45bfa372016-10-12 12:39:42 -050064 timer->expiry_fn(timer);
Benjamin Walsh456c6da2016-09-02 18:55:39 -040065 }
Benjamin Walshb889fa82016-12-07 22:39:31 -050066
Patrik Flykt4344e272019-03-08 14:19:05 -070067 thread = z_waitq_head(&timer->wait_q);
Benjamin Walshb889fa82016-12-07 22:39:31 -050068
Flavio Ceolin4218d5f2018-09-17 09:39:51 -070069 if (thread == NULL) {
Benjamin Walshb889fa82016-12-07 22:39:31 -050070 return;
Benjamin Walsh456c6da2016-09-02 18:55:39 -040071 }
Allan Stephens45bfa372016-10-12 12:39:42 -050072
Benjamin Walshb889fa82016-12-07 22:39:31 -050073 /*
Andy Ross22642cf2018-04-02 18:24:58 -070074 * Interrupts _DO NOT_ have to be locked in this specific
75 * instance of thread unpending because a) this is the only
76 * place a thread can be taken off this pend queue, and b) the
77 * only place a thread can be put on the pend queue is at
78 * thread level, which of course cannot interrupt the current
79 * context.
Benjamin Walshb889fa82016-12-07 22:39:31 -050080 */
Patrik Flykt4344e272019-03-08 14:19:05 -070081 z_unpend_thread_no_timeout(thread);
Benjamin Walshb889fa82016-12-07 22:39:31 -050082
Patrik Flykt4344e272019-03-08 14:19:05 -070083 z_ready_thread(thread);
Benjamin Walshb889fa82016-12-07 22:39:31 -050084
Patrik Flykt4344e272019-03-08 14:19:05 -070085 z_set_thread_return_value(thread, 0);
Benjamin Walsh456c6da2016-09-02 18:55:39 -040086}
87
88
Allan Stephens45bfa372016-10-12 12:39:42 -050089void k_timer_init(struct k_timer *timer,
Flavio Ceolin118715c2018-11-16 19:52:37 -080090 k_timer_expiry_t expiry_fn,
91 k_timer_stop_t stop_fn)
Benjamin Walsh456c6da2016-09-02 18:55:39 -040092{
Allan Stephens45bfa372016-10-12 12:39:42 -050093 timer->expiry_fn = expiry_fn;
94 timer->stop_fn = stop_fn;
Patrik Flykt24d71432019-03-26 19:57:45 -060095 timer->status = 0U;
Allan Stephens45bfa372016-10-12 12:39:42 -050096
Patrik Flykt4344e272019-03-08 14:19:05 -070097 z_waitq_init(&timer->wait_q);
98 z_init_timeout(&timer->timeout, z_timer_expiration_handler);
Allan Stephense7d2cc22016-10-19 16:10:46 -050099 SYS_TRACING_OBJ_INIT(k_timer, timer);
Allan Stephens45bfa372016-10-12 12:39:42 -0500100
Maciek Borzecki4fef7602017-05-18 08:49:50 +0200101 timer->user_data = NULL;
Andrew Boie945af952017-08-22 13:15:23 -0700102
Patrik Flykt4344e272019-03-08 14:19:05 -0700103 z_object_init(timer);
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400104}
105
106
Patrik Flykt4344e272019-03-08 14:19:05 -0700107void z_impl_k_timer_start(struct k_timer *timer, s32_t duration, s32_t period)
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400108{
109 __ASSERT(duration >= 0 && period >= 0 &&
110 (duration != 0 || period != 0), "invalid parameters\n");
111
Kumar Galacc334c72017-04-21 10:55:34 -0500112 volatile s32_t period_in_ticks, duration_in_ticks;
Benjamin Walsh6ca6c282016-12-09 13:39:00 -0500113
Patrik Flykt4344e272019-03-08 14:19:05 -0700114 period_in_ticks = z_ms_to_ticks(period);
115 duration_in_ticks = z_ms_to_ticks(duration);
Benjamin Walsh6ca6c282016-12-09 13:39:00 -0500116
Patrik Flykt4344e272019-03-08 14:19:05 -0700117 (void)z_abort_timeout(&timer->timeout);
Benjamin Walsh6ca6c282016-12-09 13:39:00 -0500118 timer->period = period_in_ticks;
Patrik Flykt24d71432019-03-26 19:57:45 -0600119 timer->status = 0U;
Patrik Flykt4344e272019-03-08 14:19:05 -0700120 z_add_timeout(&timer->timeout, z_timer_expiration_handler,
Andy Rossfe82f1c2018-09-26 15:14:21 -0700121 duration_in_ticks);
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400122}
123
Andrew Boiea354d492017-09-29 16:22:28 -0700124#ifdef CONFIG_USERSPACE
Andy Ross643701a2019-08-13 12:58:38 -0700125static inline void z_vrfy_k_timer_start(struct k_timer *timer,
126 s32_t duration, s32_t period)
Andrew Boiea354d492017-09-29 16:22:28 -0700127{
Andrew Boie8345e5e2018-05-04 15:57:57 -0700128 Z_OOPS(Z_SYSCALL_VERIFY(duration >= 0 && period >= 0 &&
129 (duration != 0 || period != 0)));
130 Z_OOPS(Z_SYSCALL_OBJ(timer, K_OBJ_TIMER));
Andy Ross65649742019-08-06 13:34:31 -0700131 z_impl_k_timer_start(timer, duration, period);
Andrew Boiea354d492017-09-29 16:22:28 -0700132}
Andy Ross65649742019-08-06 13:34:31 -0700133#include <syscalls/k_timer_start_mrsh.c>
Andrew Boiea354d492017-09-29 16:22:28 -0700134#endif
135
Patrik Flykt4344e272019-03-08 14:19:05 -0700136void z_impl_k_timer_stop(struct k_timer *timer)
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400137{
Patrik Flykt4344e272019-03-08 14:19:05 -0700138 int inactive = z_abort_timeout(&timer->timeout) != 0;
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400139
Benjamin Walshd211a522016-12-06 11:44:01 -0500140 if (inactive) {
Allan Stephens45bfa372016-10-12 12:39:42 -0500141 return;
142 }
143
Flavio Ceolin76b35182018-12-16 12:48:29 -0800144 if (timer->stop_fn != NULL) {
Allan Stephens45bfa372016-10-12 12:39:42 -0500145 timer->stop_fn(timer);
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400146 }
147
Patrik Flykt4344e272019-03-08 14:19:05 -0700148 struct k_thread *pending_thread = z_unpend1_no_timeout(&timer->wait_q);
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400149
Flavio Ceolin4218d5f2018-09-17 09:39:51 -0700150 if (pending_thread != NULL) {
Patrik Flykt4344e272019-03-08 14:19:05 -0700151 z_ready_thread(pending_thread);
152 z_reschedule_unlocked();
Allan Stephens45bfa372016-10-12 12:39:42 -0500153 }
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400154}
155
Andrew Boiea354d492017-09-29 16:22:28 -0700156#ifdef CONFIG_USERSPACE
Andy Ross65649742019-08-06 13:34:31 -0700157static inline void z_vrfy_k_timer_stop(struct k_timer *timer)
158{
159 Z_OOPS(Z_SYSCALL_OBJ(timer, K_OBJ_TIMER));
160 z_impl_k_timer_stop(timer);
161}
162#include <syscalls/k_timer_stop_mrsh.c>
Andrew Boiea354d492017-09-29 16:22:28 -0700163#endif
164
Patrik Flykt4344e272019-03-08 14:19:05 -0700165u32_t z_impl_k_timer_status_get(struct k_timer *timer)
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400166{
Andy Rossb29fb222019-02-05 16:19:30 -0800167 k_spinlock_key_t key = k_spin_lock(&lock);
Kumar Galacc334c72017-04-21 10:55:34 -0500168 u32_t result = timer->status;
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400169
Patrik Flykt24d71432019-03-26 19:57:45 -0600170 timer->status = 0U;
Andy Rossb29fb222019-02-05 16:19:30 -0800171 k_spin_unlock(&lock, key);
Allan Stephens45bfa372016-10-12 12:39:42 -0500172
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400173 return result;
174}
175
Andrew Boiea354d492017-09-29 16:22:28 -0700176#ifdef CONFIG_USERSPACE
Andy Ross65649742019-08-06 13:34:31 -0700177static inline u32_t z_vrfy_k_timer_status_get(struct k_timer *timer)
178{
179 Z_OOPS(Z_SYSCALL_OBJ(timer, K_OBJ_TIMER));
180 return z_impl_k_timer_status_get(timer);
181}
182#include <syscalls/k_timer_status_get_mrsh.c>
Andrew Boiea354d492017-09-29 16:22:28 -0700183#endif
184
Patrik Flykt4344e272019-03-08 14:19:05 -0700185u32_t z_impl_k_timer_status_sync(struct k_timer *timer)
Allan Stephens45bfa372016-10-12 12:39:42 -0500186{
Patrik Flykt4344e272019-03-08 14:19:05 -0700187 __ASSERT(!z_is_in_isr(), "");
Allan Stephens45bfa372016-10-12 12:39:42 -0500188
Andy Rossb29fb222019-02-05 16:19:30 -0800189 k_spinlock_key_t key = k_spin_lock(&lock);
Kumar Galacc334c72017-04-21 10:55:34 -0500190 u32_t result = timer->status;
Allan Stephens45bfa372016-10-12 12:39:42 -0500191
Patrik Flykt24d71432019-03-26 19:57:45 -0600192 if (result == 0U) {
Patrik Flykt4344e272019-03-08 14:19:05 -0700193 if (!z_is_inactive_timeout(&timer->timeout)) {
Allan Stephens45bfa372016-10-12 12:39:42 -0500194 /* wait for timer to expire or stop */
Patrik Flykt4344e272019-03-08 14:19:05 -0700195 (void)z_pend_curr(&lock, key, &timer->wait_q, K_FOREVER);
Allan Stephens45bfa372016-10-12 12:39:42 -0500196
197 /* get updated timer status */
Andy Rossb29fb222019-02-05 16:19:30 -0800198 key = k_spin_lock(&lock);
Allan Stephens45bfa372016-10-12 12:39:42 -0500199 result = timer->status;
200 } else {
201 /* timer is already stopped */
202 }
203 } else {
204 /* timer has already expired at least once */
205 }
206
Patrik Flykt24d71432019-03-26 19:57:45 -0600207 timer->status = 0U;
Andy Rossb29fb222019-02-05 16:19:30 -0800208 k_spin_unlock(&lock, key);
Allan Stephens45bfa372016-10-12 12:39:42 -0500209
210 return result;
211}
212
Andrew Boiea354d492017-09-29 16:22:28 -0700213#ifdef CONFIG_USERSPACE
Andy Ross65649742019-08-06 13:34:31 -0700214static inline u32_t z_vrfy_k_timer_status_sync(struct k_timer *timer)
Andrew Boie225e4c02017-10-12 09:54:26 -0700215{
Andrew Boie8345e5e2018-05-04 15:57:57 -0700216 Z_OOPS(Z_SYSCALL_OBJ(timer, K_OBJ_TIMER));
Andy Ross65649742019-08-06 13:34:31 -0700217 return z_impl_k_timer_status_sync(timer);
Andrew Boie225e4c02017-10-12 09:54:26 -0700218}
Andy Ross65649742019-08-06 13:34:31 -0700219#include <syscalls/k_timer_status_sync_mrsh.c>
220
221static inline u32_t z_vrfy_k_timer_remaining_get(struct k_timer *timer)
222{
223 Z_OOPS(Z_SYSCALL_OBJ(timer, K_OBJ_TIMER));
224 return z_impl_k_timer_remaining_get(timer);
225}
226#include <syscalls/k_timer_remaining_get_mrsh.c>
227
228static inline void *z_vrfy_k_timer_user_data_get(struct k_timer *timer)
229{
230 Z_OOPS(Z_SYSCALL_OBJ(timer, K_OBJ_TIMER));
231 return z_impl_k_timer_user_data_get(timer);
232}
233#include <syscalls/k_timer_user_data_get_mrsh.c>
234
Andy Ross643701a2019-08-13 12:58:38 -0700235static inline void z_vrfy_k_timer_user_data_set(struct k_timer *timer,
236 void *user_data)
Andy Ross65649742019-08-06 13:34:31 -0700237{
238 Z_OOPS(Z_SYSCALL_OBJ(timer, K_OBJ_TIMER));
239 z_impl_k_timer_user_data_set(timer, user_data);
240}
241#include <syscalls/k_timer_user_data_set_mrsh.c>
242
Andrew Boie225e4c02017-10-12 09:54:26 -0700243#endif