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