Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2018 Intel Corporation
3 : : *
4 : : * SPDX-License-Identifier: Apache-2.0
5 : : */
6 : : #include <zephyr/kernel.h>
7 : : #include <ksched.h>
8 : : #include <zephyr/spinlock.h>
9 : : #include <wait_q.h>
10 : : #include <kthread.h>
11 : : #include <priority_q.h>
12 : : #include <kswap.h>
13 : : #include <ipi.h>
14 : : #include <kernel_arch_func.h>
15 : : #include <zephyr/internal/syscall_handler.h>
16 : : #include <zephyr/drivers/timer/system_timer.h>
17 : : #include <stdbool.h>
18 : : #include <kernel_internal.h>
19 : : #include <zephyr/logging/log.h>
20 : : #include <zephyr/sys/atomic.h>
21 : : #include <zephyr/sys/math_extras.h>
22 : : #include <zephyr/timing/timing.h>
23 : : #include <zephyr/sys/util.h>
24 : :
25 : : LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL);
26 : :
27 : : #if defined(CONFIG_SWAP_NONATOMIC) && defined(CONFIG_TIMESLICING)
28 : : extern struct k_thread *pending_current;
29 : : #endif
30 : :
31 : : struct k_spinlock _sched_spinlock;
32 : :
33 : : /* Storage to "complete" the context switch from an invalid/incomplete thread
34 : : * context (ex: exiting an ISR that aborted arch_current_thread())
35 : : */
36 : : __incoherent struct k_thread _thread_dummy;
37 : :
38 : : static ALWAYS_INLINE void update_cache(int preempt_ok);
39 : : static void halt_thread(struct k_thread *thread, uint8_t new_state);
40 : : static void add_to_waitq_locked(struct k_thread *thread, _wait_q_t *wait_q);
41 : :
42 : :
43 : : BUILD_ASSERT(CONFIG_NUM_COOP_PRIORITIES >= CONFIG_NUM_METAIRQ_PRIORITIES,
44 : : "You need to provide at least as many CONFIG_NUM_COOP_PRIORITIES as "
45 : : "CONFIG_NUM_METAIRQ_PRIORITIES as Meta IRQs are just a special class of cooperative "
46 : : "threads.");
47 : :
48 : : /*
49 : : * Return value same as e.g. memcmp
50 : : * > 0 -> thread 1 priority > thread 2 priority
51 : : * = 0 -> thread 1 priority == thread 2 priority
52 : : * < 0 -> thread 1 priority < thread 2 priority
53 : : * Do not rely on the actual value returned aside from the above.
54 : : * (Again, like memcmp.)
55 : : */
56 : 58 : int32_t z_sched_prio_cmp(struct k_thread *thread_1,
57 : : struct k_thread *thread_2)
58 : : {
59 : : /* `prio` is <32b, so the below cannot overflow. */
60 : 58 : int32_t b1 = thread_1->base.prio;
61 : 58 : int32_t b2 = thread_2->base.prio;
62 : :
63 [ + + ]: 58 : if (b1 != b2) {
64 : 52 : return b2 - b1;
65 : : }
66 : :
67 : : #ifdef CONFIG_SCHED_DEADLINE
68 : : /* If we assume all deadlines live within the same "half" of
69 : : * the 32 bit modulus space (this is a documented API rule),
70 : : * then the latest deadline in the queue minus the earliest is
71 : : * guaranteed to be (2's complement) non-negative. We can
72 : : * leverage that to compare the values without having to check
73 : : * the current time.
74 : : */
75 : : uint32_t d1 = thread_1->base.prio_deadline;
76 : : uint32_t d2 = thread_2->base.prio_deadline;
77 : :
78 : : if (d1 != d2) {
79 : : /* Sooner deadline means higher effective priority.
80 : : * Doing the calculation with unsigned types and casting
81 : : * to signed isn't perfect, but at least reduces this
82 : : * from UB on overflow to impdef.
83 : : */
84 : : return (int32_t) (d2 - d1);
85 : : }
86 : : #endif /* CONFIG_SCHED_DEADLINE */
87 : : return 0;
88 : : }
89 : :
90 : 113 : static ALWAYS_INLINE void *thread_runq(struct k_thread *thread)
91 : : {
92 : : #ifdef CONFIG_SCHED_CPU_MASK_PIN_ONLY
93 : : int cpu, m = thread->base.cpu_mask;
94 : :
95 : : /* Edge case: it's legal per the API to "make runnable" a
96 : : * thread with all CPUs masked off (i.e. one that isn't
97 : : * actually runnable!). Sort of a wart in the API and maybe
98 : : * we should address this in docs/assertions instead to avoid
99 : : * the extra test.
100 : : */
101 : : cpu = m == 0 ? 0 : u32_count_trailing_zeros(m);
102 : :
103 : : return &_kernel.cpus[cpu].ready_q.runq;
104 : : #else
105 : 113 : ARG_UNUSED(thread);
106 : 113 : return &_kernel.ready_q.runq;
107 : : #endif /* CONFIG_SCHED_CPU_MASK_PIN_ONLY */
108 : : }
109 : :
110 : 114 : static ALWAYS_INLINE void *curr_cpu_runq(void)
111 : : {
112 : : #ifdef CONFIG_SCHED_CPU_MASK_PIN_ONLY
113 : : return &arch_curr_cpu()->ready_q.runq;
114 : : #else
115 : 114 : return &_kernel.ready_q.runq;
116 : : #endif /* CONFIG_SCHED_CPU_MASK_PIN_ONLY */
117 : : }
118 : :
119 : 57 : static ALWAYS_INLINE void runq_add(struct k_thread *thread)
120 : : {
121 [ - + ]: 57 : __ASSERT_NO_MSG(!z_is_idle_thread_object(thread));
122 : :
123 : 57 : _priq_run_add(thread_runq(thread), thread);
124 : 57 : }
125 : :
126 : 56 : static ALWAYS_INLINE void runq_remove(struct k_thread *thread)
127 : : {
128 [ - + ]: 56 : __ASSERT_NO_MSG(!z_is_idle_thread_object(thread));
129 : :
130 : 56 : _priq_run_remove(thread_runq(thread), thread);
131 : 56 : }
132 : :
133 : 114 : static ALWAYS_INLINE struct k_thread *runq_best(void)
134 : : {
135 : 114 : return _priq_run_best(curr_cpu_runq());
136 : : }
137 : :
138 : : /* arch_current_thread() is never in the run queue until context switch on
139 : : * SMP configurations, see z_requeue_current()
140 : : */
141 : 113 : static inline bool should_queue_thread(struct k_thread *thread)
142 : : {
143 : 113 : return !IS_ENABLED(CONFIG_SMP) || (thread != arch_current_thread());
144 : : }
145 : :
146 : 57 : static ALWAYS_INLINE void queue_thread(struct k_thread *thread)
147 : : {
148 : 57 : thread->base.thread_state |= _THREAD_QUEUED;
149 [ + - ]: 57 : if (should_queue_thread(thread)) {
150 : 57 : runq_add(thread);
151 : : }
152 : : #ifdef CONFIG_SMP
153 : : if (thread == arch_current_thread()) {
154 : : /* add current to end of queue means "yield" */
155 : : _current_cpu->swap_ok = true;
156 : : }
157 : : #endif /* CONFIG_SMP */
158 : 57 : }
159 : :
160 : 56 : static ALWAYS_INLINE void dequeue_thread(struct k_thread *thread)
161 : : {
162 : 56 : thread->base.thread_state &= ~_THREAD_QUEUED;
163 [ + - ]: 56 : if (should_queue_thread(thread)) {
164 : 56 : runq_remove(thread);
165 : : }
166 : 56 : }
167 : :
168 : : /* Called out of z_swap() when CONFIG_SMP. The current thread can
169 : : * never live in the run queue until we are inexorably on the context
170 : : * switch path on SMP, otherwise there is a deadlock condition where a
171 : : * set of CPUs pick a cycle of threads to run and wait for them all to
172 : : * context switch forever.
173 : : */
174 : 0 : void z_requeue_current(struct k_thread *thread)
175 : : {
176 [ # # ]: 0 : if (z_is_thread_queued(thread)) {
177 : 0 : runq_add(thread);
178 : : }
179 : 0 : signal_pending_ipi();
180 : 0 : }
181 : :
182 : : /* Return true if the thread is aborting, else false */
183 : 0 : static inline bool is_aborting(struct k_thread *thread)
184 : : {
185 : 0 : return (thread->base.thread_state & _THREAD_ABORTING) != 0U;
186 : : }
187 : :
188 : : /* Return true if the thread is aborting or suspending, else false */
189 : 0 : static inline bool is_halting(struct k_thread *thread)
190 : : {
191 : 0 : return (thread->base.thread_state &
192 : 0 : (_THREAD_ABORTING | _THREAD_SUSPENDING)) != 0U;
193 : : }
194 : :
195 : : /* Clear the halting bits (_THREAD_ABORTING and _THREAD_SUSPENDING) */
196 : 46 : static inline void clear_halting(struct k_thread *thread)
197 : : {
198 : 46 : barrier_dmem_fence_full(); /* Other cpus spin on this locklessly! */
199 : 46 : thread->base.thread_state &= ~(_THREAD_ABORTING | _THREAD_SUSPENDING);
200 : 46 : }
201 : :
202 : 114 : static ALWAYS_INLINE struct k_thread *next_up(void)
203 : : {
204 : : #ifdef CONFIG_SMP
205 : : if (is_halting(arch_current_thread())) {
206 : : halt_thread(arch_current_thread(), is_aborting(arch_current_thread()) ?
207 : : _THREAD_DEAD : _THREAD_SUSPENDED);
208 : : }
209 : : #endif /* CONFIG_SMP */
210 : :
211 : 114 : struct k_thread *thread = runq_best();
212 : :
213 : : #if (CONFIG_NUM_METAIRQ_PRIORITIES > 0) && \
214 : : (CONFIG_NUM_COOP_PRIORITIES > CONFIG_NUM_METAIRQ_PRIORITIES)
215 : : /* MetaIRQs must always attempt to return back to a
216 : : * cooperative thread they preempted and not whatever happens
217 : : * to be highest priority now. The cooperative thread was
218 : : * promised it wouldn't be preempted (by non-metairq threads)!
219 : : */
220 : : struct k_thread *mirqp = _current_cpu->metairq_preempted;
221 : :
222 : : if (mirqp != NULL && (thread == NULL || !thread_is_metairq(thread))) {
223 : : if (!z_is_thread_prevented_from_running(mirqp)) {
224 : : thread = mirqp;
225 : : } else {
226 : : _current_cpu->metairq_preempted = NULL;
227 : : }
228 : : }
229 : : #endif
230 : : /* CONFIG_NUM_METAIRQ_PRIORITIES > 0 &&
231 : : * CONFIG_NUM_COOP_PRIORITIES > CONFIG_NUM_METAIRQ_PRIORITIES
232 : : */
233 : :
234 : : #ifndef CONFIG_SMP
235 : : /* In uniprocessor mode, we can leave the current thread in
236 : : * the queue (actually we have to, otherwise the assembly
237 : : * context switch code for all architectures would be
238 : : * responsible for putting it back in z_swap and ISR return!),
239 : : * which makes this choice simple.
240 : : */
241 [ - + ]: 114 : return (thread != NULL) ? thread : _current_cpu->idle_thread;
242 : : #else
243 : : /* Under SMP, the "cache" mechanism for selecting the next
244 : : * thread doesn't work, so we have more work to do to test
245 : : * arch_current_thread() against the best choice from the queue. Here, the
246 : : * thread selected above represents "the best thread that is
247 : : * not current".
248 : : *
249 : : * Subtle note on "queued": in SMP mode, arch_current_thread() does not
250 : : * live in the queue, so this isn't exactly the same thing as
251 : : * "ready", it means "is arch_current_thread() already added back to the
252 : : * queue such that we don't want to re-add it".
253 : : */
254 : : bool queued = z_is_thread_queued(arch_current_thread());
255 : : bool active = !z_is_thread_prevented_from_running(arch_current_thread());
256 : :
257 : : if (thread == NULL) {
258 : : thread = _current_cpu->idle_thread;
259 : : }
260 : :
261 : : if (active) {
262 : : int32_t cmp = z_sched_prio_cmp(arch_current_thread(), thread);
263 : :
264 : : /* Ties only switch if state says we yielded */
265 : : if ((cmp > 0) || ((cmp == 0) && !_current_cpu->swap_ok)) {
266 : : thread = arch_current_thread();
267 : : }
268 : :
269 : : if (!should_preempt(thread, _current_cpu->swap_ok)) {
270 : : thread = arch_current_thread();
271 : : }
272 : : }
273 : :
274 : : /* Put arch_current_thread() back into the queue */
275 : : if ((thread != arch_current_thread()) && active &&
276 : : !z_is_idle_thread_object(arch_current_thread()) && !queued) {
277 : : queue_thread(arch_current_thread());
278 : : }
279 : :
280 : : /* Take the new arch_current_thread() out of the queue */
281 : : if (z_is_thread_queued(thread)) {
282 : : dequeue_thread(thread);
283 : : }
284 : :
285 : : _current_cpu->swap_ok = false;
286 : : return thread;
287 : : #endif /* CONFIG_SMP */
288 : : }
289 : :
290 : 0 : void move_thread_to_end_of_prio_q(struct k_thread *thread)
291 : : {
292 [ # # ]: 0 : if (z_is_thread_queued(thread)) {
293 : 0 : dequeue_thread(thread);
294 : : }
295 : 0 : queue_thread(thread);
296 : 0 : update_cache(thread == arch_current_thread());
297 : 0 : }
298 : :
299 : : /* Track cooperative threads preempted by metairqs so we can return to
300 : : * them specifically. Called at the moment a new thread has been
301 : : * selected to run.
302 : : */
303 : : static void update_metairq_preempt(struct k_thread *thread)
304 : : {
305 : : #if (CONFIG_NUM_METAIRQ_PRIORITIES > 0) && \
306 : : (CONFIG_NUM_COOP_PRIORITIES > CONFIG_NUM_METAIRQ_PRIORITIES)
307 : : if (thread_is_metairq(thread) && !thread_is_metairq(arch_current_thread()) &&
308 : : !thread_is_preemptible(arch_current_thread())) {
309 : : /* Record new preemption */
310 : : _current_cpu->metairq_preempted = arch_current_thread();
311 : : } else if (!thread_is_metairq(thread) && !z_is_idle_thread_object(thread)) {
312 : : /* Returning from existing preemption */
313 : : _current_cpu->metairq_preempted = NULL;
314 : : }
315 : : #else
316 : : ARG_UNUSED(thread);
317 : : #endif
318 : : /* CONFIG_NUM_METAIRQ_PRIORITIES > 0 &&
319 : : * CONFIG_NUM_COOP_PRIORITIES > CONFIG_NUM_METAIRQ_PRIORITIES
320 : : */
321 : : }
322 : :
323 : 114 : static ALWAYS_INLINE void update_cache(int preempt_ok)
324 : : {
325 : : #ifndef CONFIG_SMP
326 : 114 : struct k_thread *thread = next_up();
327 : :
328 [ + + ]: 114 : if (should_preempt(thread, preempt_ok)) {
329 : : #ifdef CONFIG_TIMESLICING
330 [ + + ]: 110 : if (thread != arch_current_thread()) {
331 : 105 : z_reset_time_slice(thread);
332 : : }
333 : : #endif /* CONFIG_TIMESLICING */
334 : 110 : update_metairq_preempt(thread);
335 : 110 : _kernel.ready_q.cache = thread;
336 : : } else {
337 : 4 : _kernel.ready_q.cache = arch_current_thread();
338 : : }
339 : :
340 : : #else
341 : : /* The way this works is that the CPU record keeps its
342 : : * "cooperative swapping is OK" flag until the next reschedule
343 : : * call or context switch. It doesn't need to be tracked per
344 : : * thread because if the thread gets preempted for whatever
345 : : * reason the scheduler will make the same decision anyway.
346 : : */
347 : : _current_cpu->swap_ok = preempt_ok;
348 : : #endif /* CONFIG_SMP */
349 : 114 : }
350 : :
351 : 51 : static struct _cpu *thread_active_elsewhere(struct k_thread *thread)
352 : : {
353 : : /* Returns pointer to _cpu if the thread is currently running on
354 : : * another CPU. There are more scalable designs to answer this
355 : : * question in constant time, but this is fine for now.
356 : : */
357 : : #ifdef CONFIG_SMP
358 : : int currcpu = _current_cpu->id;
359 : :
360 : : unsigned int num_cpus = arch_num_cpus();
361 : :
362 : : for (int i = 0; i < num_cpus; i++) {
363 : : if ((i != currcpu) &&
364 : : (_kernel.cpus[i].current == thread)) {
365 : : return &_kernel.cpus[i];
366 : : }
367 : : }
368 : : #endif /* CONFIG_SMP */
369 : 51 : ARG_UNUSED(thread);
370 : 51 : return NULL;
371 : : }
372 : :
373 : 57 : static void ready_thread(struct k_thread *thread)
374 : : {
375 : : #ifdef CONFIG_KERNEL_COHERENCE
376 : : __ASSERT_NO_MSG(arch_mem_coherent(thread));
377 : : #endif /* CONFIG_KERNEL_COHERENCE */
378 : :
379 : : /* If thread is queued already, do not try and added it to the
380 : : * run queue again
381 : : */
382 [ + - + - ]: 57 : if (!z_is_thread_queued(thread) && z_is_thread_ready(thread)) {
383 : 57 : SYS_PORT_TRACING_OBJ_FUNC(k_thread, sched_ready, thread);
384 : :
385 : 57 : queue_thread(thread);
386 : 57 : update_cache(0);
387 : :
388 : 57 : flag_ipi(ipi_mask_create(thread));
389 : : }
390 : 57 : }
391 : :
392 : 5 : void z_ready_thread(struct k_thread *thread)
393 : : {
394 [ + + ]: 10 : K_SPINLOCK(&_sched_spinlock) {
395 [ + - ]: 5 : if (thread_active_elsewhere(thread) == NULL) {
396 : 5 : ready_thread(thread);
397 : : }
398 : : }
399 : 5 : }
400 : :
401 : 0 : void z_move_thread_to_end_of_prio_q(struct k_thread *thread)
402 : : {
403 [ # # ]: 0 : K_SPINLOCK(&_sched_spinlock) {
404 : 0 : move_thread_to_end_of_prio_q(thread);
405 : : }
406 : 0 : }
407 : :
408 : 50 : void z_sched_start(struct k_thread *thread)
409 : : {
410 : 50 : k_spinlock_key_t key = k_spin_lock(&_sched_spinlock);
411 : :
412 [ + + ]: 50 : if (z_has_thread_started(thread)) {
413 : 4 : k_spin_unlock(&_sched_spinlock, key);
414 : 4 : return;
415 : : }
416 : :
417 : 46 : z_mark_thread_as_started(thread);
418 : 46 : ready_thread(thread);
419 : 46 : z_reschedule(&_sched_spinlock, key);
420 : : }
421 : :
422 : : /* Spins in ISR context, waiting for a thread known to be running on
423 : : * another CPU to catch the IPI we sent and halt. Note that we check
424 : : * for ourselves being asynchronously halted first to prevent simple
425 : : * deadlocks (but not complex ones involving cycles of 3+ threads!).
426 : : * Acts to release the provided lock before returning.
427 : : */
428 : 0 : static void thread_halt_spin(struct k_thread *thread, k_spinlock_key_t key)
429 : : {
430 [ # # ]: 0 : if (is_halting(arch_current_thread())) {
431 : 0 : halt_thread(arch_current_thread(),
432 [ # # ]: 0 : is_aborting(arch_current_thread()) ? _THREAD_DEAD : _THREAD_SUSPENDED);
433 : : }
434 : 0 : k_spin_unlock(&_sched_spinlock, key);
435 [ # # ]: 0 : while (is_halting(thread)) {
436 : 0 : unsigned int k = arch_irq_lock();
437 : :
438 : 0 : arch_spin_relax(); /* Requires interrupts be masked */
439 : 0 : arch_irq_unlock(k);
440 : : }
441 : 0 : }
442 : :
443 : : /* Shared handler for k_thread_{suspend,abort}(). Called with the
444 : : * scheduler lock held and the key passed (which it may
445 : : * release/reacquire!) which will be released before a possible return
446 : : * (aborting arch_current_thread() will not return, obviously), which may be after
447 : : * a context switch.
448 : : */
449 : 46 : static void z_thread_halt(struct k_thread *thread, k_spinlock_key_t key,
450 : : bool terminate)
451 : : {
452 : 46 : _wait_q_t *wq = &thread->join_queue;
453 : : #ifdef CONFIG_SMP
454 : : wq = terminate ? wq : &thread->halt_queue;
455 : : #endif
456 : :
457 : : /* If the target is a thread running on another CPU, flag and
458 : : * poke (note that we might spin to wait, so a true
459 : : * synchronous IPI is needed here, not deferred!), it will
460 : : * halt itself in the IPI. Otherwise it's unscheduled, so we
461 : : * can clean it up directly.
462 : : */
463 : :
464 : 46 : struct _cpu *cpu = thread_active_elsewhere(thread);
465 : :
466 [ - + ]: 46 : if (cpu != NULL) {
467 [ # # ]: 0 : thread->base.thread_state |= (terminate ? _THREAD_ABORTING
468 : : : _THREAD_SUSPENDING);
469 : : #if defined(CONFIG_SMP) && defined(CONFIG_SCHED_IPI_SUPPORTED)
470 : : #ifdef CONFIG_ARCH_HAS_DIRECTED_IPIS
471 : : arch_sched_directed_ipi(IPI_CPU_MASK(cpu->id));
472 : : #else
473 : : arch_sched_broadcast_ipi();
474 : : #endif
475 : : #endif
476 [ # # ]: 0 : if (arch_is_in_isr()) {
477 : 0 : thread_halt_spin(thread, key);
478 : : } else {
479 : 0 : add_to_waitq_locked(arch_current_thread(), wq);
480 : 0 : z_swap(&_sched_spinlock, key);
481 : : }
482 : : } else {
483 [ - + ]: 46 : halt_thread(thread, terminate ? _THREAD_DEAD : _THREAD_SUSPENDED);
484 [ + - + - ]: 46 : if ((thread == arch_current_thread()) && !arch_is_in_isr()) {
485 : 46 : z_swap(&_sched_spinlock, key);
486 [ # # ]: 0 : __ASSERT(!terminate, "aborted arch_current_thread() back from dead");
487 : : } else {
488 : 0 : k_spin_unlock(&_sched_spinlock, key);
489 : : }
490 : : }
491 : : /* NOTE: the scheduler lock has been released. Don't put
492 : : * logic here, it's likely to be racy/deadlocky even if you
493 : : * re-take the lock!
494 : : */
495 : 0 : }
496 : :
497 : :
498 : 0 : void z_impl_k_thread_suspend(k_tid_t thread)
499 : : {
500 : 0 : SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_thread, suspend, thread);
501 : :
502 : 0 : (void)z_abort_thread_timeout(thread);
503 : :
504 : 0 : k_spinlock_key_t key = k_spin_lock(&_sched_spinlock);
505 : :
506 [ # # ]: 0 : if ((thread->base.thread_state & _THREAD_SUSPENDED) != 0U) {
507 : :
508 : : /* The target thread is already suspended. Nothing to do. */
509 : :
510 : 0 : k_spin_unlock(&_sched_spinlock, key);
511 : 0 : return;
512 : : }
513 : :
514 : 0 : z_thread_halt(thread, key, false);
515 : :
516 : 0 : SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_thread, suspend, thread);
517 : : }
518 : :
519 : : #ifdef CONFIG_USERSPACE
520 : : static inline void z_vrfy_k_thread_suspend(k_tid_t thread)
521 : : {
522 : : K_OOPS(K_SYSCALL_OBJ(thread, K_OBJ_THREAD));
523 : : z_impl_k_thread_suspend(thread);
524 : : }
525 : : #include <zephyr/syscalls/k_thread_suspend_mrsh.c>
526 : : #endif /* CONFIG_USERSPACE */
527 : :
528 : 0 : void z_impl_k_thread_resume(k_tid_t thread)
529 : : {
530 : 0 : SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_thread, resume, thread);
531 : :
532 : 0 : k_spinlock_key_t key = k_spin_lock(&_sched_spinlock);
533 : :
534 : : /* Do not try to resume a thread that was not suspended */
535 [ # # ]: 0 : if (!z_is_thread_suspended(thread)) {
536 : 0 : k_spin_unlock(&_sched_spinlock, key);
537 : 0 : return;
538 : : }
539 : :
540 : 0 : z_mark_thread_as_not_suspended(thread);
541 : 0 : ready_thread(thread);
542 : :
543 : 0 : z_reschedule(&_sched_spinlock, key);
544 : :
545 : 0 : SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_thread, resume, thread);
546 : : }
547 : :
548 : : #ifdef CONFIG_USERSPACE
549 : : static inline void z_vrfy_k_thread_resume(k_tid_t thread)
550 : : {
551 : : K_OOPS(K_SYSCALL_OBJ(thread, K_OBJ_THREAD));
552 : : z_impl_k_thread_resume(thread);
553 : : }
554 : : #include <zephyr/syscalls/k_thread_resume_mrsh.c>
555 : : #endif /* CONFIG_USERSPACE */
556 : :
557 : 10 : static void unready_thread(struct k_thread *thread)
558 : : {
559 [ + - ]: 10 : if (z_is_thread_queued(thread)) {
560 : 10 : dequeue_thread(thread);
561 : : }
562 : 10 : update_cache(thread == arch_current_thread());
563 : 10 : }
564 : :
565 : : /* _sched_spinlock must be held */
566 : 10 : static void add_to_waitq_locked(struct k_thread *thread, _wait_q_t *wait_q)
567 : : {
568 : 10 : unready_thread(thread);
569 : 10 : z_mark_thread_as_pending(thread);
570 : :
571 : 10 : SYS_PORT_TRACING_FUNC(k_thread, sched_pend, thread);
572 : :
573 [ + - ]: 10 : if (wait_q != NULL) {
574 : 10 : thread->base.pended_on = wait_q;
575 : 10 : _priq_wait_add(&wait_q->waitq, thread);
576 : : }
577 : 10 : }
578 : :
579 : 10 : static void add_thread_timeout(struct k_thread *thread, k_timeout_t timeout)
580 : : {
581 [ - + ]: 10 : if (!K_TIMEOUT_EQ(timeout, K_FOREVER)) {
582 : 0 : z_add_thread_timeout(thread, timeout);
583 : : }
584 : 10 : }
585 : :
586 : 4 : static void pend_locked(struct k_thread *thread, _wait_q_t *wait_q,
587 : : k_timeout_t timeout)
588 : : {
589 : : #ifdef CONFIG_KERNEL_COHERENCE
590 : : __ASSERT_NO_MSG(wait_q == NULL || arch_mem_coherent(wait_q));
591 : : #endif /* CONFIG_KERNEL_COHERENCE */
592 : 4 : add_to_waitq_locked(thread, wait_q);
593 : 4 : add_thread_timeout(thread, timeout);
594 : 4 : }
595 : :
596 : 0 : void z_pend_thread(struct k_thread *thread, _wait_q_t *wait_q,
597 : : k_timeout_t timeout)
598 : : {
599 [ # # # # ]: 0 : __ASSERT_NO_MSG(thread == arch_current_thread() || is_thread_dummy(thread));
600 [ # # ]: 0 : K_SPINLOCK(&_sched_spinlock) {
601 : 0 : pend_locked(thread, wait_q, timeout);
602 : : }
603 : 0 : }
604 : :
605 : 0 : void z_unpend_thread_no_timeout(struct k_thread *thread)
606 : : {
607 [ # # ]: 0 : K_SPINLOCK(&_sched_spinlock) {
608 [ # # ]: 0 : if (thread->base.pended_on != NULL) {
609 : 0 : unpend_thread_no_timeout(thread);
610 : : }
611 : : }
612 : 0 : }
613 : :
614 : 0 : void z_sched_wake_thread(struct k_thread *thread, bool is_timeout)
615 : : {
616 [ # # ]: 0 : K_SPINLOCK(&_sched_spinlock) {
617 : 0 : bool killed = (thread->base.thread_state &
618 : : (_THREAD_DEAD | _THREAD_ABORTING));
619 : :
620 : : #ifdef CONFIG_EVENTS
621 : : bool do_nothing = thread->no_wake_on_timeout && is_timeout;
622 : :
623 : : thread->no_wake_on_timeout = false;
624 : :
625 : : if (do_nothing) {
626 : : continue;
627 : : }
628 : : #endif /* CONFIG_EVENTS */
629 : :
630 [ # # ]: 0 : if (!killed) {
631 : : /* The thread is not being killed */
632 [ # # ]: 0 : if (thread->base.pended_on != NULL) {
633 : 0 : unpend_thread_no_timeout(thread);
634 : : }
635 : 0 : z_mark_thread_as_started(thread);
636 [ # # ]: 0 : if (is_timeout) {
637 : 0 : z_mark_thread_as_not_suspended(thread);
638 : : }
639 : 0 : ready_thread(thread);
640 : : }
641 : : }
642 : :
643 : 0 : }
644 : :
645 : : #ifdef CONFIG_SYS_CLOCK_EXISTS
646 : : /* Timeout handler for *_thread_timeout() APIs */
647 : 0 : void z_thread_timeout(struct _timeout *timeout)
648 : : {
649 : 0 : struct k_thread *thread = CONTAINER_OF(timeout,
650 : : struct k_thread, base.timeout);
651 : :
652 : 0 : z_sched_wake_thread(thread, true);
653 : 0 : }
654 : : #endif /* CONFIG_SYS_CLOCK_EXISTS */
655 : :
656 : 4 : int z_pend_curr(struct k_spinlock *lock, k_spinlock_key_t key,
657 : : _wait_q_t *wait_q, k_timeout_t timeout)
658 : : {
659 : : #if defined(CONFIG_TIMESLICING) && defined(CONFIG_SWAP_NONATOMIC)
660 : : pending_current = arch_current_thread();
661 : : #endif /* CONFIG_TIMESLICING && CONFIG_SWAP_NONATOMIC */
662 [ - + ]: 4 : __ASSERT_NO_MSG(sizeof(_sched_spinlock) == 0 || lock != &_sched_spinlock);
663 : :
664 : : /* We do a "lock swap" prior to calling z_swap(), such that
665 : : * the caller's lock gets released as desired. But we ensure
666 : : * that we hold the scheduler lock and leave local interrupts
667 : : * masked until we reach the context switch. z_swap() itself
668 : : * has similar code; the duplication is because it's a legacy
669 : : * API that doesn't expect to be called with scheduler lock
670 : : * held.
671 : : */
672 : 4 : (void) k_spin_lock(&_sched_spinlock);
673 : 4 : pend_locked(arch_current_thread(), wait_q, timeout);
674 : 4 : k_spin_release(lock);
675 : 4 : return z_swap(&_sched_spinlock, key);
676 : : }
677 : :
678 : 0 : struct k_thread *z_unpend1_no_timeout(_wait_q_t *wait_q)
679 : : {
680 : 0 : struct k_thread *thread = NULL;
681 : :
682 [ # # ]: 0 : K_SPINLOCK(&_sched_spinlock) {
683 : 0 : thread = _priq_wait_best(&wait_q->waitq);
684 : :
685 [ # # ]: 0 : if (thread != NULL) {
686 : 0 : unpend_thread_no_timeout(thread);
687 : : }
688 : : }
689 : :
690 : 0 : return thread;
691 : : }
692 : :
693 : 0 : void z_unpend_thread(struct k_thread *thread)
694 : : {
695 : 0 : z_unpend_thread_no_timeout(thread);
696 : 0 : (void)z_abort_thread_timeout(thread);
697 : 0 : }
698 : :
699 : : /* Priority set utility that does no rescheduling, it just changes the
700 : : * run queue state, returning true if a reschedule is needed later.
701 : : */
702 : 0 : bool z_thread_prio_set(struct k_thread *thread, int prio)
703 : : {
704 : 0 : bool need_sched = 0;
705 : 0 : int old_prio = thread->base.prio;
706 : :
707 [ # # ]: 0 : K_SPINLOCK(&_sched_spinlock) {
708 : 0 : need_sched = z_is_thread_ready(thread);
709 : :
710 [ # # ]: 0 : if (need_sched) {
711 : 0 : if (!IS_ENABLED(CONFIG_SMP) || z_is_thread_queued(thread)) {
712 : 0 : dequeue_thread(thread);
713 : 0 : thread->base.prio = prio;
714 : 0 : queue_thread(thread);
715 : :
716 : 0 : if (old_prio > prio) {
717 : 0 : flag_ipi(ipi_mask_create(thread));
718 : : }
719 : : } else {
720 : : /*
721 : : * This is a running thread on SMP. Update its
722 : : * priority, but do not requeue it. An IPI is
723 : : * needed if the priority is both being lowered
724 : : * and it is running on another CPU.
725 : : */
726 : :
727 : : thread->base.prio = prio;
728 : :
729 : : struct _cpu *cpu;
730 : :
731 : : cpu = thread_active_elsewhere(thread);
732 : : if ((cpu != NULL) && (old_prio < prio)) {
733 : 0 : flag_ipi(IPI_CPU_MASK(cpu->id));
734 : : }
735 : : }
736 : :
737 : 0 : update_cache(1);
738 : : } else {
739 : 0 : thread->base.prio = prio;
740 : : }
741 : : }
742 : :
743 : 0 : SYS_PORT_TRACING_OBJ_FUNC(k_thread, sched_priority_set, thread, prio);
744 : :
745 : 0 : return need_sched;
746 : : }
747 : :
748 : 93 : static inline bool resched(uint32_t key)
749 : : {
750 : : #ifdef CONFIG_SMP
751 : : _current_cpu->swap_ok = 0;
752 : : #endif /* CONFIG_SMP */
753 : :
754 [ + - - + ]: 93 : return arch_irq_unlocked(key) && !arch_is_in_isr();
755 : : }
756 : :
757 : : /*
758 : : * Check if the next ready thread is the same as the current thread
759 : : * and save the trip if true.
760 : : */
761 : 93 : static inline bool need_swap(void)
762 : : {
763 : : /* the SMP case will be handled in C based z_swap() */
764 : : #ifdef CONFIG_SMP
765 : : return true;
766 : : #else
767 : 93 : struct k_thread *new_thread;
768 : :
769 : : /* Check if the next ready thread is the same as the current thread */
770 : 93 : new_thread = _kernel.ready_q.cache;
771 : 93 : return new_thread != arch_current_thread();
772 : : #endif /* CONFIG_SMP */
773 : : }
774 : :
775 : 50 : void z_reschedule(struct k_spinlock *lock, k_spinlock_key_t key)
776 : : {
777 [ + - + + ]: 50 : if (resched(key.key) && need_swap()) {
778 : 42 : z_swap(lock, key);
779 : : } else {
780 : 8 : k_spin_unlock(lock, key);
781 : 50 : signal_pending_ipi();
782 : : }
783 : 50 : }
784 : :
785 : 43 : void z_reschedule_irqlock(uint32_t key)
786 : : {
787 [ + - - + ]: 43 : if (resched(key) && need_swap()) {
788 : 0 : z_swap_irqlock(key);
789 : : } else {
790 : 43 : irq_unlock(key);
791 : 43 : signal_pending_ipi();
792 : : }
793 : 43 : }
794 : :
795 : 1 : void k_sched_lock(void)
796 : : {
797 [ + + ]: 2 : K_SPINLOCK(&_sched_spinlock) {
798 : 1 : SYS_PORT_TRACING_FUNC(k_thread, sched_lock);
799 : :
800 : 1 : z_sched_lock();
801 : : }
802 : 1 : }
803 : :
804 : 1 : void k_sched_unlock(void)
805 : : {
806 [ + + ]: 2 : K_SPINLOCK(&_sched_spinlock) {
807 [ - + ]: 1 : __ASSERT(arch_current_thread()->base.sched_locked != 0U, "");
808 [ - + ]: 1 : __ASSERT(!arch_is_in_isr(), "");
809 : :
810 : 1 : ++arch_current_thread()->base.sched_locked;
811 : 1 : update_cache(0);
812 : : }
813 : :
814 : 1 : LOG_DBG("scheduler unlocked (%p:%d)",
815 : : arch_current_thread(), arch_current_thread()->base.sched_locked);
816 : :
817 : 1 : SYS_PORT_TRACING_FUNC(k_thread, sched_unlock);
818 : :
819 : 1 : z_reschedule_unlocked();
820 : 1 : }
821 : :
822 : 0 : struct k_thread *z_swap_next_thread(void)
823 : : {
824 : : #ifdef CONFIG_SMP
825 : : struct k_thread *ret = next_up();
826 : :
827 : : if (ret == arch_current_thread()) {
828 : : /* When not swapping, have to signal IPIs here. In
829 : : * the context switch case it must happen later, after
830 : : * arch_current_thread() gets requeued.
831 : : */
832 : : signal_pending_ipi();
833 : : }
834 : : return ret;
835 : : #else
836 : 0 : return _kernel.ready_q.cache;
837 : : #endif /* CONFIG_SMP */
838 : : }
839 : :
840 : : #ifdef CONFIG_USE_SWITCH
841 : : /* Just a wrapper around arch_current_thread_set(xxx) with tracing */
842 : : static inline void set_current(struct k_thread *new_thread)
843 : : {
844 : : z_thread_mark_switched_out();
845 : : arch_current_thread_set(new_thread);
846 : : }
847 : :
848 : : /**
849 : : * @brief Determine next thread to execute upon completion of an interrupt
850 : : *
851 : : * Thread preemption is performed by context switching after the completion
852 : : * of a non-recursed interrupt. This function determines which thread to
853 : : * switch to if any. This function accepts as @p interrupted either:
854 : : *
855 : : * - The handle for the interrupted thread in which case the thread's context
856 : : * must already be fully saved and ready to be picked up by a different CPU.
857 : : *
858 : : * - NULL if more work is required to fully save the thread's state after
859 : : * it is known that a new thread is to be scheduled. It is up to the caller
860 : : * to store the handle resulting from the thread that is being switched out
861 : : * in that thread's "switch_handle" field after its
862 : : * context has fully been saved, following the same requirements as with
863 : : * the @ref arch_switch() function.
864 : : *
865 : : * If a new thread needs to be scheduled then its handle is returned.
866 : : * Otherwise the same value provided as @p interrupted is returned back.
867 : : * Those handles are the same opaque types used by the @ref arch_switch()
868 : : * function.
869 : : *
870 : : * @warning
871 : : * The arch_current_thread() value may have changed after this call and not refer
872 : : * to the interrupted thread anymore. It might be necessary to make a local
873 : : * copy before calling this function.
874 : : *
875 : : * @param interrupted Handle for the thread that was interrupted or NULL.
876 : : * @retval Handle for the next thread to execute, or @p interrupted when
877 : : * no new thread is to be scheduled.
878 : : */
879 : : void *z_get_next_switch_handle(void *interrupted)
880 : : {
881 : : z_check_stack_sentinel();
882 : :
883 : : #ifdef CONFIG_SMP
884 : : void *ret = NULL;
885 : :
886 : : K_SPINLOCK(&_sched_spinlock) {
887 : : struct k_thread *old_thread = arch_current_thread(), *new_thread;
888 : :
889 : : if (IS_ENABLED(CONFIG_SMP)) {
890 : : old_thread->switch_handle = NULL;
891 : : }
892 : : new_thread = next_up();
893 : :
894 : : z_sched_usage_switch(new_thread);
895 : :
896 : : if (old_thread != new_thread) {
897 : : uint8_t cpu_id;
898 : :
899 : : update_metairq_preempt(new_thread);
900 : : z_sched_switch_spin(new_thread);
901 : : arch_cohere_stacks(old_thread, interrupted, new_thread);
902 : :
903 : : _current_cpu->swap_ok = 0;
904 : : cpu_id = arch_curr_cpu()->id;
905 : : new_thread->base.cpu = cpu_id;
906 : : set_current(new_thread);
907 : :
908 : : #ifdef CONFIG_TIMESLICING
909 : : z_reset_time_slice(new_thread);
910 : : #endif /* CONFIG_TIMESLICING */
911 : :
912 : : #ifdef CONFIG_SPIN_VALIDATE
913 : : /* Changed arch_current_thread()! Update the spinlock
914 : : * bookkeeping so the validation doesn't get
915 : : * confused when the "wrong" thread tries to
916 : : * release the lock.
917 : : */
918 : : z_spin_lock_set_owner(&_sched_spinlock);
919 : : #endif /* CONFIG_SPIN_VALIDATE */
920 : :
921 : : /* A queued (runnable) old/current thread
922 : : * needs to be added back to the run queue
923 : : * here, and atomically with its switch handle
924 : : * being set below. This is safe now, as we
925 : : * will not return into it.
926 : : */
927 : : if (z_is_thread_queued(old_thread)) {
928 : : #ifdef CONFIG_SCHED_IPI_CASCADE
929 : : if ((new_thread->base.cpu_mask != -1) &&
930 : : (old_thread->base.cpu_mask != BIT(cpu_id))) {
931 : : flag_ipi(ipi_mask_create(old_thread));
932 : : }
933 : : #endif
934 : : runq_add(old_thread);
935 : : }
936 : : }
937 : : old_thread->switch_handle = interrupted;
938 : : ret = new_thread->switch_handle;
939 : : if (IS_ENABLED(CONFIG_SMP)) {
940 : : /* Active threads MUST have a null here */
941 : : new_thread->switch_handle = NULL;
942 : : }
943 : : }
944 : : signal_pending_ipi();
945 : : return ret;
946 : : #else
947 : : z_sched_usage_switch(_kernel.ready_q.cache);
948 : : arch_current_thread()->switch_handle = interrupted;
949 : : set_current(_kernel.ready_q.cache);
950 : : return arch_current_thread()->switch_handle;
951 : : #endif /* CONFIG_SMP */
952 : : }
953 : : #endif /* CONFIG_USE_SWITCH */
954 : :
955 : 0 : int z_unpend_all(_wait_q_t *wait_q)
956 : : {
957 : 0 : int need_sched = 0;
958 : 0 : struct k_thread *thread;
959 : :
960 [ # # ]: 0 : for (thread = z_waitq_head(wait_q); thread != NULL; thread = z_waitq_head(wait_q)) {
961 : 0 : z_unpend_thread(thread);
962 : 0 : z_ready_thread(thread);
963 : 0 : need_sched = 1;
964 : : }
965 : :
966 : 0 : return need_sched;
967 : : }
968 : :
969 : 1 : void init_ready_q(struct _ready_q *ready_q)
970 : : {
971 : 1 : _priq_run_init(&ready_q->runq);
972 : 1 : }
973 : :
974 : 1 : void z_sched_init(void)
975 : : {
976 : : #ifdef CONFIG_SCHED_CPU_MASK_PIN_ONLY
977 : : for (int i = 0; i < CONFIG_MP_MAX_NUM_CPUS; i++) {
978 : : init_ready_q(&_kernel.cpus[i].ready_q);
979 : : }
980 : : #else
981 : 1 : init_ready_q(&_kernel.ready_q);
982 : : #endif /* CONFIG_SCHED_CPU_MASK_PIN_ONLY */
983 : 1 : }
984 : :
985 : 0 : void z_impl_k_thread_priority_set(k_tid_t thread, int prio)
986 : : {
987 : : /*
988 : : * Use NULL, since we cannot know what the entry point is (we do not
989 : : * keep track of it) and idle cannot change its priority.
990 : : */
991 [ # # # # : 0 : Z_ASSERT_VALID_PRIO(prio, NULL);
# # ]
992 : :
993 : 0 : bool need_sched = z_thread_prio_set((struct k_thread *)thread, prio);
994 : :
995 [ # # ]: 0 : if ((need_sched) && (IS_ENABLED(CONFIG_SMP) ||
996 [ # # ]: 0 : (arch_current_thread()->base.sched_locked == 0U))) {
997 : 0 : z_reschedule_unlocked();
998 : : }
999 : 0 : }
1000 : :
1001 : : #ifdef CONFIG_USERSPACE
1002 : : static inline void z_vrfy_k_thread_priority_set(k_tid_t thread, int prio)
1003 : : {
1004 : : K_OOPS(K_SYSCALL_OBJ(thread, K_OBJ_THREAD));
1005 : : K_OOPS(K_SYSCALL_VERIFY_MSG(_is_valid_prio(prio, NULL),
1006 : : "invalid thread priority %d", prio));
1007 : : #ifndef CONFIG_USERSPACE_THREAD_MAY_RAISE_PRIORITY
1008 : : K_OOPS(K_SYSCALL_VERIFY_MSG((int8_t)prio >= thread->base.prio,
1009 : : "thread priority may only be downgraded (%d < %d)",
1010 : : prio, thread->base.prio));
1011 : : #endif /* CONFIG_USERSPACE_THREAD_MAY_RAISE_PRIORITY */
1012 : : z_impl_k_thread_priority_set(thread, prio);
1013 : : }
1014 : : #include <zephyr/syscalls/k_thread_priority_set_mrsh.c>
1015 : : #endif /* CONFIG_USERSPACE */
1016 : :
1017 : : #ifdef CONFIG_SCHED_DEADLINE
1018 : : void z_impl_k_thread_deadline_set(k_tid_t tid, int deadline)
1019 : : {
1020 : :
1021 : : deadline = CLAMP(deadline, 0, INT_MAX);
1022 : :
1023 : : struct k_thread *thread = tid;
1024 : : int32_t newdl = k_cycle_get_32() + deadline;
1025 : :
1026 : : /* The prio_deadline field changes the sorting order, so can't
1027 : : * change it while the thread is in the run queue (dlists
1028 : : * actually are benign as long as we requeue it before we
1029 : : * release the lock, but an rbtree will blow up if we break
1030 : : * sorting!)
1031 : : */
1032 : : K_SPINLOCK(&_sched_spinlock) {
1033 : : if (z_is_thread_queued(thread)) {
1034 : : dequeue_thread(thread);
1035 : : thread->base.prio_deadline = newdl;
1036 : : queue_thread(thread);
1037 : : } else {
1038 : : thread->base.prio_deadline = newdl;
1039 : : }
1040 : : }
1041 : : }
1042 : :
1043 : : #ifdef CONFIG_USERSPACE
1044 : : static inline void z_vrfy_k_thread_deadline_set(k_tid_t tid, int deadline)
1045 : : {
1046 : : struct k_thread *thread = tid;
1047 : :
1048 : : K_OOPS(K_SYSCALL_OBJ(thread, K_OBJ_THREAD));
1049 : : K_OOPS(K_SYSCALL_VERIFY_MSG(deadline > 0,
1050 : : "invalid thread deadline %d",
1051 : : (int)deadline));
1052 : :
1053 : : z_impl_k_thread_deadline_set((k_tid_t)thread, deadline);
1054 : : }
1055 : : #include <zephyr/syscalls/k_thread_deadline_set_mrsh.c>
1056 : : #endif /* CONFIG_USERSPACE */
1057 : : #endif /* CONFIG_SCHED_DEADLINE */
1058 : :
1059 : 0 : bool k_can_yield(void)
1060 : : {
1061 [ # # # # ]: 0 : return !(k_is_pre_kernel() || k_is_in_isr() ||
1062 [ # # ]: 0 : z_is_idle_thread_object(arch_current_thread()));
1063 : : }
1064 : :
1065 : 0 : void z_impl_k_yield(void)
1066 : : {
1067 [ # # ]: 0 : __ASSERT(!arch_is_in_isr(), "");
1068 : :
1069 : 0 : SYS_PORT_TRACING_FUNC(k_thread, yield);
1070 : :
1071 : 0 : k_spinlock_key_t key = k_spin_lock(&_sched_spinlock);
1072 : :
1073 : 0 : if (!IS_ENABLED(CONFIG_SMP) ||
1074 : : z_is_thread_queued(arch_current_thread())) {
1075 : 0 : dequeue_thread(arch_current_thread());
1076 : : }
1077 : 0 : queue_thread(arch_current_thread());
1078 : 0 : update_cache(1);
1079 : 0 : z_swap(&_sched_spinlock, key);
1080 : 0 : }
1081 : :
1082 : : #ifdef CONFIG_USERSPACE
1083 : : static inline void z_vrfy_k_yield(void)
1084 : : {
1085 : : z_impl_k_yield();
1086 : : }
1087 : : #include <zephyr/syscalls/k_yield_mrsh.c>
1088 : : #endif /* CONFIG_USERSPACE */
1089 : :
1090 : 0 : static int32_t z_tick_sleep(k_ticks_t ticks)
1091 : : {
1092 : 0 : uint32_t expected_wakeup_ticks;
1093 : :
1094 [ # # ]: 0 : __ASSERT(!arch_is_in_isr(), "");
1095 : :
1096 : 0 : LOG_DBG("thread %p for %lu ticks", arch_current_thread(), (unsigned long)ticks);
1097 : :
1098 : : /* wait of 0 ms is treated as a 'yield' */
1099 [ # # ]: 0 : if (ticks == 0) {
1100 : 0 : k_yield();
1101 : 0 : return 0;
1102 : : }
1103 : :
1104 [ # # ]: 0 : if (Z_TICK_ABS(ticks) <= 0) {
1105 : 0 : expected_wakeup_ticks = ticks + sys_clock_tick_get_32();
1106 : : } else {
1107 : 0 : expected_wakeup_ticks = Z_TICK_ABS(ticks);
1108 : : }
1109 : :
1110 : 0 : k_timeout_t timeout = Z_TIMEOUT_TICKS(ticks);
1111 : 0 : k_spinlock_key_t key = k_spin_lock(&_sched_spinlock);
1112 : :
1113 : : #if defined(CONFIG_TIMESLICING) && defined(CONFIG_SWAP_NONATOMIC)
1114 : : pending_current = arch_current_thread();
1115 : : #endif /* CONFIG_TIMESLICING && CONFIG_SWAP_NONATOMIC */
1116 : 0 : unready_thread(arch_current_thread());
1117 : 0 : z_add_thread_timeout(arch_current_thread(), timeout);
1118 : 0 : z_mark_thread_as_suspended(arch_current_thread());
1119 : :
1120 : 0 : (void)z_swap(&_sched_spinlock, key);
1121 : :
1122 [ # # ]: 0 : __ASSERT(!z_is_thread_state_set(arch_current_thread(), _THREAD_SUSPENDED), "");
1123 : :
1124 : 0 : ticks = (k_ticks_t)expected_wakeup_ticks - sys_clock_tick_get_32();
1125 [ # # ]: 0 : if (ticks > 0) {
1126 : 0 : return ticks;
1127 : : }
1128 : :
1129 : : return 0;
1130 : : }
1131 : :
1132 : 0 : int32_t z_impl_k_sleep(k_timeout_t timeout)
1133 : : {
1134 : 0 : k_ticks_t ticks;
1135 : :
1136 [ # # ]: 0 : __ASSERT(!arch_is_in_isr(), "");
1137 : :
1138 : 0 : SYS_PORT_TRACING_FUNC_ENTER(k_thread, sleep, timeout);
1139 : :
1140 : : /* in case of K_FOREVER, we suspend */
1141 [ # # ]: 0 : if (K_TIMEOUT_EQ(timeout, K_FOREVER)) {
1142 : :
1143 : 0 : k_thread_suspend(arch_current_thread());
1144 : 0 : SYS_PORT_TRACING_FUNC_EXIT(k_thread, sleep, timeout, (int32_t) K_TICKS_FOREVER);
1145 : :
1146 : 0 : return (int32_t) K_TICKS_FOREVER;
1147 : : }
1148 : :
1149 : 0 : ticks = timeout.ticks;
1150 : :
1151 : 0 : ticks = z_tick_sleep(ticks);
1152 : :
1153 : 0 : int32_t ret = k_ticks_to_ms_ceil64(ticks);
1154 : :
1155 : 0 : SYS_PORT_TRACING_FUNC_EXIT(k_thread, sleep, timeout, ret);
1156 : :
1157 : 0 : return ret;
1158 : : }
1159 : :
1160 : : #ifdef CONFIG_USERSPACE
1161 : : static inline int32_t z_vrfy_k_sleep(k_timeout_t timeout)
1162 : : {
1163 : : return z_impl_k_sleep(timeout);
1164 : : }
1165 : : #include <zephyr/syscalls/k_sleep_mrsh.c>
1166 : : #endif /* CONFIG_USERSPACE */
1167 : :
1168 : 0 : int32_t z_impl_k_usleep(int32_t us)
1169 : : {
1170 : 0 : int32_t ticks;
1171 : :
1172 : 0 : SYS_PORT_TRACING_FUNC_ENTER(k_thread, usleep, us);
1173 : :
1174 : 0 : ticks = k_us_to_ticks_ceil64(us);
1175 : 0 : ticks = z_tick_sleep(ticks);
1176 : :
1177 : 0 : int32_t ret = k_ticks_to_us_ceil64(ticks);
1178 : :
1179 : 0 : SYS_PORT_TRACING_FUNC_EXIT(k_thread, usleep, us, ret);
1180 : :
1181 : 0 : return ret;
1182 : : }
1183 : :
1184 : : #ifdef CONFIG_USERSPACE
1185 : : static inline int32_t z_vrfy_k_usleep(int32_t us)
1186 : : {
1187 : : return z_impl_k_usleep(us);
1188 : : }
1189 : : #include <zephyr/syscalls/k_usleep_mrsh.c>
1190 : : #endif /* CONFIG_USERSPACE */
1191 : :
1192 : 0 : void z_impl_k_wakeup(k_tid_t thread)
1193 : : {
1194 : 0 : SYS_PORT_TRACING_OBJ_FUNC(k_thread, wakeup, thread);
1195 : :
1196 [ # # ]: 0 : if (z_is_thread_pending(thread)) {
1197 : 0 : return;
1198 : : }
1199 : :
1200 [ # # ]: 0 : if (z_abort_thread_timeout(thread) < 0) {
1201 : : /* Might have just been sleeping forever */
1202 [ # # ]: 0 : if (thread->base.thread_state != _THREAD_SUSPENDED) {
1203 : : return;
1204 : : }
1205 : : }
1206 : :
1207 : 0 : k_spinlock_key_t key = k_spin_lock(&_sched_spinlock);
1208 : :
1209 : 0 : z_mark_thread_as_not_suspended(thread);
1210 : :
1211 [ # # ]: 0 : if (thread_active_elsewhere(thread) == NULL) {
1212 : 0 : ready_thread(thread);
1213 : : }
1214 : :
1215 [ # # ]: 0 : if (arch_is_in_isr()) {
1216 : 0 : k_spin_unlock(&_sched_spinlock, key);
1217 : : } else {
1218 : 0 : z_reschedule(&_sched_spinlock, key);
1219 : : }
1220 : : }
1221 : :
1222 : : #ifdef CONFIG_USERSPACE
1223 : : static inline void z_vrfy_k_wakeup(k_tid_t thread)
1224 : : {
1225 : : K_OOPS(K_SYSCALL_OBJ(thread, K_OBJ_THREAD));
1226 : : z_impl_k_wakeup(thread);
1227 : : }
1228 : : #include <zephyr/syscalls/k_wakeup_mrsh.c>
1229 : : #endif /* CONFIG_USERSPACE */
1230 : :
1231 : 46 : k_tid_t z_impl_k_sched_current_thread_query(void)
1232 : : {
1233 : 46 : return arch_current_thread();
1234 : : }
1235 : :
1236 : : #ifdef CONFIG_USERSPACE
1237 : : static inline k_tid_t z_vrfy_k_sched_current_thread_query(void)
1238 : : {
1239 : : return z_impl_k_sched_current_thread_query();
1240 : : }
1241 : : #include <zephyr/syscalls/k_sched_current_thread_query_mrsh.c>
1242 : : #endif /* CONFIG_USERSPACE */
1243 : :
1244 : 46 : static inline void unpend_all(_wait_q_t *wait_q)
1245 : : {
1246 : 46 : struct k_thread *thread;
1247 : :
1248 [ + + ]: 52 : for (thread = z_waitq_head(wait_q); thread != NULL; thread = z_waitq_head(wait_q)) {
1249 : 6 : unpend_thread_no_timeout(thread);
1250 : 6 : (void)z_abort_thread_timeout(thread);
1251 : 6 : arch_thread_return_value_set(thread, 0);
1252 : 6 : ready_thread(thread);
1253 : : }
1254 : 46 : }
1255 : :
1256 : : #ifdef CONFIG_THREAD_ABORT_HOOK
1257 : : extern void thread_abort_hook(struct k_thread *thread);
1258 : : #endif /* CONFIG_THREAD_ABORT_HOOK */
1259 : :
1260 : : /**
1261 : : * @brief Dequeues the specified thread
1262 : : *
1263 : : * Dequeues the specified thread and move it into the specified new state.
1264 : : *
1265 : : * @param thread Identify the thread to halt
1266 : : * @param new_state New thread state (_THREAD_DEAD or _THREAD_SUSPENDED)
1267 : : */
1268 : 46 : static void halt_thread(struct k_thread *thread, uint8_t new_state)
1269 : : {
1270 : 46 : bool dummify = false;
1271 : :
1272 : : /* We hold the lock, and the thread is known not to be running
1273 : : * anywhere.
1274 : : */
1275 [ + - ]: 46 : if ((thread->base.thread_state & new_state) == 0U) {
1276 : 46 : thread->base.thread_state |= new_state;
1277 [ + - ]: 46 : if (z_is_thread_queued(thread)) {
1278 : 46 : dequeue_thread(thread);
1279 : : }
1280 : :
1281 [ + - ]: 46 : if (new_state == _THREAD_DEAD) {
1282 [ - + ]: 46 : if (thread->base.pended_on != NULL) {
1283 : 0 : unpend_thread_no_timeout(thread);
1284 : : }
1285 : 46 : (void)z_abort_thread_timeout(thread);
1286 : 46 : unpend_all(&thread->join_queue);
1287 : :
1288 : : /* Edge case: aborting arch_current_thread() from within an
1289 : : * ISR that preempted it requires clearing the
1290 : : * arch_current_thread() pointer so the upcoming context
1291 : : * switch doesn't clobber the now-freed
1292 : : * memory
1293 : : */
1294 : 46 : if (thread == arch_current_thread() && arch_is_in_isr()) {
1295 : 46 : dummify = true;
1296 : : }
1297 : : }
1298 : : #ifdef CONFIG_SMP
1299 : : unpend_all(&thread->halt_queue);
1300 : : #endif /* CONFIG_SMP */
1301 : 46 : update_cache(1);
1302 : :
1303 [ - + ]: 46 : if (new_state == _THREAD_SUSPENDED) {
1304 : 0 : clear_halting(thread);
1305 : 0 : return;
1306 : : }
1307 : :
1308 : : #if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING)
1309 : : arch_float_disable(thread);
1310 : : #endif /* CONFIG_FPU && CONFIG_FPU_SHARING */
1311 : :
1312 : 46 : SYS_PORT_TRACING_FUNC(k_thread, sched_abort, thread);
1313 : :
1314 : 46 : z_thread_monitor_exit(thread);
1315 : : #ifdef CONFIG_THREAD_ABORT_HOOK
1316 : : thread_abort_hook(thread);
1317 : : #endif /* CONFIG_THREAD_ABORT_HOOK */
1318 : :
1319 : : #ifdef CONFIG_OBJ_CORE_THREAD
1320 : : #ifdef CONFIG_OBJ_CORE_STATS_THREAD
1321 : : k_obj_core_stats_deregister(K_OBJ_CORE(thread));
1322 : : #endif /* CONFIG_OBJ_CORE_STATS_THREAD */
1323 : : k_obj_core_unlink(K_OBJ_CORE(thread));
1324 : : #endif /* CONFIG_OBJ_CORE_THREAD */
1325 : :
1326 : : #ifdef CONFIG_USERSPACE
1327 : : z_mem_domain_exit_thread(thread);
1328 : : k_thread_perms_all_clear(thread);
1329 : : k_object_uninit(thread->stack_obj);
1330 : : k_object_uninit(thread);
1331 : : #endif /* CONFIG_USERSPACE */
1332 : :
1333 : : #ifdef CONFIG_THREAD_ABORT_NEED_CLEANUP
1334 : : k_thread_abort_cleanup(thread);
1335 : : #endif /* CONFIG_THREAD_ABORT_NEED_CLEANUP */
1336 : :
1337 : : /* Do this "set arch_current_thread() to dummy" step last so that
1338 : : * subsystems above can rely on arch_current_thread() being
1339 : : * unchanged. Disabled for posix as that arch
1340 : : * continues to use the arch_current_thread() pointer in its swap
1341 : : * code. Note that we must leave a non-null switch
1342 : : * handle for any threads spinning in join() (this can
1343 : : * never be used, as our thread is flagged dead, but
1344 : : * it must not be NULL otherwise join can deadlock).
1345 : : */
1346 : 46 : if (dummify && !IS_ENABLED(CONFIG_ARCH_POSIX)) {
1347 : : #ifdef CONFIG_USE_SWITCH
1348 : : arch_current_thread()->switch_handle = arch_current_thread();
1349 : : #endif
1350 : : z_dummy_thread_init(&_thread_dummy);
1351 : :
1352 : : }
1353 : :
1354 : : /* Finally update the halting thread state, on which
1355 : : * other CPUs might be spinning (see
1356 : : * thread_halt_spin()).
1357 : : */
1358 : 46 : clear_halting(thread);
1359 : : }
1360 : : }
1361 : :
1362 : 88 : void z_thread_abort(struct k_thread *thread)
1363 : : {
1364 : 88 : k_spinlock_key_t key = k_spin_lock(&_sched_spinlock);
1365 : :
1366 [ - + ]: 88 : if (z_is_thread_essential(thread)) {
1367 : 0 : k_spin_unlock(&_sched_spinlock, key);
1368 : 0 : __ASSERT(false, "aborting essential thread %p", thread);
1369 : : k_panic();
1370 : 42 : return;
1371 : : }
1372 : :
1373 [ + + ]: 88 : if ((thread->base.thread_state & _THREAD_DEAD) != 0U) {
1374 : 42 : k_spin_unlock(&_sched_spinlock, key);
1375 : 42 : return;
1376 : : }
1377 : :
1378 : 46 : z_thread_halt(thread, key, true);
1379 : : }
1380 : :
1381 : : #if !defined(CONFIG_ARCH_HAS_THREAD_ABORT)
1382 : : void z_impl_k_thread_abort(k_tid_t thread)
1383 : : {
1384 : : SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_thread, abort, thread);
1385 : :
1386 : : z_thread_abort(thread);
1387 : :
1388 : : __ASSERT_NO_MSG((thread->base.thread_state & _THREAD_DEAD) != 0);
1389 : :
1390 : : SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_thread, abort, thread);
1391 : : }
1392 : : #endif /* !CONFIG_ARCH_HAS_THREAD_ABORT */
1393 : :
1394 : 46 : int z_impl_k_thread_join(struct k_thread *thread, k_timeout_t timeout)
1395 : : {
1396 : 46 : k_spinlock_key_t key = k_spin_lock(&_sched_spinlock);
1397 : 46 : int ret;
1398 : :
1399 : 46 : SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_thread, join, thread, timeout);
1400 : :
1401 [ + + ]: 46 : if ((thread->base.thread_state & _THREAD_DEAD) != 0U) {
1402 : : z_sched_switch_spin(thread);
1403 : 40 : ret = 0;
1404 [ + - ]: 6 : } else if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {
1405 : : ret = -EBUSY;
1406 [ + - ]: 6 : } else if ((thread == arch_current_thread()) ||
1407 [ + - ]: 6 : (thread->base.pended_on == &arch_current_thread()->join_queue)) {
1408 : : ret = -EDEADLK;
1409 : : } else {
1410 [ - + ]: 6 : __ASSERT(!arch_is_in_isr(), "cannot join in ISR");
1411 : 6 : add_to_waitq_locked(arch_current_thread(), &thread->join_queue);
1412 : 6 : add_thread_timeout(arch_current_thread(), timeout);
1413 : :
1414 : 6 : SYS_PORT_TRACING_OBJ_FUNC_BLOCKING(k_thread, join, thread, timeout);
1415 : 6 : ret = z_swap(&_sched_spinlock, key);
1416 : 6 : SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_thread, join, thread, timeout, ret);
1417 : :
1418 : 6 : return ret;
1419 : : }
1420 : :
1421 : 40 : SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_thread, join, thread, timeout, ret);
1422 : :
1423 : 40 : k_spin_unlock(&_sched_spinlock, key);
1424 : 40 : return ret;
1425 : : }
1426 : :
1427 : : #ifdef CONFIG_USERSPACE
1428 : : /* Special case: don't oops if the thread is uninitialized. This is because
1429 : : * the initialization bit does double-duty for thread objects; if false, means
1430 : : * the thread object is truly uninitialized, or the thread ran and exited for
1431 : : * some reason.
1432 : : *
1433 : : * Return true in this case indicating we should just do nothing and return
1434 : : * success to the caller.
1435 : : */
1436 : : static bool thread_obj_validate(struct k_thread *thread)
1437 : : {
1438 : : struct k_object *ko = k_object_find(thread);
1439 : : int ret = k_object_validate(ko, K_OBJ_THREAD, _OBJ_INIT_TRUE);
1440 : :
1441 : : switch (ret) {
1442 : : case 0:
1443 : : return false;
1444 : : case -EINVAL:
1445 : : return true;
1446 : : default:
1447 : : #ifdef CONFIG_LOG
1448 : : k_object_dump_error(ret, thread, ko, K_OBJ_THREAD);
1449 : : #endif /* CONFIG_LOG */
1450 : : K_OOPS(K_SYSCALL_VERIFY_MSG(ret, "access denied"));
1451 : : }
1452 : : CODE_UNREACHABLE; /* LCOV_EXCL_LINE */
1453 : : }
1454 : :
1455 : : static inline int z_vrfy_k_thread_join(struct k_thread *thread,
1456 : : k_timeout_t timeout)
1457 : : {
1458 : : if (thread_obj_validate(thread)) {
1459 : : return 0;
1460 : : }
1461 : :
1462 : : return z_impl_k_thread_join(thread, timeout);
1463 : : }
1464 : : #include <zephyr/syscalls/k_thread_join_mrsh.c>
1465 : :
1466 : : static inline void z_vrfy_k_thread_abort(k_tid_t thread)
1467 : : {
1468 : : if (thread_obj_validate(thread)) {
1469 : : return;
1470 : : }
1471 : :
1472 : : K_OOPS(K_SYSCALL_VERIFY_MSG(!z_is_thread_essential(thread),
1473 : : "aborting essential thread %p", thread));
1474 : :
1475 : : z_impl_k_thread_abort((struct k_thread *)thread);
1476 : : }
1477 : : #include <zephyr/syscalls/k_thread_abort_mrsh.c>
1478 : : #endif /* CONFIG_USERSPACE */
1479 : :
1480 : : /*
1481 : : * future scheduler.h API implementations
1482 : : */
1483 : 0 : bool z_sched_wake(_wait_q_t *wait_q, int swap_retval, void *swap_data)
1484 : : {
1485 : 0 : struct k_thread *thread;
1486 : 0 : bool ret = false;
1487 : :
1488 [ # # ]: 0 : K_SPINLOCK(&_sched_spinlock) {
1489 : 0 : thread = _priq_wait_best(&wait_q->waitq);
1490 : :
1491 [ # # ]: 0 : if (thread != NULL) {
1492 : 0 : z_thread_return_value_set_with_data(thread,
1493 : : swap_retval,
1494 : : swap_data);
1495 : 0 : unpend_thread_no_timeout(thread);
1496 : 0 : (void)z_abort_thread_timeout(thread);
1497 : 0 : ready_thread(thread);
1498 : 0 : ret = true;
1499 : : }
1500 : : }
1501 : :
1502 : 0 : return ret;
1503 : : }
1504 : :
1505 : 0 : int z_sched_wait(struct k_spinlock *lock, k_spinlock_key_t key,
1506 : : _wait_q_t *wait_q, k_timeout_t timeout, void **data)
1507 : : {
1508 : 0 : int ret = z_pend_curr(lock, key, wait_q, timeout);
1509 : :
1510 [ # # ]: 0 : if (data != NULL) {
1511 : 0 : *data = arch_current_thread()->base.swap_data;
1512 : : }
1513 : 0 : return ret;
1514 : : }
1515 : :
1516 : 0 : int z_sched_waitq_walk(_wait_q_t *wait_q,
1517 : : int (*func)(struct k_thread *, void *), void *data)
1518 : : {
1519 : 0 : struct k_thread *thread;
1520 : 0 : int status = 0;
1521 : :
1522 [ # # ]: 0 : K_SPINLOCK(&_sched_spinlock) {
1523 [ # # # # : 0 : _WAIT_Q_FOR_EACH(wait_q, thread) {
# # ]
1524 : :
1525 : : /*
1526 : : * Invoke the callback function on each waiting thread
1527 : : * for as long as there are both waiting threads AND
1528 : : * it returns 0.
1529 : : */
1530 : :
1531 : 0 : status = func(thread, data);
1532 [ # # ]: 0 : if (status != 0) {
1533 : : break;
1534 : : }
1535 : : }
1536 : : }
1537 : :
1538 : 0 : return status;
1539 : : }
1540 : :
1541 : : /* This routine exists for benchmarking purposes. It is not used in
1542 : : * general production code.
1543 : : */
1544 : 0 : void z_unready_thread(struct k_thread *thread)
1545 : : {
1546 [ # # ]: 0 : K_SPINLOCK(&_sched_spinlock) {
1547 : 0 : unready_thread(thread);
1548 : : }
1549 : 0 : }
|