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