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 : 0 : void z_impl_k_thread_resume(k_tid_t thread)
534 : : {
535 : 0 : SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_thread, resume, thread);
536 : :
537 : 0 : k_spinlock_key_t key = k_spin_lock(&_sched_spinlock);
538 : :
539 : : /* Do not try to resume a thread that was not suspended */
540 [ # # ]: 0 : if (unlikely(!z_is_thread_suspended(thread))) {
541 : 0 : k_spin_unlock(&_sched_spinlock, key);
542 : 0 : return;
543 : : }
544 : :
545 : 0 : z_mark_thread_as_not_suspended(thread);
546 : 0 : ready_thread(thread);
547 : :
548 : 0 : z_reschedule(&_sched_spinlock, key);
549 : :
550 : 0 : SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_thread, resume, thread);
551 : : }
552 : :
553 : : #ifdef CONFIG_USERSPACE
554 : : static inline void z_vrfy_k_thread_resume(k_tid_t thread)
555 : : {
556 : : K_OOPS(K_SYSCALL_OBJ(thread, K_OBJ_THREAD));
557 : : z_impl_k_thread_resume(thread);
558 : : }
559 : : #include <zephyr/syscalls/k_thread_resume_mrsh.c>
560 : : #endif /* CONFIG_USERSPACE */
561 : :
562 : 10 : static void unready_thread(struct k_thread *thread)
563 : : {
564 [ + - ]: 10 : if (z_is_thread_queued(thread)) {
565 : 10 : dequeue_thread(thread);
566 : : }
567 : 10 : update_cache(thread == _current);
568 : 10 : }
569 : :
570 : : /* _sched_spinlock must be held */
571 : : #ifdef IAR_SUPPRESS_ALWAYS_INLINE_WARNING_FLAG
572 : : TOOLCHAIN_DISABLE_WARNING(TOOLCHAIN_WARNING_ALWAYS_INLINE)
573 : : #endif
574 : 10 : static void add_to_waitq_locked(struct k_thread *thread, _wait_q_t *wait_q)
575 : : {
576 : 10 : unready_thread(thread);
577 : 10 : z_mark_thread_as_pending(thread);
578 : :
579 : 10 : SYS_PORT_TRACING_FUNC(k_thread, sched_pend, thread);
580 : :
581 [ + - ]: 10 : if (wait_q != NULL) {
582 : 10 : thread->base.pended_on = wait_q;
583 : 10 : _priq_wait_add(&wait_q->waitq, thread);
584 : : }
585 : 10 : }
586 : : #ifdef IAR_SUPPRESS_ALWAYS_INLINE_WARNING_FLAG
587 : : TOOLCHAIN_ENABLE_WARNING(TOOLCHAIN_WARNING_ALWAYS_INLINE)
588 : : #endif
589 : :
590 : 10 : static void add_thread_timeout(struct k_thread *thread, k_timeout_t timeout)
591 : : {
592 [ - + ]: 10 : if (!K_TIMEOUT_EQ(timeout, K_FOREVER)) {
593 : 0 : z_add_thread_timeout(thread, timeout);
594 : : }
595 : 10 : }
596 : :
597 : 4 : static void pend_locked(struct k_thread *thread, _wait_q_t *wait_q,
598 : : k_timeout_t timeout)
599 : : {
600 : : #ifdef CONFIG_KERNEL_COHERENCE
601 : : __ASSERT_NO_MSG(wait_q == NULL || sys_cache_is_mem_coherent(wait_q));
602 : : #endif /* CONFIG_KERNEL_COHERENCE */
603 : 4 : add_to_waitq_locked(thread, wait_q);
604 : 4 : add_thread_timeout(thread, timeout);
605 : 4 : }
606 : :
607 : 0 : void z_pend_thread(struct k_thread *thread, _wait_q_t *wait_q,
608 : : k_timeout_t timeout)
609 : : {
610 [ # # # # ]: 0 : __ASSERT_NO_MSG(thread == _current || is_thread_dummy(thread));
611 [ # # ]: 0 : K_SPINLOCK(&_sched_spinlock) {
612 : 0 : pend_locked(thread, wait_q, timeout);
613 : : }
614 : 0 : }
615 : :
616 : 0 : void z_unpend_thread_no_timeout(struct k_thread *thread)
617 : : {
618 [ # # ]: 0 : K_SPINLOCK(&_sched_spinlock) {
619 [ # # ]: 0 : if (thread->base.pended_on != NULL) {
620 : 0 : unpend_thread_no_timeout(thread);
621 : : }
622 : : }
623 : 0 : }
624 : :
625 : 0 : void z_sched_wake_thread(struct k_thread *thread, bool is_timeout)
626 : : {
627 [ # # ]: 0 : K_SPINLOCK(&_sched_spinlock) {
628 : 0 : bool killed = (thread->base.thread_state &
629 : : (_THREAD_DEAD | _THREAD_ABORTING));
630 : :
631 : : #ifdef CONFIG_EVENTS
632 : : bool do_nothing = thread->no_wake_on_timeout && is_timeout;
633 : :
634 : : thread->no_wake_on_timeout = false;
635 : :
636 : : if (do_nothing) {
637 : : continue;
638 : : }
639 : : #endif /* CONFIG_EVENTS */
640 : :
641 [ # # ]: 0 : if (!killed) {
642 : : /* The thread is not being killed */
643 [ # # ]: 0 : if (thread->base.pended_on != NULL) {
644 : 0 : unpend_thread_no_timeout(thread);
645 : : }
646 : 0 : z_mark_thread_as_not_sleeping(thread);
647 : 0 : ready_thread(thread);
648 : : }
649 : : }
650 : :
651 : 0 : }
652 : :
653 : : #ifdef CONFIG_SYS_CLOCK_EXISTS
654 : : /* Timeout handler for *_thread_timeout() APIs */
655 : 0 : void z_thread_timeout(struct _timeout *timeout)
656 : : {
657 : 0 : struct k_thread *thread = CONTAINER_OF(timeout,
658 : : struct k_thread, base.timeout);
659 : :
660 : 0 : z_sched_wake_thread(thread, true);
661 : 0 : }
662 : : #endif /* CONFIG_SYS_CLOCK_EXISTS */
663 : :
664 : 4 : int z_pend_curr(struct k_spinlock *lock, k_spinlock_key_t key,
665 : : _wait_q_t *wait_q, k_timeout_t timeout)
666 : : {
667 : : #if defined(CONFIG_TIMESLICING) && defined(CONFIG_SWAP_NONATOMIC)
668 : : pending_current = _current;
669 : : #endif /* CONFIG_TIMESLICING && CONFIG_SWAP_NONATOMIC */
670 [ - + ]: 4 : __ASSERT_NO_MSG(sizeof(_sched_spinlock) == 0 || lock != &_sched_spinlock);
671 : :
672 : : /* We do a "lock swap" prior to calling z_swap(), such that
673 : : * the caller's lock gets released as desired. But we ensure
674 : : * that we hold the scheduler lock and leave local interrupts
675 : : * masked until we reach the context switch. z_swap() itself
676 : : * has similar code; the duplication is because it's a legacy
677 : : * API that doesn't expect to be called with scheduler lock
678 : : * held.
679 : : */
680 : 4 : (void) k_spin_lock(&_sched_spinlock);
681 : 4 : pend_locked(_current, wait_q, timeout);
682 : 4 : k_spin_release(lock);
683 : 4 : return z_swap(&_sched_spinlock, key);
684 : : }
685 : :
686 : 0 : struct k_thread *z_unpend1_no_timeout(_wait_q_t *wait_q)
687 : : {
688 : 0 : struct k_thread *thread = NULL;
689 : :
690 [ # # ]: 0 : K_SPINLOCK(&_sched_spinlock) {
691 : 0 : thread = _priq_wait_best(&wait_q->waitq);
692 : :
693 [ # # ]: 0 : if (thread != NULL) {
694 : 0 : unpend_thread_no_timeout(thread);
695 : : }
696 : : }
697 : :
698 : 0 : return thread;
699 : : }
700 : :
701 : 0 : void z_unpend_thread(struct k_thread *thread)
702 : : {
703 : 0 : z_unpend_thread_no_timeout(thread);
704 : 0 : z_abort_thread_timeout(thread);
705 : 0 : }
706 : :
707 : : /* Priority set utility that does no rescheduling, it just changes the
708 : : * run queue state, returning true if a reschedule is needed later.
709 : : */
710 : : #ifdef IAR_SUPPRESS_ALWAYS_INLINE_WARNING_FLAG
711 : : TOOLCHAIN_DISABLE_WARNING(TOOLCHAIN_WARNING_ALWAYS_INLINE)
712 : : #endif
713 : 0 : bool z_thread_prio_set(struct k_thread *thread, int prio)
714 : : {
715 : 0 : bool need_sched = 0;
716 : 0 : int old_prio = thread->base.prio;
717 : :
718 [ # # ]: 0 : K_SPINLOCK(&_sched_spinlock) {
719 : 0 : need_sched = z_is_thread_ready(thread);
720 : :
721 [ # # ]: 0 : if (need_sched) {
722 : 0 : if (!IS_ENABLED(CONFIG_SMP) || z_is_thread_queued(thread)) {
723 : 0 : dequeue_thread(thread);
724 : 0 : thread->base.prio = prio;
725 : 0 : queue_thread(thread);
726 : :
727 : 0 : if (old_prio > prio) {
728 : 0 : flag_ipi(ipi_mask_create(thread));
729 : : }
730 : : } else {
731 : : /*
732 : : * This is a running thread on SMP. Update its
733 : : * priority, but do not requeue it. An IPI is
734 : : * needed if the priority is both being lowered
735 : : * and it is running on another CPU.
736 : : */
737 : :
738 : : thread->base.prio = prio;
739 : :
740 : : struct _cpu *cpu;
741 : :
742 : : cpu = thread_active_elsewhere(thread);
743 : : if ((cpu != NULL) && (old_prio < prio)) {
744 : 0 : flag_ipi(IPI_CPU_MASK(cpu->id));
745 : : }
746 : : }
747 : :
748 : 0 : update_cache(1);
749 [ # # ]: 0 : } else if (z_is_thread_pending(thread)) {
750 : : /* Thread is pending, remove it from the waitq
751 : : * and reinsert it with the new priority to avoid
752 : : * violating waitq ordering and rb assumptions.
753 : : */
754 : 0 : _wait_q_t *wait_q = pended_on_thread(thread);
755 : :
756 : 0 : _priq_wait_remove(&wait_q->waitq, thread);
757 : 0 : thread->base.prio = prio;
758 : 0 : _priq_wait_add(&wait_q->waitq, thread);
759 : : } else {
760 : 0 : thread->base.prio = prio;
761 : : }
762 : : }
763 : :
764 : 0 : SYS_PORT_TRACING_OBJ_FUNC(k_thread, sched_priority_set, thread, prio);
765 : :
766 : 0 : return need_sched;
767 : : }
768 : : #ifdef IAR_SUPPRESS_ALWAYS_INLINE_WARNING_FLAG
769 : : TOOLCHAIN_ENABLE_WARNING(TOOLCHAIN_WARNING_ALWAYS_INLINE)
770 : : #endif
771 : :
772 : 93 : static inline bool resched(uint32_t key)
773 : : {
774 : : #ifdef CONFIG_SMP
775 : : _current_cpu->swap_ok = 0;
776 : : #endif /* CONFIG_SMP */
777 : :
778 [ + - - + ]: 93 : return arch_irq_unlocked(key) && !arch_is_in_isr();
779 : : }
780 : :
781 : : /*
782 : : * Check if the next ready thread is the same as the current thread
783 : : * and save the trip if true.
784 : : */
785 : 93 : static inline bool need_swap(void)
786 : : {
787 : : /* the SMP case will be handled in C based z_swap() */
788 : : #ifdef CONFIG_SMP
789 : : return true;
790 : : #else
791 : 93 : struct k_thread *new_thread;
792 : :
793 : : /* Check if the next ready thread is the same as the current thread */
794 : 93 : new_thread = _kernel.ready_q.cache;
795 : 93 : return new_thread != _current;
796 : : #endif /* CONFIG_SMP */
797 : : }
798 : :
799 : 50 : void z_reschedule(struct k_spinlock *lock, k_spinlock_key_t key)
800 : : {
801 [ + - + + ]: 50 : if (resched(key.key) && need_swap()) {
802 : 42 : z_swap(lock, key);
803 : : } else {
804 : 8 : k_spin_unlock(lock, key);
805 : 50 : signal_pending_ipi();
806 : : }
807 : 50 : }
808 : :
809 : 43 : void z_reschedule_irqlock(uint32_t key)
810 : : {
811 [ + - - + ]: 43 : if (resched(key) && need_swap()) {
812 : 0 : z_swap_irqlock(key);
813 : : } else {
814 : 43 : irq_unlock(key);
815 : 43 : signal_pending_ipi();
816 : : }
817 : 43 : }
818 : :
819 : 1 : void k_sched_lock(void)
820 : : {
821 : 1 : LOG_DBG("scheduler locked (%p:%d)",
822 : : _current, _current->base.sched_locked);
823 : :
824 [ + + ]: 2 : K_SPINLOCK(&_sched_spinlock) {
825 : 1 : SYS_PORT_TRACING_FUNC(k_thread, sched_lock);
826 : :
827 [ - + ]: 1 : __ASSERT(!arch_is_in_isr(), "");
828 [ - + ]: 1 : __ASSERT(_current->base.sched_locked != 1U, "");
829 : :
830 : 1 : --_current->base.sched_locked;
831 : :
832 : 1 : compiler_barrier();
833 : : }
834 : 1 : }
835 : :
836 : 1 : void k_sched_unlock(void)
837 : : {
838 [ + + ]: 2 : K_SPINLOCK(&_sched_spinlock) {
839 [ - + ]: 1 : __ASSERT(_current->base.sched_locked != 0U, "");
840 [ - + ]: 1 : __ASSERT(!arch_is_in_isr(), "");
841 : :
842 : 1 : ++_current->base.sched_locked;
843 : 1 : update_cache(0);
844 : : }
845 : :
846 : 1 : LOG_DBG("scheduler unlocked (%p:%d)",
847 : : _current, _current->base.sched_locked);
848 : :
849 : 1 : SYS_PORT_TRACING_FUNC(k_thread, sched_unlock);
850 : :
851 : 1 : z_reschedule_unlocked();
852 : 1 : }
853 : :
854 : 0 : struct k_thread *z_swap_next_thread(void)
855 : : {
856 : : #ifdef CONFIG_SMP
857 : : struct k_thread *ret = next_up();
858 : :
859 : : if (ret == _current) {
860 : : /* When not swapping, have to signal IPIs here. In
861 : : * the context switch case it must happen later, after
862 : : * _current gets requeued.
863 : : */
864 : : signal_pending_ipi();
865 : : }
866 : : return ret;
867 : : #else
868 : 0 : return _kernel.ready_q.cache;
869 : : #endif /* CONFIG_SMP */
870 : : }
871 : :
872 : : #ifdef CONFIG_USE_SWITCH
873 : : /* Just a wrapper around z_current_thread_set(xxx) with tracing */
874 : : static inline void set_current(struct k_thread *new_thread)
875 : : {
876 : : /* If the new thread is the same as the current thread, we
877 : : * don't need to do anything.
878 : : */
879 : : if (IS_ENABLED(CONFIG_INSTRUMENT_THREAD_SWITCHING) && new_thread != _current) {
880 : : z_thread_mark_switched_out();
881 : : }
882 : : z_current_thread_set(new_thread);
883 : : }
884 : :
885 : : /**
886 : : * @brief Determine next thread to execute upon completion of an interrupt
887 : : *
888 : : * Thread preemption is performed by context switching after the completion
889 : : * of a non-recursed interrupt. This function determines which thread to
890 : : * switch to if any. This function accepts as @p interrupted either:
891 : : *
892 : : * - The handle for the interrupted thread in which case the thread's context
893 : : * must already be fully saved and ready to be picked up by a different CPU.
894 : : *
895 : : * - NULL if more work is required to fully save the thread's state after
896 : : * it is known that a new thread is to be scheduled. It is up to the caller
897 : : * to store the handle resulting from the thread that is being switched out
898 : : * in that thread's "switch_handle" field after its
899 : : * context has fully been saved, following the same requirements as with
900 : : * the @ref arch_switch() function.
901 : : *
902 : : * If a new thread needs to be scheduled then its handle is returned.
903 : : * Otherwise the same value provided as @p interrupted is returned back.
904 : : * Those handles are the same opaque types used by the @ref arch_switch()
905 : : * function.
906 : : *
907 : : * @warning
908 : : * The _current value may have changed after this call and not refer
909 : : * to the interrupted thread anymore. It might be necessary to make a local
910 : : * copy before calling this function.
911 : : *
912 : : * @param interrupted Handle for the thread that was interrupted or NULL.
913 : : * @retval Handle for the next thread to execute, or @p interrupted when
914 : : * no new thread is to be scheduled.
915 : : */
916 : : void *z_get_next_switch_handle(void *interrupted)
917 : : {
918 : : z_check_stack_sentinel();
919 : :
920 : : #ifdef CONFIG_SMP
921 : : void *ret = NULL;
922 : :
923 : : K_SPINLOCK(&_sched_spinlock) {
924 : : struct k_thread *old_thread = _current, *new_thread;
925 : :
926 : : __ASSERT(old_thread->switch_handle == NULL || is_thread_dummy(old_thread),
927 : : "old thread handle should be null.");
928 : :
929 : : new_thread = next_up();
930 : :
931 : : z_sched_usage_switch(new_thread);
932 : :
933 : : if (old_thread != new_thread) {
934 : : uint8_t cpu_id;
935 : :
936 : : z_sched_switch_spin(new_thread);
937 : : arch_cohere_stacks(old_thread, interrupted, new_thread);
938 : :
939 : : _current_cpu->swap_ok = 0;
940 : : cpu_id = arch_curr_cpu()->id;
941 : : new_thread->base.cpu = cpu_id;
942 : : set_current(new_thread);
943 : :
944 : : #ifdef CONFIG_TIMESLICING
945 : : z_reset_time_slice(new_thread);
946 : : #endif /* CONFIG_TIMESLICING */
947 : :
948 : : #ifdef CONFIG_SPIN_VALIDATE
949 : : /* Changed _current! Update the spinlock
950 : : * bookkeeping so the validation doesn't get
951 : : * confused when the "wrong" thread tries to
952 : : * release the lock.
953 : : */
954 : : z_spin_lock_set_owner(&_sched_spinlock);
955 : : #endif /* CONFIG_SPIN_VALIDATE */
956 : :
957 : : /* A queued (runnable) old/current thread
958 : : * needs to be added back to the run queue
959 : : * here, and atomically with its switch handle
960 : : * being set below. This is safe now, as we
961 : : * will not return into it.
962 : : */
963 : : if (z_is_thread_queued(old_thread)) {
964 : : #ifdef CONFIG_SCHED_IPI_CASCADE
965 : : if ((new_thread->base.cpu_mask != -1) &&
966 : : (old_thread->base.cpu_mask != BIT(cpu_id))) {
967 : : flag_ipi(ipi_mask_create(old_thread));
968 : : }
969 : : #endif
970 : : runq_add(old_thread);
971 : : }
972 : : }
973 : : old_thread->switch_handle = interrupted;
974 : : ret = new_thread->switch_handle;
975 : : /* Active threads MUST have a null here */
976 : : new_thread->switch_handle = NULL;
977 : : }
978 : : signal_pending_ipi();
979 : : return ret;
980 : : #else
981 : : z_sched_usage_switch(_kernel.ready_q.cache);
982 : : _current->switch_handle = interrupted;
983 : : set_current(_kernel.ready_q.cache);
984 : : return _current->switch_handle;
985 : : #endif /* CONFIG_SMP */
986 : : }
987 : : #endif /* CONFIG_USE_SWITCH */
988 : :
989 : 0 : int z_unpend_all(_wait_q_t *wait_q)
990 : : {
991 : 0 : int need_sched = 0;
992 : 0 : struct k_thread *thread;
993 : :
994 [ # # ]: 0 : for (thread = z_waitq_head(wait_q); thread != NULL; thread = z_waitq_head(wait_q)) {
995 : 0 : z_unpend_thread(thread);
996 : 0 : z_ready_thread(thread);
997 : 0 : need_sched = 1;
998 : : }
999 : :
1000 : 0 : return need_sched;
1001 : : }
1002 : :
1003 : 1 : void init_ready_q(struct _ready_q *ready_q)
1004 : : {
1005 : 1 : _priq_run_init(&ready_q->runq);
1006 : 1 : }
1007 : :
1008 : 1 : void z_sched_init(void)
1009 : : {
1010 : : #ifdef CONFIG_SCHED_CPU_MASK_PIN_ONLY
1011 : : for (int i = 0; i < CONFIG_MP_MAX_NUM_CPUS; i++) {
1012 : : init_ready_q(&_kernel.cpus[i].ready_q);
1013 : : }
1014 : : #else
1015 : 1 : init_ready_q(&_kernel.ready_q);
1016 : : #endif /* CONFIG_SCHED_CPU_MASK_PIN_ONLY */
1017 : 1 : }
1018 : :
1019 : 0 : void z_impl_k_thread_priority_set(k_tid_t thread, int prio)
1020 : : {
1021 : : /*
1022 : : * Use NULL, since we cannot know what the entry point is (we do not
1023 : : * keep track of it) and idle cannot change its priority.
1024 : : */
1025 [ # # # # : 0 : Z_ASSERT_VALID_PRIO(prio, NULL);
# # ]
1026 : :
1027 : 0 : bool need_sched = z_thread_prio_set((struct k_thread *)thread, prio);
1028 : :
1029 [ # # ]: 0 : if ((need_sched) && (IS_ENABLED(CONFIG_SMP) ||
1030 [ # # ]: 0 : (_current->base.sched_locked == 0U))) {
1031 : 0 : z_reschedule_unlocked();
1032 : : }
1033 : 0 : }
1034 : :
1035 : : #ifdef CONFIG_USERSPACE
1036 : : static inline void z_vrfy_k_thread_priority_set(k_tid_t thread, int prio)
1037 : : {
1038 : : K_OOPS(K_SYSCALL_OBJ(thread, K_OBJ_THREAD));
1039 : : K_OOPS(K_SYSCALL_VERIFY_MSG(_is_valid_prio(prio, NULL),
1040 : : "invalid thread priority %d", prio));
1041 : : #ifndef CONFIG_USERSPACE_THREAD_MAY_RAISE_PRIORITY
1042 : : K_OOPS(K_SYSCALL_VERIFY_MSG((int8_t)prio >= thread->base.prio,
1043 : : "thread priority may only be downgraded (%d < %d)",
1044 : : prio, thread->base.prio));
1045 : : #endif /* CONFIG_USERSPACE_THREAD_MAY_RAISE_PRIORITY */
1046 : : z_impl_k_thread_priority_set(thread, prio);
1047 : : }
1048 : : #include <zephyr/syscalls/k_thread_priority_set_mrsh.c>
1049 : : #endif /* CONFIG_USERSPACE */
1050 : :
1051 : : #ifdef CONFIG_SCHED_DEADLINE
1052 : : void z_impl_k_thread_absolute_deadline_set(k_tid_t tid, int deadline)
1053 : : {
1054 : : struct k_thread *thread = tid;
1055 : :
1056 : : /* The prio_deadline field changes the sorting order, so can't
1057 : : * change it while the thread is in the run queue (dlists
1058 : : * actually are benign as long as we requeue it before we
1059 : : * release the lock, but an rbtree will blow up if we break
1060 : : * sorting!)
1061 : : */
1062 : : K_SPINLOCK(&_sched_spinlock) {
1063 : : if (z_is_thread_queued(thread)) {
1064 : : dequeue_thread(thread);
1065 : : thread->base.prio_deadline = deadline;
1066 : : queue_thread(thread);
1067 : : } else {
1068 : : thread->base.prio_deadline = deadline;
1069 : : }
1070 : : }
1071 : : }
1072 : :
1073 : : void z_impl_k_thread_deadline_set(k_tid_t tid, int deadline)
1074 : : {
1075 : :
1076 : : deadline = clamp(deadline, 0, INT_MAX);
1077 : :
1078 : : int32_t newdl = k_cycle_get_32() + deadline;
1079 : :
1080 : : z_impl_k_thread_absolute_deadline_set(tid, newdl);
1081 : : }
1082 : :
1083 : : #ifdef CONFIG_USERSPACE
1084 : : static inline void z_vrfy_k_thread_absolute_deadline_set(k_tid_t tid, int deadline)
1085 : : {
1086 : : struct k_thread *thread = tid;
1087 : :
1088 : : K_OOPS(K_SYSCALL_OBJ(thread, K_OBJ_THREAD));
1089 : :
1090 : : z_impl_k_thread_absolute_deadline_set((k_tid_t)thread, deadline);
1091 : : }
1092 : : #include <zephyr/syscalls/k_thread_absolute_deadline_set_mrsh.c>
1093 : :
1094 : : static inline void z_vrfy_k_thread_deadline_set(k_tid_t tid, int deadline)
1095 : : {
1096 : : struct k_thread *thread = tid;
1097 : :
1098 : : K_OOPS(K_SYSCALL_OBJ(thread, K_OBJ_THREAD));
1099 : : K_OOPS(K_SYSCALL_VERIFY_MSG(deadline > 0,
1100 : : "invalid thread deadline %d",
1101 : : (int)deadline));
1102 : :
1103 : : z_impl_k_thread_deadline_set((k_tid_t)thread, deadline);
1104 : : }
1105 : : #include <zephyr/syscalls/k_thread_deadline_set_mrsh.c>
1106 : : #endif /* CONFIG_USERSPACE */
1107 : : #endif /* CONFIG_SCHED_DEADLINE */
1108 : :
1109 : 0 : void z_impl_k_reschedule(void)
1110 : : {
1111 : 0 : k_spinlock_key_t key;
1112 : :
1113 : 0 : key = k_spin_lock(&_sched_spinlock);
1114 : :
1115 : 0 : update_cache(0);
1116 : :
1117 : 0 : z_reschedule(&_sched_spinlock, key);
1118 : 0 : }
1119 : :
1120 : : #ifdef CONFIG_USERSPACE
1121 : : static inline void z_vrfy_k_reschedule(void)
1122 : : {
1123 : : z_impl_k_reschedule();
1124 : : }
1125 : : #include <zephyr/syscalls/k_reschedule_mrsh.c>
1126 : : #endif /* CONFIG_USERSPACE */
1127 : :
1128 : 0 : bool k_can_yield(void)
1129 : : {
1130 [ # # # # ]: 0 : return !(k_is_pre_kernel() || k_is_in_isr() ||
1131 [ # # ]: 0 : z_is_idle_thread_object(_current));
1132 : : }
1133 : :
1134 : 0 : void z_impl_k_yield(void)
1135 : : {
1136 [ # # ]: 0 : __ASSERT(!arch_is_in_isr(), "");
1137 : :
1138 : 0 : SYS_PORT_TRACING_FUNC(k_thread, yield);
1139 : :
1140 : 0 : k_spinlock_key_t key = k_spin_lock(&_sched_spinlock);
1141 : :
1142 : 0 : runq_yield();
1143 : :
1144 : 0 : update_cache(1);
1145 : 0 : z_swap(&_sched_spinlock, key);
1146 : 0 : }
1147 : :
1148 : : #ifdef CONFIG_USERSPACE
1149 : : static inline void z_vrfy_k_yield(void)
1150 : : {
1151 : : z_impl_k_yield();
1152 : : }
1153 : : #include <zephyr/syscalls/k_yield_mrsh.c>
1154 : : #endif /* CONFIG_USERSPACE */
1155 : :
1156 : 0 : static int32_t z_tick_sleep(k_timeout_t timeout)
1157 : : {
1158 : 0 : uint32_t expected_wakeup_ticks;
1159 : :
1160 [ # # ]: 0 : __ASSERT(!arch_is_in_isr(), "");
1161 : :
1162 : 0 : LOG_DBG("thread %p for %lu ticks", _current, (unsigned long)timeout.ticks);
1163 : :
1164 : : /* K_NO_WAIT is treated as a 'yield' */
1165 [ # # ]: 0 : if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {
1166 : 0 : k_yield();
1167 : 0 : return 0;
1168 : : }
1169 : :
1170 : 0 : k_spinlock_key_t key = k_spin_lock(&_sched_spinlock);
1171 : :
1172 : : #if defined(CONFIG_TIMESLICING) && defined(CONFIG_SWAP_NONATOMIC)
1173 : : pending_current = _current;
1174 : : #endif /* CONFIG_TIMESLICING && CONFIG_SWAP_NONATOMIC */
1175 : 0 : unready_thread(_current);
1176 : 0 : expected_wakeup_ticks = (uint32_t)z_add_thread_timeout(_current, timeout);
1177 : 0 : z_mark_thread_as_sleeping(_current);
1178 : :
1179 : 0 : (void)z_swap(&_sched_spinlock, key);
1180 : :
1181 [ # # ]: 0 : if (!z_is_aborted_thread_timeout(_current)) {
1182 : : return 0;
1183 : : }
1184 : :
1185 : : /* We require a 32 bit unsigned subtraction to care a wraparound */
1186 : 0 : uint32_t left_ticks = expected_wakeup_ticks - sys_clock_tick_get_32();
1187 : :
1188 : : /* To handle a negative value correctly, once type-cast it to signed 32 bit */
1189 : 0 : k_ticks_t ticks = (k_ticks_t)(int32_t)left_ticks;
1190 : :
1191 [ # # ]: 0 : if (ticks > 0) {
1192 : : return ticks;
1193 : : }
1194 : :
1195 : : return 0;
1196 : : }
1197 : :
1198 : 0 : int32_t z_impl_k_sleep(k_timeout_t timeout)
1199 : : {
1200 : 0 : k_ticks_t ticks;
1201 : :
1202 [ # # ]: 0 : __ASSERT(!arch_is_in_isr(), "");
1203 : :
1204 : 0 : SYS_PORT_TRACING_FUNC_ENTER(k_thread, sleep, timeout);
1205 : :
1206 : 0 : ticks = z_tick_sleep(timeout);
1207 : :
1208 : : /* k_sleep() still returns 32 bit milliseconds for compatibility */
1209 [ # # ]: 0 : int64_t ms = K_TIMEOUT_EQ(timeout, K_FOREVER) ? K_TICKS_FOREVER :
1210 : 0 : clamp(k_ticks_to_ms_ceil64(ticks), 0, INT_MAX);
1211 : :
1212 : 0 : SYS_PORT_TRACING_FUNC_EXIT(k_thread, sleep, timeout, ms);
1213 : 0 : return (int32_t) ms;
1214 : : }
1215 : :
1216 : : #ifdef CONFIG_USERSPACE
1217 : : static inline int32_t z_vrfy_k_sleep(k_timeout_t timeout)
1218 : : {
1219 : : return z_impl_k_sleep(timeout);
1220 : : }
1221 : : #include <zephyr/syscalls/k_sleep_mrsh.c>
1222 : : #endif /* CONFIG_USERSPACE */
1223 : :
1224 : 0 : int32_t z_impl_k_usleep(int32_t us)
1225 : : {
1226 : 0 : int32_t ticks;
1227 : :
1228 : 0 : SYS_PORT_TRACING_FUNC_ENTER(k_thread, usleep, us);
1229 : :
1230 : 0 : ticks = k_us_to_ticks_ceil64(us);
1231 : 0 : ticks = z_tick_sleep(Z_TIMEOUT_TICKS(ticks));
1232 : :
1233 : 0 : int32_t ret = k_ticks_to_us_ceil64(ticks);
1234 : :
1235 : 0 : SYS_PORT_TRACING_FUNC_EXIT(k_thread, usleep, us, ret);
1236 : :
1237 : 0 : return ret;
1238 : : }
1239 : :
1240 : : #ifdef CONFIG_USERSPACE
1241 : : static inline int32_t z_vrfy_k_usleep(int32_t us)
1242 : : {
1243 : : return z_impl_k_usleep(us);
1244 : : }
1245 : : #include <zephyr/syscalls/k_usleep_mrsh.c>
1246 : : #endif /* CONFIG_USERSPACE */
1247 : :
1248 : 50 : void z_impl_k_wakeup(k_tid_t thread)
1249 : : {
1250 : 50 : SYS_PORT_TRACING_OBJ_FUNC(k_thread, wakeup, thread);
1251 : :
1252 : 50 : k_spinlock_key_t key = k_spin_lock(&_sched_spinlock);
1253 : :
1254 [ + + ]: 50 : if (z_is_thread_sleeping(thread)) {
1255 : 46 : z_abort_thread_timeout(thread);
1256 : 46 : z_mark_thread_as_not_sleeping(thread);
1257 : 46 : ready_thread(thread);
1258 : 46 : z_reschedule(&_sched_spinlock, key);
1259 : : } else {
1260 : 4 : k_spin_unlock(&_sched_spinlock, key);
1261 : : }
1262 : 50 : }
1263 : :
1264 : : #ifdef CONFIG_USERSPACE
1265 : : static inline void z_vrfy_k_wakeup(k_tid_t thread)
1266 : : {
1267 : : K_OOPS(K_SYSCALL_OBJ(thread, K_OBJ_THREAD));
1268 : : z_impl_k_wakeup(thread);
1269 : : }
1270 : : #include <zephyr/syscalls/k_wakeup_mrsh.c>
1271 : : #endif /* CONFIG_USERSPACE */
1272 : :
1273 : 46 : k_tid_t z_impl_k_sched_current_thread_query(void)
1274 : : {
1275 : 46 : return _current;
1276 : : }
1277 : :
1278 : : #ifdef CONFIG_USERSPACE
1279 : : static inline k_tid_t z_vrfy_k_sched_current_thread_query(void)
1280 : : {
1281 : : return z_impl_k_sched_current_thread_query();
1282 : : }
1283 : : #include <zephyr/syscalls/k_sched_current_thread_query_mrsh.c>
1284 : : #endif /* CONFIG_USERSPACE */
1285 : :
1286 : 46 : static inline void unpend_all(_wait_q_t *wait_q)
1287 : : {
1288 : 46 : struct k_thread *thread;
1289 : :
1290 [ + + ]: 52 : for (thread = z_waitq_head(wait_q); thread != NULL; thread = z_waitq_head(wait_q)) {
1291 : 6 : unpend_thread_no_timeout(thread);
1292 : 6 : z_abort_thread_timeout(thread);
1293 : 6 : arch_thread_return_value_set(thread, 0);
1294 : 6 : ready_thread(thread);
1295 : : }
1296 : 46 : }
1297 : :
1298 : : #ifdef CONFIG_THREAD_ABORT_HOOK
1299 : : extern void thread_abort_hook(struct k_thread *thread);
1300 : : #endif /* CONFIG_THREAD_ABORT_HOOK */
1301 : :
1302 : : /**
1303 : : * @brief Dequeues the specified thread
1304 : : *
1305 : : * Dequeues the specified thread and move it into the specified new state.
1306 : : *
1307 : : * @param thread Identify the thread to halt
1308 : : * @param new_state New thread state (_THREAD_DEAD or _THREAD_SUSPENDED)
1309 : : */
1310 : : #ifdef IAR_SUPPRESS_ALWAYS_INLINE_WARNING_FLAG
1311 : : TOOLCHAIN_DISABLE_WARNING(TOOLCHAIN_WARNING_ALWAYS_INLINE)
1312 : : #endif
1313 : 46 : static ALWAYS_INLINE void halt_thread(struct k_thread *thread, uint8_t new_state)
1314 : : {
1315 : 46 : bool dummify = false;
1316 : :
1317 : : /* We hold the lock, and the thread is known not to be running
1318 : : * anywhere.
1319 : : */
1320 [ + - ]: 46 : if ((thread->base.thread_state & new_state) == 0U) {
1321 : 46 : thread->base.thread_state |= new_state;
1322 [ + - ]: 46 : if (z_is_thread_queued(thread)) {
1323 : 46 : dequeue_thread(thread);
1324 : : }
1325 : :
1326 [ + - ]: 46 : if (new_state == _THREAD_DEAD) {
1327 [ - + ]: 46 : if (thread->base.pended_on != NULL) {
1328 : 0 : unpend_thread_no_timeout(thread);
1329 : : }
1330 : 46 : z_abort_thread_timeout(thread);
1331 : 46 : unpend_all(&thread->join_queue);
1332 : :
1333 : : /* Edge case: aborting _current from within an
1334 : : * ISR that preempted it requires clearing the
1335 : : * _current pointer so the upcoming context
1336 : : * switch doesn't clobber the now-freed
1337 : : * memory
1338 : : */
1339 : 46 : if (thread == _current && arch_is_in_isr()) {
1340 : : dummify = true;
1341 : : }
1342 : : }
1343 : : #ifdef CONFIG_SMP
1344 : : unpend_all(&thread->halt_queue);
1345 : : #endif /* CONFIG_SMP */
1346 : 46 : update_cache(1);
1347 : :
1348 [ + - ]: 46 : if (new_state == _THREAD_SUSPENDED) {
1349 : : clear_halting(thread);
1350 : : return;
1351 : : }
1352 : :
1353 : 46 : arch_coprocessors_disable(thread);
1354 : :
1355 : 46 : SYS_PORT_TRACING_FUNC(k_thread, sched_abort, thread);
1356 : :
1357 : 46 : z_thread_monitor_exit(thread);
1358 : : #ifdef CONFIG_THREAD_ABORT_HOOK
1359 : : thread_abort_hook(thread);
1360 : : #endif /* CONFIG_THREAD_ABORT_HOOK */
1361 : :
1362 : : #ifdef CONFIG_OBJ_CORE_THREAD
1363 : : #ifdef CONFIG_OBJ_CORE_STATS_THREAD
1364 : : k_obj_core_stats_deregister(K_OBJ_CORE(thread));
1365 : : #endif /* CONFIG_OBJ_CORE_STATS_THREAD */
1366 : : k_obj_core_unlink(K_OBJ_CORE(thread));
1367 : : #endif /* CONFIG_OBJ_CORE_THREAD */
1368 : :
1369 : : #ifdef CONFIG_USERSPACE
1370 : : z_mem_domain_exit_thread(thread);
1371 : : k_thread_perms_all_clear(thread);
1372 : : k_object_uninit(thread->stack_obj);
1373 : : k_object_uninit(thread);
1374 : : #endif /* CONFIG_USERSPACE */
1375 : :
1376 : : #ifdef CONFIG_THREAD_ABORT_NEED_CLEANUP
1377 : : k_thread_abort_cleanup(thread);
1378 : : #endif /* CONFIG_THREAD_ABORT_NEED_CLEANUP */
1379 : :
1380 : : /* Do this "set _current to dummy" step last so that
1381 : : * subsystems above can rely on _current being
1382 : : * unchanged. Disabled for posix as that arch
1383 : : * continues to use the _current pointer in its swap
1384 : : * code. Note that we must leave a non-null switch
1385 : : * handle for any threads spinning in join() (this can
1386 : : * never be used, as our thread is flagged dead, but
1387 : : * it must not be NULL otherwise join can deadlock).
1388 : : * Use 1 as a clearly invalid but non-NULL value.
1389 : : */
1390 : 46 : if (dummify && !IS_ENABLED(CONFIG_ARCH_POSIX)) {
1391 : : #ifdef CONFIG_USE_SWITCH
1392 : : _current->switch_handle = (void *)1;
1393 : : #endif
1394 : : z_dummy_thread_init(&_thread_dummy);
1395 : :
1396 : : }
1397 : :
1398 : : /* Finally update the halting thread state, on which
1399 : : * other CPUs might be spinning (see
1400 : : * thread_halt_spin()).
1401 : : */
1402 : 46 : clear_halting(thread);
1403 : : }
1404 : : }
1405 : : #ifdef IAR_SUPPRESS_ALWAYS_INLINE_WARNING_FLAG
1406 : : TOOLCHAIN_ENABLE_WARNING(TOOLCHAIN_WARNING_ALWAYS_INLINE)
1407 : : #endif
1408 : :
1409 : 88 : void z_thread_abort(struct k_thread *thread)
1410 : : {
1411 : 88 : bool essential = z_is_thread_essential(thread);
1412 : 88 : k_spinlock_key_t key = k_spin_lock(&_sched_spinlock);
1413 : :
1414 [ + + ]: 88 : if (z_is_thread_dead(thread)) {
1415 : 42 : k_spin_unlock(&_sched_spinlock, key);
1416 : 42 : return;
1417 : : }
1418 : :
1419 : 46 : z_thread_halt(thread, key, true);
1420 : :
1421 [ # # ]: 0 : if (essential) {
1422 : 0 : __ASSERT(!essential, "aborted essential thread %p", thread);
1423 : 0 : k_panic();
1424 : : }
1425 : : }
1426 : :
1427 : : #if !defined(CONFIG_ARCH_HAS_THREAD_ABORT)
1428 : : void z_impl_k_thread_abort(k_tid_t thread)
1429 : : {
1430 : : SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_thread, abort, thread);
1431 : :
1432 : : z_thread_abort(thread);
1433 : :
1434 : : __ASSERT_NO_MSG(z_is_thread_dead(thread));
1435 : :
1436 : : SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_thread, abort, thread);
1437 : : }
1438 : : #endif /* !CONFIG_ARCH_HAS_THREAD_ABORT */
1439 : :
1440 : 46 : int z_impl_k_thread_join(struct k_thread *thread, k_timeout_t timeout)
1441 : : {
1442 : 46 : k_spinlock_key_t key = k_spin_lock(&_sched_spinlock);
1443 : 46 : int ret;
1444 : :
1445 : 46 : SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_thread, join, thread, timeout);
1446 : :
1447 [ + + ]: 46 : if (z_is_thread_dead(thread)) {
1448 : : z_sched_switch_spin(thread);
1449 : 40 : ret = 0;
1450 [ + - ]: 6 : } else if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {
1451 : : ret = -EBUSY;
1452 [ + - ]: 6 : } else if ((thread == _current) ||
1453 [ + - ]: 6 : (thread->base.pended_on == &_current->join_queue)) {
1454 : : ret = -EDEADLK;
1455 : : } else {
1456 [ - + ]: 6 : __ASSERT(!arch_is_in_isr(), "cannot join in ISR");
1457 : 6 : add_to_waitq_locked(_current, &thread->join_queue);
1458 : 6 : add_thread_timeout(_current, timeout);
1459 : :
1460 : 6 : SYS_PORT_TRACING_OBJ_FUNC_BLOCKING(k_thread, join, thread, timeout);
1461 : 6 : ret = z_swap(&_sched_spinlock, key);
1462 : 6 : SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_thread, join, thread, timeout, ret);
1463 : :
1464 : 6 : return ret;
1465 : : }
1466 : :
1467 : 40 : SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_thread, join, thread, timeout, ret);
1468 : :
1469 : 40 : k_spin_unlock(&_sched_spinlock, key);
1470 : 40 : return ret;
1471 : : }
1472 : :
1473 : : #ifdef CONFIG_USERSPACE
1474 : : /* Special case: don't oops if the thread is uninitialized. This is because
1475 : : * the initialization bit does double-duty for thread objects; if false, means
1476 : : * the thread object is truly uninitialized, or the thread ran and exited for
1477 : : * some reason.
1478 : : *
1479 : : * Return true in this case indicating we should just do nothing and return
1480 : : * success to the caller.
1481 : : */
1482 : : static bool thread_obj_validate(struct k_thread *thread)
1483 : : {
1484 : : struct k_object *ko = k_object_find(thread);
1485 : : int ret = k_object_validate(ko, K_OBJ_THREAD, _OBJ_INIT_TRUE);
1486 : :
1487 : : switch (ret) {
1488 : : case 0:
1489 : : return false;
1490 : : case -EINVAL:
1491 : : return true;
1492 : : default:
1493 : : #ifdef CONFIG_LOG
1494 : : k_object_dump_error(ret, thread, ko, K_OBJ_THREAD);
1495 : : #endif /* CONFIG_LOG */
1496 : : K_OOPS(K_SYSCALL_VERIFY_MSG(ret, "access denied"));
1497 : : }
1498 : : CODE_UNREACHABLE; /* LCOV_EXCL_LINE */
1499 : : }
1500 : :
1501 : : static inline int z_vrfy_k_thread_join(struct k_thread *thread,
1502 : : k_timeout_t timeout)
1503 : : {
1504 : : if (thread_obj_validate(thread)) {
1505 : : return 0;
1506 : : }
1507 : :
1508 : : return z_impl_k_thread_join(thread, timeout);
1509 : : }
1510 : : #include <zephyr/syscalls/k_thread_join_mrsh.c>
1511 : :
1512 : : static inline void z_vrfy_k_thread_abort(k_tid_t thread)
1513 : : {
1514 : : if (thread_obj_validate(thread)) {
1515 : : return;
1516 : : }
1517 : :
1518 : : K_OOPS(K_SYSCALL_VERIFY_MSG(!z_is_thread_essential(thread),
1519 : : "aborting essential thread %p", thread));
1520 : :
1521 : : z_impl_k_thread_abort((struct k_thread *)thread);
1522 : : }
1523 : : #include <zephyr/syscalls/k_thread_abort_mrsh.c>
1524 : : #endif /* CONFIG_USERSPACE */
1525 : :
1526 : : /*
1527 : : * future scheduler.h API implementations
1528 : : */
1529 : 0 : bool z_sched_wake(_wait_q_t *wait_q, int swap_retval, void *swap_data)
1530 : : {
1531 : 0 : struct k_thread *thread;
1532 : 0 : bool ret = false;
1533 : :
1534 [ # # ]: 0 : K_SPINLOCK(&_sched_spinlock) {
1535 : 0 : thread = _priq_wait_best(&wait_q->waitq);
1536 : :
1537 [ # # ]: 0 : if (thread != NULL) {
1538 : 0 : z_thread_return_value_set_with_data(thread,
1539 : : swap_retval,
1540 : : swap_data);
1541 : 0 : unpend_thread_no_timeout(thread);
1542 : 0 : z_abort_thread_timeout(thread);
1543 : 0 : ready_thread(thread);
1544 : 0 : ret = true;
1545 : : }
1546 : : }
1547 : :
1548 : 0 : return ret;
1549 : : }
1550 : :
1551 : 0 : int z_sched_wait(struct k_spinlock *lock, k_spinlock_key_t key,
1552 : : _wait_q_t *wait_q, k_timeout_t timeout, void **data)
1553 : : {
1554 : 0 : int ret = z_pend_curr(lock, key, wait_q, timeout);
1555 : :
1556 [ # # ]: 0 : if (data != NULL) {
1557 : 0 : *data = _current->base.swap_data;
1558 : : }
1559 : 0 : return ret;
1560 : : }
1561 : :
1562 : 0 : int z_sched_waitq_walk(_wait_q_t *wait_q,
1563 : : int (*func)(struct k_thread *, void *), void *data)
1564 : : {
1565 : 0 : struct k_thread *thread;
1566 : 0 : int status = 0;
1567 : :
1568 [ # # ]: 0 : K_SPINLOCK(&_sched_spinlock) {
1569 [ # # ]: 0 : _WAIT_Q_FOR_EACH(wait_q, thread) {
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 = func(thread, data);
1578 [ # # ]: 0 : if (status != 0) {
1579 : : break;
1580 : : }
1581 : : }
1582 : : }
1583 : :
1584 : 0 : return status;
1585 : : }
1586 : :
1587 : : /* This routine exists for benchmarking purposes. It is not used in
1588 : : * general production code.
1589 : : */
1590 : 0 : void z_unready_thread(struct k_thread *thread)
1591 : : {
1592 [ # # ]: 0 : K_SPINLOCK(&_sched_spinlock) {
1593 : 0 : unready_thread(thread);
1594 : : }
1595 : 0 : }
|