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 <zephyr/kernel/internal/sched_priq.h>
10 #include <wait_q.h>
11 #include <kswap.h>
12 #include <kernel_arch_func.h>
13 #include <zephyr/syscall_handler.h>
14 #include <zephyr/drivers/timer/system_timer.h>
15 #include <stdbool.h>
16 #include <kernel_internal.h>
17 #include <zephyr/logging/log.h>
18 #include <zephyr/sys/atomic.h>
19 #include <zephyr/sys/math_extras.h>
20 #include <zephyr/timing/timing.h>
21 #include <zephyr/sys/util.h>
22
23 LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL);
24
25 #if defined(CONFIG_SCHED_DUMB)
26 #define _priq_run_add z_priq_dumb_add
27 #define _priq_run_remove z_priq_dumb_remove
28 # if defined(CONFIG_SCHED_CPU_MASK)
29 # define _priq_run_best _priq_dumb_mask_best
30 # else
31 # define _priq_run_best z_priq_dumb_best
32 # endif
33 #elif defined(CONFIG_SCHED_SCALABLE)
34 #define _priq_run_add z_priq_rb_add
35 #define _priq_run_remove z_priq_rb_remove
36 #define _priq_run_best z_priq_rb_best
37 #elif defined(CONFIG_SCHED_MULTIQ)
38 #define _priq_run_add z_priq_mq_add
39 #define _priq_run_remove z_priq_mq_remove
40 #define _priq_run_best z_priq_mq_best
41 static ALWAYS_INLINE void z_priq_mq_add(struct _priq_mq *pq,
42 struct k_thread *thread);
43 static ALWAYS_INLINE void z_priq_mq_remove(struct _priq_mq *pq,
44 struct k_thread *thread);
45 #endif
46
47 #if defined(CONFIG_WAITQ_SCALABLE)
48 #define z_priq_wait_add z_priq_rb_add
49 #define _priq_wait_remove z_priq_rb_remove
50 #define _priq_wait_best z_priq_rb_best
51 #elif defined(CONFIG_WAITQ_DUMB)
52 #define z_priq_wait_add z_priq_dumb_add
53 #define _priq_wait_remove z_priq_dumb_remove
54 #define _priq_wait_best z_priq_dumb_best
55 #endif
56
57 struct k_spinlock sched_spinlock;
58
59 static void update_cache(int preempt_ok);
60 static void end_thread(struct k_thread *thread);
61
62
is_preempt(struct k_thread * thread)63 static inline int is_preempt(struct k_thread *thread)
64 {
65 /* explanation in kernel_struct.h */
66 return thread->base.preempt <= _PREEMPT_THRESHOLD;
67 }
68
69 BUILD_ASSERT(CONFIG_NUM_COOP_PRIORITIES >= CONFIG_NUM_METAIRQ_PRIORITIES,
70 "You need to provide at least as many CONFIG_NUM_COOP_PRIORITIES as "
71 "CONFIG_NUM_METAIRQ_PRIORITIES as Meta IRQs are just a special class of cooperative "
72 "threads.");
73
is_metairq(struct k_thread * thread)74 static inline int is_metairq(struct k_thread *thread)
75 {
76 #if CONFIG_NUM_METAIRQ_PRIORITIES > 0
77 return (thread->base.prio - K_HIGHEST_THREAD_PRIO)
78 < CONFIG_NUM_METAIRQ_PRIORITIES;
79 #else
80 ARG_UNUSED(thread);
81 return 0;
82 #endif
83 }
84
85 #if CONFIG_ASSERT
is_thread_dummy(struct k_thread * thread)86 static inline bool is_thread_dummy(struct k_thread *thread)
87 {
88 return (thread->base.thread_state & _THREAD_DUMMY) != 0U;
89 }
90 #endif
91
92 /*
93 * Return value same as e.g. memcmp
94 * > 0 -> thread 1 priority > thread 2 priority
95 * = 0 -> thread 1 priority == thread 2 priority
96 * < 0 -> thread 1 priority < thread 2 priority
97 * Do not rely on the actual value returned aside from the above.
98 * (Again, like memcmp.)
99 */
z_sched_prio_cmp(struct k_thread * thread_1,struct k_thread * thread_2)100 int32_t z_sched_prio_cmp(struct k_thread *thread_1,
101 struct k_thread *thread_2)
102 {
103 /* `prio` is <32b, so the below cannot overflow. */
104 int32_t b1 = thread_1->base.prio;
105 int32_t b2 = thread_2->base.prio;
106
107 if (b1 != b2) {
108 return b2 - b1;
109 }
110
111 #ifdef CONFIG_SCHED_DEADLINE
112 /* If we assume all deadlines live within the same "half" of
113 * the 32 bit modulus space (this is a documented API rule),
114 * then the latest deadline in the queue minus the earliest is
115 * guaranteed to be (2's complement) non-negative. We can
116 * leverage that to compare the values without having to check
117 * the current time.
118 */
119 uint32_t d1 = thread_1->base.prio_deadline;
120 uint32_t d2 = thread_2->base.prio_deadline;
121
122 if (d1 != d2) {
123 /* Sooner deadline means higher effective priority.
124 * Doing the calculation with unsigned types and casting
125 * to signed isn't perfect, but at least reduces this
126 * from UB on overflow to impdef.
127 */
128 return (int32_t) (d2 - d1);
129 }
130 #endif
131 return 0;
132 }
133
should_preempt(struct k_thread * thread,int preempt_ok)134 static ALWAYS_INLINE bool should_preempt(struct k_thread *thread,
135 int preempt_ok)
136 {
137 /* Preemption is OK if it's being explicitly allowed by
138 * software state (e.g. the thread called k_yield())
139 */
140 if (preempt_ok != 0) {
141 return true;
142 }
143
144 __ASSERT(_current != NULL, "");
145
146 /* Or if we're pended/suspended/dummy (duh) */
147 if (z_is_thread_prevented_from_running(_current)) {
148 return true;
149 }
150
151 /* Edge case on ARM where a thread can be pended out of an
152 * interrupt handler before the "synchronous" swap starts
153 * context switching. Platforms with atomic swap can never
154 * hit this.
155 */
156 if (IS_ENABLED(CONFIG_SWAP_NONATOMIC)
157 && z_is_thread_timeout_active(thread)) {
158 return true;
159 }
160
161 /* Otherwise we have to be running a preemptible thread or
162 * switching to a metairq
163 */
164 if (is_preempt(_current) || is_metairq(thread)) {
165 return true;
166 }
167
168 return false;
169 }
170
171 #ifdef CONFIG_SCHED_CPU_MASK
_priq_dumb_mask_best(sys_dlist_t * pq)172 static ALWAYS_INLINE struct k_thread *_priq_dumb_mask_best(sys_dlist_t *pq)
173 {
174 /* With masks enabled we need to be prepared to walk the list
175 * looking for one we can run
176 */
177 struct k_thread *thread;
178
179 SYS_DLIST_FOR_EACH_CONTAINER(pq, thread, base.qnode_dlist) {
180 if ((thread->base.cpu_mask & BIT(_current_cpu->id)) != 0) {
181 return thread;
182 }
183 }
184 return NULL;
185 }
186 #endif
187
188 #if defined(CONFIG_SCHED_DUMB) || defined(CONFIG_WAITQ_DUMB)
z_priq_dumb_add(sys_dlist_t * pq,struct k_thread * thread)189 static ALWAYS_INLINE void z_priq_dumb_add(sys_dlist_t *pq,
190 struct k_thread *thread)
191 {
192 struct k_thread *t;
193
194 __ASSERT_NO_MSG(!z_is_idle_thread_object(thread));
195
196 SYS_DLIST_FOR_EACH_CONTAINER(pq, t, base.qnode_dlist) {
197 if (z_sched_prio_cmp(thread, t) > 0) {
198 sys_dlist_insert(&t->base.qnode_dlist,
199 &thread->base.qnode_dlist);
200 return;
201 }
202 }
203
204 sys_dlist_append(pq, &thread->base.qnode_dlist);
205 }
206 #endif
207
thread_runq(struct k_thread * thread)208 static ALWAYS_INLINE void *thread_runq(struct k_thread *thread)
209 {
210 #ifdef CONFIG_SCHED_CPU_MASK_PIN_ONLY
211 int cpu, m = thread->base.cpu_mask;
212
213 /* Edge case: it's legal per the API to "make runnable" a
214 * thread with all CPUs masked off (i.e. one that isn't
215 * actually runnable!). Sort of a wart in the API and maybe
216 * we should address this in docs/assertions instead to avoid
217 * the extra test.
218 */
219 cpu = m == 0 ? 0 : u32_count_trailing_zeros(m);
220
221 return &_kernel.cpus[cpu].ready_q.runq;
222 #else
223 ARG_UNUSED(thread);
224 return &_kernel.ready_q.runq;
225 #endif
226 }
227
curr_cpu_runq(void)228 static ALWAYS_INLINE void *curr_cpu_runq(void)
229 {
230 #ifdef CONFIG_SCHED_CPU_MASK_PIN_ONLY
231 return &arch_curr_cpu()->ready_q.runq;
232 #else
233 return &_kernel.ready_q.runq;
234 #endif
235 }
236
runq_add(struct k_thread * thread)237 static ALWAYS_INLINE void runq_add(struct k_thread *thread)
238 {
239 _priq_run_add(thread_runq(thread), thread);
240 }
241
runq_remove(struct k_thread * thread)242 static ALWAYS_INLINE void runq_remove(struct k_thread *thread)
243 {
244 _priq_run_remove(thread_runq(thread), thread);
245 }
246
runq_best(void)247 static ALWAYS_INLINE struct k_thread *runq_best(void)
248 {
249 return _priq_run_best(curr_cpu_runq());
250 }
251
252 /* _current is never in the run queue until context switch on
253 * SMP configurations, see z_requeue_current()
254 */
should_queue_thread(struct k_thread * th)255 static inline bool should_queue_thread(struct k_thread *th)
256 {
257 return !IS_ENABLED(CONFIG_SMP) || th != _current;
258 }
259
queue_thread(struct k_thread * thread)260 static ALWAYS_INLINE void queue_thread(struct k_thread *thread)
261 {
262 thread->base.thread_state |= _THREAD_QUEUED;
263 if (should_queue_thread(thread)) {
264 runq_add(thread);
265 }
266 #ifdef CONFIG_SMP
267 if (thread == _current) {
268 /* add current to end of queue means "yield" */
269 _current_cpu->swap_ok = true;
270 }
271 #endif
272 }
273
dequeue_thread(struct k_thread * thread)274 static ALWAYS_INLINE void dequeue_thread(struct k_thread *thread)
275 {
276 thread->base.thread_state &= ~_THREAD_QUEUED;
277 if (should_queue_thread(thread)) {
278 runq_remove(thread);
279 }
280 }
281
signal_pending_ipi(void)282 static void signal_pending_ipi(void)
283 {
284 /* Synchronization note: you might think we need to lock these
285 * two steps, but an IPI is idempotent. It's OK if we do it
286 * twice. All we require is that if a CPU sees the flag true,
287 * it is guaranteed to send the IPI, and if a core sets
288 * pending_ipi, the IPI will be sent the next time through
289 * this code.
290 */
291 #if defined(CONFIG_SMP) && defined(CONFIG_SCHED_IPI_SUPPORTED)
292 if (arch_num_cpus() > 1) {
293 if (_kernel.pending_ipi) {
294 _kernel.pending_ipi = false;
295 arch_sched_ipi();
296 }
297 }
298 #endif
299 }
300
301 #ifdef CONFIG_SMP
302 /* Called out of z_swap() when CONFIG_SMP. The current thread can
303 * never live in the run queue until we are inexorably on the context
304 * switch path on SMP, otherwise there is a deadlock condition where a
305 * set of CPUs pick a cycle of threads to run and wait for them all to
306 * context switch forever.
307 */
z_requeue_current(struct k_thread * curr)308 void z_requeue_current(struct k_thread *curr)
309 {
310 if (z_is_thread_queued(curr)) {
311 runq_add(curr);
312 }
313 signal_pending_ipi();
314 }
315
is_aborting(struct k_thread * thread)316 static inline bool is_aborting(struct k_thread *thread)
317 {
318 return (thread->base.thread_state & _THREAD_ABORTING) != 0U;
319 }
320 #endif
321
next_up(void)322 static ALWAYS_INLINE struct k_thread *next_up(void)
323 {
324 #ifdef CONFIG_SMP
325 if (is_aborting(_current)) {
326 end_thread(_current);
327 }
328 #endif
329
330 struct k_thread *thread = runq_best();
331
332 #if (CONFIG_NUM_METAIRQ_PRIORITIES > 0) && \
333 (CONFIG_NUM_COOP_PRIORITIES > CONFIG_NUM_METAIRQ_PRIORITIES)
334 /* MetaIRQs must always attempt to return back to a
335 * cooperative thread they preempted and not whatever happens
336 * to be highest priority now. The cooperative thread was
337 * promised it wouldn't be preempted (by non-metairq threads)!
338 */
339 struct k_thread *mirqp = _current_cpu->metairq_preempted;
340
341 if (mirqp != NULL && (thread == NULL || !is_metairq(thread))) {
342 if (!z_is_thread_prevented_from_running(mirqp)) {
343 thread = mirqp;
344 } else {
345 _current_cpu->metairq_preempted = NULL;
346 }
347 }
348 #endif
349
350 #ifndef CONFIG_SMP
351 /* In uniprocessor mode, we can leave the current thread in
352 * the queue (actually we have to, otherwise the assembly
353 * context switch code for all architectures would be
354 * responsible for putting it back in z_swap and ISR return!),
355 * which makes this choice simple.
356 */
357 return (thread != NULL) ? thread : _current_cpu->idle_thread;
358 #else
359 /* Under SMP, the "cache" mechanism for selecting the next
360 * thread doesn't work, so we have more work to do to test
361 * _current against the best choice from the queue. Here, the
362 * thread selected above represents "the best thread that is
363 * not current".
364 *
365 * Subtle note on "queued": in SMP mode, _current does not
366 * live in the queue, so this isn't exactly the same thing as
367 * "ready", it means "is _current already added back to the
368 * queue such that we don't want to re-add it".
369 */
370 bool queued = z_is_thread_queued(_current);
371 bool active = !z_is_thread_prevented_from_running(_current);
372
373 if (thread == NULL) {
374 thread = _current_cpu->idle_thread;
375 }
376
377 if (active) {
378 int32_t cmp = z_sched_prio_cmp(_current, thread);
379
380 /* Ties only switch if state says we yielded */
381 if ((cmp > 0) || ((cmp == 0) && !_current_cpu->swap_ok)) {
382 thread = _current;
383 }
384
385 if (!should_preempt(thread, _current_cpu->swap_ok)) {
386 thread = _current;
387 }
388 }
389
390 /* Put _current back into the queue */
391 if (thread != _current && active &&
392 !z_is_idle_thread_object(_current) && !queued) {
393 queue_thread(_current);
394 }
395
396 /* Take the new _current out of the queue */
397 if (z_is_thread_queued(thread)) {
398 dequeue_thread(thread);
399 }
400
401 _current_cpu->swap_ok = false;
402 return thread;
403 #endif
404 }
405
move_thread_to_end_of_prio_q(struct k_thread * thread)406 static void move_thread_to_end_of_prio_q(struct k_thread *thread)
407 {
408 if (z_is_thread_queued(thread)) {
409 dequeue_thread(thread);
410 }
411 queue_thread(thread);
412 update_cache(thread == _current);
413 }
414
flag_ipi(void)415 static void flag_ipi(void)
416 {
417 #if defined(CONFIG_SMP) && defined(CONFIG_SCHED_IPI_SUPPORTED)
418 if (arch_num_cpus() > 1) {
419 _kernel.pending_ipi = true;
420 }
421 #endif
422 }
423
424 #ifdef CONFIG_TIMESLICING
425
426 static int slice_ticks = DIV_ROUND_UP(CONFIG_TIMESLICE_SIZE * Z_HZ_ticks, Z_HZ_ms);
427 static int slice_max_prio = CONFIG_TIMESLICE_PRIORITY;
428 static struct _timeout slice_timeouts[CONFIG_MP_MAX_NUM_CPUS];
429 static bool slice_expired[CONFIG_MP_MAX_NUM_CPUS];
430
431 #ifdef CONFIG_SWAP_NONATOMIC
432 /* If z_swap() isn't atomic, then it's possible for a timer interrupt
433 * to try to timeslice away _current after it has already pended
434 * itself but before the corresponding context switch. Treat that as
435 * a noop condition in z_time_slice().
436 */
437 static struct k_thread *pending_current;
438 #endif
439
slice_time(struct k_thread * thread)440 static inline int slice_time(struct k_thread *thread)
441 {
442 int ret = slice_ticks;
443
444 #ifdef CONFIG_TIMESLICE_PER_THREAD
445 if (thread->base.slice_ticks != 0) {
446 ret = thread->base.slice_ticks;
447 }
448 #else
449 ARG_UNUSED(thread);
450 #endif
451 return ret;
452 }
453
sliceable(struct k_thread * thread)454 static inline bool sliceable(struct k_thread *thread)
455 {
456 bool ret = is_preempt(thread)
457 && slice_time(thread) != 0
458 && !z_is_prio_higher(thread->base.prio, slice_max_prio)
459 && !z_is_thread_prevented_from_running(thread)
460 && !z_is_idle_thread_object(thread);
461
462 #ifdef CONFIG_TIMESLICE_PER_THREAD
463 ret |= thread->base.slice_ticks != 0;
464 #endif
465
466 return ret;
467 }
468
slice_timeout(struct _timeout * t)469 static void slice_timeout(struct _timeout *t)
470 {
471 int cpu = ARRAY_INDEX(slice_timeouts, t);
472
473 slice_expired[cpu] = true;
474
475 /* We need an IPI if we just handled a timeslice expiration
476 * for a different CPU. Ideally this would be able to target
477 * the specific core, but that's not part of the API yet.
478 */
479 if (IS_ENABLED(CONFIG_SMP) && cpu != _current_cpu->id) {
480 flag_ipi();
481 }
482 }
483
z_reset_time_slice(struct k_thread * curr)484 void z_reset_time_slice(struct k_thread *curr)
485 {
486 int cpu = _current_cpu->id;
487
488 z_abort_timeout(&slice_timeouts[cpu]);
489 slice_expired[cpu] = false;
490 if (sliceable(curr)) {
491 z_add_timeout(&slice_timeouts[cpu], slice_timeout,
492 K_TICKS(slice_time(curr) - 1));
493 }
494 }
495
k_sched_time_slice_set(int32_t slice,int prio)496 void k_sched_time_slice_set(int32_t slice, int prio)
497 {
498 K_SPINLOCK(&sched_spinlock) {
499 slice_ticks = k_ms_to_ticks_ceil32(slice);
500 slice_max_prio = prio;
501 z_reset_time_slice(_current);
502 }
503 }
504
505 #ifdef CONFIG_TIMESLICE_PER_THREAD
k_thread_time_slice_set(struct k_thread * th,int32_t thread_slice_ticks,k_thread_timeslice_fn_t expired,void * data)506 void k_thread_time_slice_set(struct k_thread *th, int32_t thread_slice_ticks,
507 k_thread_timeslice_fn_t expired, void *data)
508 {
509 K_SPINLOCK(&sched_spinlock) {
510 th->base.slice_ticks = thread_slice_ticks;
511 th->base.slice_expired = expired;
512 th->base.slice_data = data;
513 }
514 }
515 #endif
516
517 /* Called out of each timer interrupt */
z_time_slice(void)518 void z_time_slice(void)
519 {
520 k_spinlock_key_t key = k_spin_lock(&sched_spinlock);
521 struct k_thread *curr = _current;
522
523 #ifdef CONFIG_SWAP_NONATOMIC
524 if (pending_current == curr) {
525 z_reset_time_slice(curr);
526 k_spin_unlock(&sched_spinlock, key);
527 return;
528 }
529 pending_current = NULL;
530 #endif
531
532 if (slice_expired[_current_cpu->id] && sliceable(curr)) {
533 #ifdef CONFIG_TIMESLICE_PER_THREAD
534 if (curr->base.slice_expired) {
535 k_spin_unlock(&sched_spinlock, key);
536 curr->base.slice_expired(curr, curr->base.slice_data);
537 key = k_spin_lock(&sched_spinlock);
538 }
539 #endif
540 if (!z_is_thread_prevented_from_running(curr)) {
541 move_thread_to_end_of_prio_q(curr);
542 }
543 z_reset_time_slice(curr);
544 }
545 k_spin_unlock(&sched_spinlock, key);
546 }
547 #endif
548
549 /* Track cooperative threads preempted by metairqs so we can return to
550 * them specifically. Called at the moment a new thread has been
551 * selected to run.
552 */
update_metairq_preempt(struct k_thread * thread)553 static void update_metairq_preempt(struct k_thread *thread)
554 {
555 #if (CONFIG_NUM_METAIRQ_PRIORITIES > 0) && \
556 (CONFIG_NUM_COOP_PRIORITIES > CONFIG_NUM_METAIRQ_PRIORITIES)
557 if (is_metairq(thread) && !is_metairq(_current) &&
558 !is_preempt(_current)) {
559 /* Record new preemption */
560 _current_cpu->metairq_preempted = _current;
561 } else if (!is_metairq(thread) && !z_is_idle_thread_object(thread)) {
562 /* Returning from existing preemption */
563 _current_cpu->metairq_preempted = NULL;
564 }
565 #else
566 ARG_UNUSED(thread);
567 #endif
568 }
569
update_cache(int preempt_ok)570 static void update_cache(int preempt_ok)
571 {
572 #ifndef CONFIG_SMP
573 struct k_thread *thread = next_up();
574
575 if (should_preempt(thread, preempt_ok)) {
576 #ifdef CONFIG_TIMESLICING
577 if (thread != _current) {
578 z_reset_time_slice(thread);
579 }
580 #endif
581 update_metairq_preempt(thread);
582 _kernel.ready_q.cache = thread;
583 } else {
584 _kernel.ready_q.cache = _current;
585 }
586
587 #else
588 /* The way this works is that the CPU record keeps its
589 * "cooperative swapping is OK" flag until the next reschedule
590 * call or context switch. It doesn't need to be tracked per
591 * thread because if the thread gets preempted for whatever
592 * reason the scheduler will make the same decision anyway.
593 */
594 _current_cpu->swap_ok = preempt_ok;
595 #endif
596 }
597
thread_active_elsewhere(struct k_thread * thread)598 static bool thread_active_elsewhere(struct k_thread *thread)
599 {
600 /* True if the thread is currently running on another CPU.
601 * There are more scalable designs to answer this question in
602 * constant time, but this is fine for now.
603 */
604 #ifdef CONFIG_SMP
605 int currcpu = _current_cpu->id;
606
607 unsigned int num_cpus = arch_num_cpus();
608
609 for (int i = 0; i < num_cpus; i++) {
610 if ((i != currcpu) &&
611 (_kernel.cpus[i].current == thread)) {
612 return true;
613 }
614 }
615 #endif
616 ARG_UNUSED(thread);
617 return false;
618 }
619
ready_thread(struct k_thread * thread)620 static void ready_thread(struct k_thread *thread)
621 {
622 #ifdef CONFIG_KERNEL_COHERENCE
623 __ASSERT_NO_MSG(arch_mem_coherent(thread));
624 #endif
625
626 /* If thread is queued already, do not try and added it to the
627 * run queue again
628 */
629 if (!z_is_thread_queued(thread) && z_is_thread_ready(thread)) {
630 SYS_PORT_TRACING_OBJ_FUNC(k_thread, sched_ready, thread);
631
632 queue_thread(thread);
633 update_cache(0);
634 flag_ipi();
635 }
636 }
637
z_ready_thread(struct k_thread * thread)638 void z_ready_thread(struct k_thread *thread)
639 {
640 K_SPINLOCK(&sched_spinlock) {
641 if (!thread_active_elsewhere(thread)) {
642 ready_thread(thread);
643 }
644 }
645 }
646
z_move_thread_to_end_of_prio_q(struct k_thread * thread)647 void z_move_thread_to_end_of_prio_q(struct k_thread *thread)
648 {
649 K_SPINLOCK(&sched_spinlock) {
650 move_thread_to_end_of_prio_q(thread);
651 }
652 }
653
z_sched_start(struct k_thread * thread)654 void z_sched_start(struct k_thread *thread)
655 {
656 k_spinlock_key_t key = k_spin_lock(&sched_spinlock);
657
658 if (z_has_thread_started(thread)) {
659 k_spin_unlock(&sched_spinlock, key);
660 return;
661 }
662
663 z_mark_thread_as_started(thread);
664 ready_thread(thread);
665 z_reschedule(&sched_spinlock, key);
666 }
667
z_impl_k_thread_suspend(struct k_thread * thread)668 void z_impl_k_thread_suspend(struct k_thread *thread)
669 {
670 SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_thread, suspend, thread);
671
672 (void)z_abort_thread_timeout(thread);
673
674 K_SPINLOCK(&sched_spinlock) {
675 if (z_is_thread_queued(thread)) {
676 dequeue_thread(thread);
677 }
678 z_mark_thread_as_suspended(thread);
679 update_cache(thread == _current);
680 }
681
682 if (thread == _current) {
683 z_reschedule_unlocked();
684 }
685
686 SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_thread, suspend, thread);
687 }
688
689 #ifdef CONFIG_USERSPACE
z_vrfy_k_thread_suspend(struct k_thread * thread)690 static inline void z_vrfy_k_thread_suspend(struct k_thread *thread)
691 {
692 Z_OOPS(Z_SYSCALL_OBJ(thread, K_OBJ_THREAD));
693 z_impl_k_thread_suspend(thread);
694 }
695 #include <syscalls/k_thread_suspend_mrsh.c>
696 #endif
697
z_impl_k_thread_resume(struct k_thread * thread)698 void z_impl_k_thread_resume(struct k_thread *thread)
699 {
700 SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_thread, resume, thread);
701
702 k_spinlock_key_t key = k_spin_lock(&sched_spinlock);
703
704 /* Do not try to resume a thread that was not suspended */
705 if (!z_is_thread_suspended(thread)) {
706 k_spin_unlock(&sched_spinlock, key);
707 return;
708 }
709
710 z_mark_thread_as_not_suspended(thread);
711 ready_thread(thread);
712
713 z_reschedule(&sched_spinlock, key);
714
715 SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_thread, resume, thread);
716 }
717
718 #ifdef CONFIG_USERSPACE
z_vrfy_k_thread_resume(struct k_thread * thread)719 static inline void z_vrfy_k_thread_resume(struct k_thread *thread)
720 {
721 Z_OOPS(Z_SYSCALL_OBJ(thread, K_OBJ_THREAD));
722 z_impl_k_thread_resume(thread);
723 }
724 #include <syscalls/k_thread_resume_mrsh.c>
725 #endif
726
pended_on_thread(struct k_thread * thread)727 static _wait_q_t *pended_on_thread(struct k_thread *thread)
728 {
729 __ASSERT_NO_MSG(thread->base.pended_on);
730
731 return thread->base.pended_on;
732 }
733
unready_thread(struct k_thread * thread)734 static void unready_thread(struct k_thread *thread)
735 {
736 if (z_is_thread_queued(thread)) {
737 dequeue_thread(thread);
738 }
739 update_cache(thread == _current);
740 }
741
742 /* sched_spinlock must be held */
add_to_waitq_locked(struct k_thread * thread,_wait_q_t * wait_q)743 static void add_to_waitq_locked(struct k_thread *thread, _wait_q_t *wait_q)
744 {
745 unready_thread(thread);
746 z_mark_thread_as_pending(thread);
747
748 SYS_PORT_TRACING_FUNC(k_thread, sched_pend, thread);
749
750 if (wait_q != NULL) {
751 thread->base.pended_on = wait_q;
752 z_priq_wait_add(&wait_q->waitq, thread);
753 }
754 }
755
add_thread_timeout(struct k_thread * thread,k_timeout_t timeout)756 static void add_thread_timeout(struct k_thread *thread, k_timeout_t timeout)
757 {
758 if (!K_TIMEOUT_EQ(timeout, K_FOREVER)) {
759 z_add_thread_timeout(thread, timeout);
760 }
761 }
762
pend_locked(struct k_thread * thread,_wait_q_t * wait_q,k_timeout_t timeout)763 static void pend_locked(struct k_thread *thread, _wait_q_t *wait_q,
764 k_timeout_t timeout)
765 {
766 #ifdef CONFIG_KERNEL_COHERENCE
767 __ASSERT_NO_MSG(wait_q == NULL || arch_mem_coherent(wait_q));
768 #endif
769 add_to_waitq_locked(thread, wait_q);
770 add_thread_timeout(thread, timeout);
771 }
772
z_pend_thread(struct k_thread * thread,_wait_q_t * wait_q,k_timeout_t timeout)773 void z_pend_thread(struct k_thread *thread, _wait_q_t *wait_q,
774 k_timeout_t timeout)
775 {
776 __ASSERT_NO_MSG(thread == _current || is_thread_dummy(thread));
777 K_SPINLOCK(&sched_spinlock) {
778 pend_locked(thread, wait_q, timeout);
779 }
780 }
781
unpend_thread_no_timeout(struct k_thread * thread)782 static inline void unpend_thread_no_timeout(struct k_thread *thread)
783 {
784 _priq_wait_remove(&pended_on_thread(thread)->waitq, thread);
785 z_mark_thread_as_not_pending(thread);
786 thread->base.pended_on = NULL;
787 }
788
z_unpend_thread_no_timeout(struct k_thread * thread)789 ALWAYS_INLINE void z_unpend_thread_no_timeout(struct k_thread *thread)
790 {
791 K_SPINLOCK(&sched_spinlock) {
792 if (thread->base.pended_on != NULL) {
793 unpend_thread_no_timeout(thread);
794 }
795 }
796 }
797
z_sched_wake_thread(struct k_thread * thread,bool is_timeout)798 void z_sched_wake_thread(struct k_thread *thread, bool is_timeout)
799 {
800 K_SPINLOCK(&sched_spinlock) {
801 bool killed = ((thread->base.thread_state & _THREAD_DEAD) ||
802 (thread->base.thread_state & _THREAD_ABORTING));
803
804 #ifdef CONFIG_EVENTS
805 bool do_nothing = thread->no_wake_on_timeout && is_timeout;
806
807 thread->no_wake_on_timeout = false;
808
809 if (do_nothing) {
810 continue;
811 }
812 #endif
813
814 if (!killed) {
815 /* The thread is not being killed */
816 if (thread->base.pended_on != NULL) {
817 unpend_thread_no_timeout(thread);
818 }
819 z_mark_thread_as_started(thread);
820 if (is_timeout) {
821 z_mark_thread_as_not_suspended(thread);
822 }
823 ready_thread(thread);
824 }
825 }
826
827 }
828
829 #ifdef CONFIG_SYS_CLOCK_EXISTS
830 /* Timeout handler for *_thread_timeout() APIs */
z_thread_timeout(struct _timeout * timeout)831 void z_thread_timeout(struct _timeout *timeout)
832 {
833 struct k_thread *thread = CONTAINER_OF(timeout,
834 struct k_thread, base.timeout);
835
836 z_sched_wake_thread(thread, true);
837 }
838 #endif
839
z_pend_curr_irqlock(uint32_t key,_wait_q_t * wait_q,k_timeout_t timeout)840 int z_pend_curr_irqlock(uint32_t key, _wait_q_t *wait_q, k_timeout_t timeout)
841 {
842 /* This is a legacy API for pre-switch architectures and isn't
843 * correctly synchronized for multi-cpu use
844 */
845 __ASSERT_NO_MSG(!IS_ENABLED(CONFIG_SMP));
846
847 pend_locked(_current, wait_q, timeout);
848
849 #if defined(CONFIG_TIMESLICING) && defined(CONFIG_SWAP_NONATOMIC)
850 pending_current = _current;
851
852 int ret = z_swap_irqlock(key);
853 K_SPINLOCK(&sched_spinlock) {
854 if (pending_current == _current) {
855 pending_current = NULL;
856 }
857 }
858 return ret;
859 #else
860 return z_swap_irqlock(key);
861 #endif
862 }
863
z_pend_curr(struct k_spinlock * lock,k_spinlock_key_t key,_wait_q_t * wait_q,k_timeout_t timeout)864 int z_pend_curr(struct k_spinlock *lock, k_spinlock_key_t key,
865 _wait_q_t *wait_q, k_timeout_t timeout)
866 {
867 #if defined(CONFIG_TIMESLICING) && defined(CONFIG_SWAP_NONATOMIC)
868 pending_current = _current;
869 #endif
870 __ASSERT_NO_MSG(sizeof(sched_spinlock) == 0 || lock != &sched_spinlock);
871
872 /* We do a "lock swap" prior to calling z_swap(), such that
873 * the caller's lock gets released as desired. But we ensure
874 * that we hold the scheduler lock and leave local interrupts
875 * masked until we reach the context swich. z_swap() itself
876 * has similar code; the duplication is because it's a legacy
877 * API that doesn't expect to be called with scheduler lock
878 * held.
879 */
880 (void) k_spin_lock(&sched_spinlock);
881 pend_locked(_current, wait_q, timeout);
882 k_spin_release(lock);
883 return z_swap(&sched_spinlock, key);
884 }
885
z_unpend1_no_timeout(_wait_q_t * wait_q)886 struct k_thread *z_unpend1_no_timeout(_wait_q_t *wait_q)
887 {
888 struct k_thread *thread = NULL;
889
890 K_SPINLOCK(&sched_spinlock) {
891 thread = _priq_wait_best(&wait_q->waitq);
892
893 if (thread != NULL) {
894 unpend_thread_no_timeout(thread);
895 }
896 }
897
898 return thread;
899 }
900
z_unpend_first_thread(_wait_q_t * wait_q)901 struct k_thread *z_unpend_first_thread(_wait_q_t *wait_q)
902 {
903 struct k_thread *thread = NULL;
904
905 K_SPINLOCK(&sched_spinlock) {
906 thread = _priq_wait_best(&wait_q->waitq);
907
908 if (thread != NULL) {
909 unpend_thread_no_timeout(thread);
910 (void)z_abort_thread_timeout(thread);
911 }
912 }
913
914 return thread;
915 }
916
z_unpend_thread(struct k_thread * thread)917 void z_unpend_thread(struct k_thread *thread)
918 {
919 z_unpend_thread_no_timeout(thread);
920 (void)z_abort_thread_timeout(thread);
921 }
922
923 /* Priority set utility that does no rescheduling, it just changes the
924 * run queue state, returning true if a reschedule is needed later.
925 */
z_set_prio(struct k_thread * thread,int prio)926 bool z_set_prio(struct k_thread *thread, int prio)
927 {
928 bool need_sched = 0;
929
930 K_SPINLOCK(&sched_spinlock) {
931 need_sched = z_is_thread_ready(thread);
932
933 if (need_sched) {
934 /* Don't requeue on SMP if it's the running thread */
935 if (!IS_ENABLED(CONFIG_SMP) || z_is_thread_queued(thread)) {
936 dequeue_thread(thread);
937 thread->base.prio = prio;
938 queue_thread(thread);
939 } else {
940 thread->base.prio = prio;
941 }
942 update_cache(1);
943 } else {
944 thread->base.prio = prio;
945 }
946 }
947
948 SYS_PORT_TRACING_OBJ_FUNC(k_thread, sched_priority_set, thread, prio);
949
950 return need_sched;
951 }
952
z_thread_priority_set(struct k_thread * thread,int prio)953 void z_thread_priority_set(struct k_thread *thread, int prio)
954 {
955 bool need_sched = z_set_prio(thread, prio);
956
957 flag_ipi();
958
959 if (need_sched && _current->base.sched_locked == 0U) {
960 z_reschedule_unlocked();
961 }
962 }
963
resched(uint32_t key)964 static inline bool resched(uint32_t key)
965 {
966 #ifdef CONFIG_SMP
967 _current_cpu->swap_ok = 0;
968 #endif
969
970 return arch_irq_unlocked(key) && !arch_is_in_isr();
971 }
972
973 /*
974 * Check if the next ready thread is the same as the current thread
975 * and save the trip if true.
976 */
need_swap(void)977 static inline bool need_swap(void)
978 {
979 /* the SMP case will be handled in C based z_swap() */
980 #ifdef CONFIG_SMP
981 return true;
982 #else
983 struct k_thread *new_thread;
984
985 /* Check if the next ready thread is the same as the current thread */
986 new_thread = _kernel.ready_q.cache;
987 return new_thread != _current;
988 #endif
989 }
990
z_reschedule(struct k_spinlock * lock,k_spinlock_key_t key)991 void z_reschedule(struct k_spinlock *lock, k_spinlock_key_t key)
992 {
993 if (resched(key.key) && need_swap()) {
994 z_swap(lock, key);
995 } else {
996 k_spin_unlock(lock, key);
997 signal_pending_ipi();
998 }
999 }
1000
z_reschedule_irqlock(uint32_t key)1001 void z_reschedule_irqlock(uint32_t key)
1002 {
1003 if (resched(key)) {
1004 z_swap_irqlock(key);
1005 } else {
1006 irq_unlock(key);
1007 signal_pending_ipi();
1008 }
1009 }
1010
k_sched_lock(void)1011 void k_sched_lock(void)
1012 {
1013 K_SPINLOCK(&sched_spinlock) {
1014 SYS_PORT_TRACING_FUNC(k_thread, sched_lock);
1015
1016 z_sched_lock();
1017 }
1018 }
1019
k_sched_unlock(void)1020 void k_sched_unlock(void)
1021 {
1022 K_SPINLOCK(&sched_spinlock) {
1023 __ASSERT(_current->base.sched_locked != 0U, "");
1024 __ASSERT(!arch_is_in_isr(), "");
1025
1026 ++_current->base.sched_locked;
1027 update_cache(0);
1028 }
1029
1030 LOG_DBG("scheduler unlocked (%p:%d)",
1031 _current, _current->base.sched_locked);
1032
1033 SYS_PORT_TRACING_FUNC(k_thread, sched_unlock);
1034
1035 z_reschedule_unlocked();
1036 }
1037
z_swap_next_thread(void)1038 struct k_thread *z_swap_next_thread(void)
1039 {
1040 #ifdef CONFIG_SMP
1041 struct k_thread *ret = next_up();
1042
1043 if (ret == _current) {
1044 /* When not swapping, have to signal IPIs here. In
1045 * the context switch case it must happen later, after
1046 * _current gets requeued.
1047 */
1048 signal_pending_ipi();
1049 }
1050 return ret;
1051 #else
1052 return _kernel.ready_q.cache;
1053 #endif
1054 }
1055
1056 #ifdef CONFIG_USE_SWITCH
1057 /* Just a wrapper around _current = xxx with tracing */
set_current(struct k_thread * new_thread)1058 static inline void set_current(struct k_thread *new_thread)
1059 {
1060 z_thread_mark_switched_out();
1061 _current_cpu->current = new_thread;
1062 }
1063
1064 /**
1065 * @brief Determine next thread to execute upon completion of an interrupt
1066 *
1067 * Thread preemption is performed by context switching after the completion
1068 * of a non-recursed interrupt. This function determines which thread to
1069 * switch to if any. This function accepts as @p interrupted either:
1070 *
1071 * - The handle for the interrupted thread in which case the thread's context
1072 * must already be fully saved and ready to be picked up by a different CPU.
1073 *
1074 * - NULL if more work is required to fully save the thread's state after
1075 * it is known that a new thread is to be scheduled. It is up to the caller
1076 * to store the handle resulting from the thread that is being switched out
1077 * in that thread's "switch_handle" field after its
1078 * context has fully been saved, following the same requirements as with
1079 * the @ref arch_switch() function.
1080 *
1081 * If a new thread needs to be scheduled then its handle is returned.
1082 * Otherwise the same value provided as @p interrupted is returned back.
1083 * Those handles are the same opaque types used by the @ref arch_switch()
1084 * function.
1085 *
1086 * @warning
1087 * The @ref _current value may have changed after this call and not refer
1088 * to the interrupted thread anymore. It might be necessary to make a local
1089 * copy before calling this function.
1090 *
1091 * @param interrupted Handle for the thread that was interrupted or NULL.
1092 * @retval Handle for the next thread to execute, or @p interrupted when
1093 * no new thread is to be scheduled.
1094 */
z_get_next_switch_handle(void * interrupted)1095 void *z_get_next_switch_handle(void *interrupted)
1096 {
1097 z_check_stack_sentinel();
1098
1099 #ifdef CONFIG_SMP
1100 void *ret = NULL;
1101
1102 K_SPINLOCK(&sched_spinlock) {
1103 struct k_thread *old_thread = _current, *new_thread;
1104
1105 if (IS_ENABLED(CONFIG_SMP)) {
1106 old_thread->switch_handle = NULL;
1107 }
1108 new_thread = next_up();
1109
1110 z_sched_usage_switch(new_thread);
1111
1112 if (old_thread != new_thread) {
1113 update_metairq_preempt(new_thread);
1114 z_sched_switch_spin(new_thread);
1115 arch_cohere_stacks(old_thread, interrupted, new_thread);
1116
1117 _current_cpu->swap_ok = 0;
1118 set_current(new_thread);
1119
1120 #ifdef CONFIG_TIMESLICING
1121 z_reset_time_slice(new_thread);
1122 #endif
1123
1124 #ifdef CONFIG_SPIN_VALIDATE
1125 /* Changed _current! Update the spinlock
1126 * bookkeeping so the validation doesn't get
1127 * confused when the "wrong" thread tries to
1128 * release the lock.
1129 */
1130 z_spin_lock_set_owner(&sched_spinlock);
1131 #endif
1132
1133 /* A queued (runnable) old/current thread
1134 * needs to be added back to the run queue
1135 * here, and atomically with its switch handle
1136 * being set below. This is safe now, as we
1137 * will not return into it.
1138 */
1139 if (z_is_thread_queued(old_thread)) {
1140 runq_add(old_thread);
1141 }
1142 }
1143 old_thread->switch_handle = interrupted;
1144 ret = new_thread->switch_handle;
1145 if (IS_ENABLED(CONFIG_SMP)) {
1146 /* Active threads MUST have a null here */
1147 new_thread->switch_handle = NULL;
1148 }
1149 }
1150 signal_pending_ipi();
1151 return ret;
1152 #else
1153 z_sched_usage_switch(_kernel.ready_q.cache);
1154 _current->switch_handle = interrupted;
1155 set_current(_kernel.ready_q.cache);
1156 return _current->switch_handle;
1157 #endif
1158 }
1159 #endif
1160
z_priq_dumb_remove(sys_dlist_t * pq,struct k_thread * thread)1161 void z_priq_dumb_remove(sys_dlist_t *pq, struct k_thread *thread)
1162 {
1163 ARG_UNUSED(pq);
1164
1165 __ASSERT_NO_MSG(!z_is_idle_thread_object(thread));
1166
1167 sys_dlist_remove(&thread->base.qnode_dlist);
1168 }
1169
z_priq_dumb_best(sys_dlist_t * pq)1170 struct k_thread *z_priq_dumb_best(sys_dlist_t *pq)
1171 {
1172 struct k_thread *thread = NULL;
1173 sys_dnode_t *n = sys_dlist_peek_head(pq);
1174
1175 if (n != NULL) {
1176 thread = CONTAINER_OF(n, struct k_thread, base.qnode_dlist);
1177 }
1178 return thread;
1179 }
1180
z_priq_rb_lessthan(struct rbnode * a,struct rbnode * b)1181 bool z_priq_rb_lessthan(struct rbnode *a, struct rbnode *b)
1182 {
1183 struct k_thread *thread_a, *thread_b;
1184 int32_t cmp;
1185
1186 thread_a = CONTAINER_OF(a, struct k_thread, base.qnode_rb);
1187 thread_b = CONTAINER_OF(b, struct k_thread, base.qnode_rb);
1188
1189 cmp = z_sched_prio_cmp(thread_a, thread_b);
1190
1191 if (cmp > 0) {
1192 return true;
1193 } else if (cmp < 0) {
1194 return false;
1195 } else {
1196 return thread_a->base.order_key < thread_b->base.order_key
1197 ? 1 : 0;
1198 }
1199 }
1200
z_priq_rb_add(struct _priq_rb * pq,struct k_thread * thread)1201 void z_priq_rb_add(struct _priq_rb *pq, struct k_thread *thread)
1202 {
1203 struct k_thread *t;
1204
1205 __ASSERT_NO_MSG(!z_is_idle_thread_object(thread));
1206
1207 thread->base.order_key = pq->next_order_key++;
1208
1209 /* Renumber at wraparound. This is tiny code, and in practice
1210 * will almost never be hit on real systems. BUT on very
1211 * long-running systems where a priq never completely empties
1212 * AND that contains very large numbers of threads, it can be
1213 * a latency glitch to loop over all the threads like this.
1214 */
1215 if (!pq->next_order_key) {
1216 RB_FOR_EACH_CONTAINER(&pq->tree, t, base.qnode_rb) {
1217 t->base.order_key = pq->next_order_key++;
1218 }
1219 }
1220
1221 rb_insert(&pq->tree, &thread->base.qnode_rb);
1222 }
1223
z_priq_rb_remove(struct _priq_rb * pq,struct k_thread * thread)1224 void z_priq_rb_remove(struct _priq_rb *pq, struct k_thread *thread)
1225 {
1226 __ASSERT_NO_MSG(!z_is_idle_thread_object(thread));
1227
1228 rb_remove(&pq->tree, &thread->base.qnode_rb);
1229
1230 if (!pq->tree.root) {
1231 pq->next_order_key = 0;
1232 }
1233 }
1234
z_priq_rb_best(struct _priq_rb * pq)1235 struct k_thread *z_priq_rb_best(struct _priq_rb *pq)
1236 {
1237 struct k_thread *thread = NULL;
1238 struct rbnode *n = rb_get_min(&pq->tree);
1239
1240 if (n != NULL) {
1241 thread = CONTAINER_OF(n, struct k_thread, base.qnode_rb);
1242 }
1243 return thread;
1244 }
1245
1246 #ifdef CONFIG_SCHED_MULTIQ
1247 # if (K_LOWEST_THREAD_PRIO - K_HIGHEST_THREAD_PRIO) > 31
1248 # error Too many priorities for multiqueue scheduler (max 32)
1249 # endif
1250
z_priq_mq_add(struct _priq_mq * pq,struct k_thread * thread)1251 static ALWAYS_INLINE void z_priq_mq_add(struct _priq_mq *pq,
1252 struct k_thread *thread)
1253 {
1254 int priority_bit = thread->base.prio - K_HIGHEST_THREAD_PRIO;
1255
1256 sys_dlist_append(&pq->queues[priority_bit], &thread->base.qnode_dlist);
1257 pq->bitmask |= BIT(priority_bit);
1258 }
1259
z_priq_mq_remove(struct _priq_mq * pq,struct k_thread * thread)1260 static ALWAYS_INLINE void z_priq_mq_remove(struct _priq_mq *pq,
1261 struct k_thread *thread)
1262 {
1263 int priority_bit = thread->base.prio - K_HIGHEST_THREAD_PRIO;
1264
1265 sys_dlist_remove(&thread->base.qnode_dlist);
1266 if (sys_dlist_is_empty(&pq->queues[priority_bit])) {
1267 pq->bitmask &= ~BIT(priority_bit);
1268 }
1269 }
1270 #endif
1271
z_priq_mq_best(struct _priq_mq * pq)1272 struct k_thread *z_priq_mq_best(struct _priq_mq *pq)
1273 {
1274 if (!pq->bitmask) {
1275 return NULL;
1276 }
1277
1278 struct k_thread *thread = NULL;
1279 sys_dlist_t *l = &pq->queues[__builtin_ctz(pq->bitmask)];
1280 sys_dnode_t *n = sys_dlist_peek_head(l);
1281
1282 if (n != NULL) {
1283 thread = CONTAINER_OF(n, struct k_thread, base.qnode_dlist);
1284 }
1285 return thread;
1286 }
1287
z_unpend_all(_wait_q_t * wait_q)1288 int z_unpend_all(_wait_q_t *wait_q)
1289 {
1290 int need_sched = 0;
1291 struct k_thread *thread;
1292
1293 while ((thread = z_waitq_head(wait_q)) != NULL) {
1294 z_unpend_thread(thread);
1295 z_ready_thread(thread);
1296 need_sched = 1;
1297 }
1298
1299 return need_sched;
1300 }
1301
init_ready_q(struct _ready_q * rq)1302 void init_ready_q(struct _ready_q *rq)
1303 {
1304 #if defined(CONFIG_SCHED_SCALABLE)
1305 rq->runq = (struct _priq_rb) {
1306 .tree = {
1307 .lessthan_fn = z_priq_rb_lessthan,
1308 }
1309 };
1310 #elif defined(CONFIG_SCHED_MULTIQ)
1311 for (int i = 0; i < ARRAY_SIZE(_kernel.ready_q.runq.queues); i++) {
1312 sys_dlist_init(&rq->runq.queues[i]);
1313 }
1314 #else
1315 sys_dlist_init(&rq->runq);
1316 #endif
1317 }
1318
z_sched_init(void)1319 void z_sched_init(void)
1320 {
1321 #ifdef CONFIG_SCHED_CPU_MASK_PIN_ONLY
1322 for (int i = 0; i < CONFIG_MP_MAX_NUM_CPUS; i++) {
1323 init_ready_q(&_kernel.cpus[i].ready_q);
1324 }
1325 #else
1326 init_ready_q(&_kernel.ready_q);
1327 #endif
1328 }
1329
z_impl_k_thread_priority_get(k_tid_t thread)1330 int z_impl_k_thread_priority_get(k_tid_t thread)
1331 {
1332 return thread->base.prio;
1333 }
1334
1335 #ifdef CONFIG_USERSPACE
z_vrfy_k_thread_priority_get(k_tid_t thread)1336 static inline int z_vrfy_k_thread_priority_get(k_tid_t thread)
1337 {
1338 Z_OOPS(Z_SYSCALL_OBJ(thread, K_OBJ_THREAD));
1339 return z_impl_k_thread_priority_get(thread);
1340 }
1341 #include <syscalls/k_thread_priority_get_mrsh.c>
1342 #endif
1343
z_impl_k_thread_priority_set(k_tid_t thread,int prio)1344 void z_impl_k_thread_priority_set(k_tid_t thread, int prio)
1345 {
1346 /*
1347 * Use NULL, since we cannot know what the entry point is (we do not
1348 * keep track of it) and idle cannot change its priority.
1349 */
1350 Z_ASSERT_VALID_PRIO(prio, NULL);
1351 __ASSERT(!arch_is_in_isr(), "");
1352
1353 struct k_thread *th = (struct k_thread *)thread;
1354
1355 z_thread_priority_set(th, prio);
1356 }
1357
1358 #ifdef CONFIG_USERSPACE
z_vrfy_k_thread_priority_set(k_tid_t thread,int prio)1359 static inline void z_vrfy_k_thread_priority_set(k_tid_t thread, int prio)
1360 {
1361 Z_OOPS(Z_SYSCALL_OBJ(thread, K_OBJ_THREAD));
1362 Z_OOPS(Z_SYSCALL_VERIFY_MSG(_is_valid_prio(prio, NULL),
1363 "invalid thread priority %d", prio));
1364 Z_OOPS(Z_SYSCALL_VERIFY_MSG((int8_t)prio >= thread->base.prio,
1365 "thread priority may only be downgraded (%d < %d)",
1366 prio, thread->base.prio));
1367
1368 z_impl_k_thread_priority_set(thread, prio);
1369 }
1370 #include <syscalls/k_thread_priority_set_mrsh.c>
1371 #endif
1372
1373 #ifdef CONFIG_SCHED_DEADLINE
z_impl_k_thread_deadline_set(k_tid_t tid,int deadline)1374 void z_impl_k_thread_deadline_set(k_tid_t tid, int deadline)
1375 {
1376 struct k_thread *thread = tid;
1377
1378 K_SPINLOCK(&sched_spinlock) {
1379 thread->base.prio_deadline = k_cycle_get_32() + deadline;
1380 if (z_is_thread_queued(thread)) {
1381 dequeue_thread(thread);
1382 queue_thread(thread);
1383 }
1384 }
1385 }
1386
1387 #ifdef CONFIG_USERSPACE
z_vrfy_k_thread_deadline_set(k_tid_t tid,int deadline)1388 static inline void z_vrfy_k_thread_deadline_set(k_tid_t tid, int deadline)
1389 {
1390 struct k_thread *thread = tid;
1391
1392 Z_OOPS(Z_SYSCALL_OBJ(thread, K_OBJ_THREAD));
1393 Z_OOPS(Z_SYSCALL_VERIFY_MSG(deadline > 0,
1394 "invalid thread deadline %d",
1395 (int)deadline));
1396
1397 z_impl_k_thread_deadline_set((k_tid_t)thread, deadline);
1398 }
1399 #include <syscalls/k_thread_deadline_set_mrsh.c>
1400 #endif
1401 #endif
1402
k_can_yield(void)1403 bool k_can_yield(void)
1404 {
1405 return !(k_is_pre_kernel() || k_is_in_isr() ||
1406 z_is_idle_thread_object(_current));
1407 }
1408
z_impl_k_yield(void)1409 void z_impl_k_yield(void)
1410 {
1411 __ASSERT(!arch_is_in_isr(), "");
1412
1413 SYS_PORT_TRACING_FUNC(k_thread, yield);
1414
1415 k_spinlock_key_t key = k_spin_lock(&sched_spinlock);
1416
1417 if (!IS_ENABLED(CONFIG_SMP) ||
1418 z_is_thread_queued(_current)) {
1419 dequeue_thread(_current);
1420 }
1421 queue_thread(_current);
1422 update_cache(1);
1423 z_swap(&sched_spinlock, key);
1424 }
1425
1426 #ifdef CONFIG_USERSPACE
z_vrfy_k_yield(void)1427 static inline void z_vrfy_k_yield(void)
1428 {
1429 z_impl_k_yield();
1430 }
1431 #include <syscalls/k_yield_mrsh.c>
1432 #endif
1433
z_tick_sleep(k_ticks_t ticks)1434 static int32_t z_tick_sleep(k_ticks_t ticks)
1435 {
1436 #ifdef CONFIG_MULTITHREADING
1437 uint32_t expected_wakeup_ticks;
1438
1439 __ASSERT(!arch_is_in_isr(), "");
1440
1441 LOG_DBG("thread %p for %lu ticks", _current, (unsigned long)ticks);
1442
1443 /* wait of 0 ms is treated as a 'yield' */
1444 if (ticks == 0) {
1445 k_yield();
1446 return 0;
1447 }
1448
1449 k_timeout_t timeout = Z_TIMEOUT_TICKS(ticks);
1450 if (Z_TICK_ABS(ticks) <= 0) {
1451 expected_wakeup_ticks = ticks + sys_clock_tick_get_32();
1452 } else {
1453 expected_wakeup_ticks = Z_TICK_ABS(ticks);
1454 }
1455
1456 k_spinlock_key_t key = k_spin_lock(&sched_spinlock);
1457
1458 #if defined(CONFIG_TIMESLICING) && defined(CONFIG_SWAP_NONATOMIC)
1459 pending_current = _current;
1460 #endif
1461 unready_thread(_current);
1462 z_add_thread_timeout(_current, timeout);
1463 z_mark_thread_as_suspended(_current);
1464
1465 (void)z_swap(&sched_spinlock, key);
1466
1467 __ASSERT(!z_is_thread_state_set(_current, _THREAD_SUSPENDED), "");
1468
1469 ticks = (k_ticks_t)expected_wakeup_ticks - sys_clock_tick_get_32();
1470 if (ticks > 0) {
1471 return ticks;
1472 }
1473 #endif
1474
1475 return 0;
1476 }
1477
z_impl_k_sleep(k_timeout_t timeout)1478 int32_t z_impl_k_sleep(k_timeout_t timeout)
1479 {
1480 k_ticks_t ticks;
1481
1482 __ASSERT(!arch_is_in_isr(), "");
1483
1484 SYS_PORT_TRACING_FUNC_ENTER(k_thread, sleep, timeout);
1485
1486 /* in case of K_FOREVER, we suspend */
1487 if (K_TIMEOUT_EQ(timeout, K_FOREVER)) {
1488 k_thread_suspend(_current);
1489
1490 SYS_PORT_TRACING_FUNC_EXIT(k_thread, sleep, timeout, (int32_t) K_TICKS_FOREVER);
1491
1492 return (int32_t) K_TICKS_FOREVER;
1493 }
1494
1495 ticks = timeout.ticks;
1496
1497 ticks = z_tick_sleep(ticks);
1498
1499 int32_t ret = k_ticks_to_ms_floor64(ticks);
1500
1501 SYS_PORT_TRACING_FUNC_EXIT(k_thread, sleep, timeout, ret);
1502
1503 return ret;
1504 }
1505
1506 #ifdef CONFIG_USERSPACE
z_vrfy_k_sleep(k_timeout_t timeout)1507 static inline int32_t z_vrfy_k_sleep(k_timeout_t timeout)
1508 {
1509 return z_impl_k_sleep(timeout);
1510 }
1511 #include <syscalls/k_sleep_mrsh.c>
1512 #endif
1513
z_impl_k_usleep(int us)1514 int32_t z_impl_k_usleep(int us)
1515 {
1516 int32_t ticks;
1517
1518 SYS_PORT_TRACING_FUNC_ENTER(k_thread, usleep, us);
1519
1520 ticks = k_us_to_ticks_ceil64(us);
1521 ticks = z_tick_sleep(ticks);
1522
1523 SYS_PORT_TRACING_FUNC_EXIT(k_thread, usleep, us, k_ticks_to_us_floor64(ticks));
1524
1525 return k_ticks_to_us_floor64(ticks);
1526 }
1527
1528 #ifdef CONFIG_USERSPACE
z_vrfy_k_usleep(int us)1529 static inline int32_t z_vrfy_k_usleep(int us)
1530 {
1531 return z_impl_k_usleep(us);
1532 }
1533 #include <syscalls/k_usleep_mrsh.c>
1534 #endif
1535
z_impl_k_wakeup(k_tid_t thread)1536 void z_impl_k_wakeup(k_tid_t thread)
1537 {
1538 SYS_PORT_TRACING_OBJ_FUNC(k_thread, wakeup, thread);
1539
1540 if (z_is_thread_pending(thread)) {
1541 return;
1542 }
1543
1544 if (z_abort_thread_timeout(thread) < 0) {
1545 /* Might have just been sleeping forever */
1546 if (thread->base.thread_state != _THREAD_SUSPENDED) {
1547 return;
1548 }
1549 }
1550
1551 z_mark_thread_as_not_suspended(thread);
1552 z_ready_thread(thread);
1553
1554 flag_ipi();
1555
1556 if (!arch_is_in_isr()) {
1557 z_reschedule_unlocked();
1558 }
1559 }
1560
1561 #ifdef CONFIG_TRACE_SCHED_IPI
1562 extern void z_trace_sched_ipi(void);
1563 #endif
1564
1565 #ifdef CONFIG_SMP
z_sched_ipi(void)1566 void z_sched_ipi(void)
1567 {
1568 /* NOTE: When adding code to this, make sure this is called
1569 * at appropriate location when !CONFIG_SCHED_IPI_SUPPORTED.
1570 */
1571 #ifdef CONFIG_TRACE_SCHED_IPI
1572 z_trace_sched_ipi();
1573 #endif
1574
1575 #ifdef CONFIG_TIMESLICING
1576 if (sliceable(_current)) {
1577 z_time_slice();
1578 }
1579 #endif
1580 }
1581 #endif
1582
1583 #ifdef CONFIG_USERSPACE
z_vrfy_k_wakeup(k_tid_t thread)1584 static inline void z_vrfy_k_wakeup(k_tid_t thread)
1585 {
1586 Z_OOPS(Z_SYSCALL_OBJ(thread, K_OBJ_THREAD));
1587 z_impl_k_wakeup(thread);
1588 }
1589 #include <syscalls/k_wakeup_mrsh.c>
1590 #endif
1591
z_impl_k_sched_current_thread_query(void)1592 k_tid_t z_impl_k_sched_current_thread_query(void)
1593 {
1594 #ifdef CONFIG_SMP
1595 /* In SMP, _current is a field read from _current_cpu, which
1596 * can race with preemption before it is read. We must lock
1597 * local interrupts when reading it.
1598 */
1599 unsigned int k = arch_irq_lock();
1600 #endif
1601
1602 k_tid_t ret = _current_cpu->current;
1603
1604 #ifdef CONFIG_SMP
1605 arch_irq_unlock(k);
1606 #endif
1607 return ret;
1608 }
1609
1610 #ifdef CONFIG_USERSPACE
z_vrfy_k_sched_current_thread_query(void)1611 static inline k_tid_t z_vrfy_k_sched_current_thread_query(void)
1612 {
1613 return z_impl_k_sched_current_thread_query();
1614 }
1615 #include <syscalls/k_sched_current_thread_query_mrsh.c>
1616 #endif
1617
z_impl_k_is_preempt_thread(void)1618 int z_impl_k_is_preempt_thread(void)
1619 {
1620 return !arch_is_in_isr() && is_preempt(_current);
1621 }
1622
1623 #ifdef CONFIG_USERSPACE
z_vrfy_k_is_preempt_thread(void)1624 static inline int z_vrfy_k_is_preempt_thread(void)
1625 {
1626 return z_impl_k_is_preempt_thread();
1627 }
1628 #include <syscalls/k_is_preempt_thread_mrsh.c>
1629 #endif
1630
1631 #ifdef CONFIG_SCHED_CPU_MASK
1632 # ifdef CONFIG_SMP
1633 /* Right now we use a two byte for this mask */
1634 BUILD_ASSERT(CONFIG_MP_MAX_NUM_CPUS <= 16, "Too many CPUs for mask word");
1635 # endif
1636
1637
cpu_mask_mod(k_tid_t thread,uint32_t enable_mask,uint32_t disable_mask)1638 static int cpu_mask_mod(k_tid_t thread, uint32_t enable_mask, uint32_t disable_mask)
1639 {
1640 int ret = 0;
1641
1642 #ifdef CONFIG_SCHED_CPU_MASK_PIN_ONLY
1643 __ASSERT(z_is_thread_prevented_from_running(thread),
1644 "Running threads cannot change CPU pin");
1645 #endif
1646
1647 K_SPINLOCK(&sched_spinlock) {
1648 if (z_is_thread_prevented_from_running(thread)) {
1649 thread->base.cpu_mask |= enable_mask;
1650 thread->base.cpu_mask &= ~disable_mask;
1651 } else {
1652 ret = -EINVAL;
1653 }
1654 }
1655
1656 #if defined(CONFIG_ASSERT) && defined(CONFIG_SCHED_CPU_MASK_PIN_ONLY)
1657 int m = thread->base.cpu_mask;
1658
1659 __ASSERT((m == 0) || ((m & (m - 1)) == 0),
1660 "Only one CPU allowed in mask when PIN_ONLY");
1661 #endif
1662
1663 return ret;
1664 }
1665
k_thread_cpu_mask_clear(k_tid_t thread)1666 int k_thread_cpu_mask_clear(k_tid_t thread)
1667 {
1668 return cpu_mask_mod(thread, 0, 0xffffffff);
1669 }
1670
k_thread_cpu_mask_enable_all(k_tid_t thread)1671 int k_thread_cpu_mask_enable_all(k_tid_t thread)
1672 {
1673 return cpu_mask_mod(thread, 0xffffffff, 0);
1674 }
1675
k_thread_cpu_mask_enable(k_tid_t thread,int cpu)1676 int k_thread_cpu_mask_enable(k_tid_t thread, int cpu)
1677 {
1678 return cpu_mask_mod(thread, BIT(cpu), 0);
1679 }
1680
k_thread_cpu_mask_disable(k_tid_t thread,int cpu)1681 int k_thread_cpu_mask_disable(k_tid_t thread, int cpu)
1682 {
1683 return cpu_mask_mod(thread, 0, BIT(cpu));
1684 }
1685
k_thread_cpu_pin(k_tid_t thread,int cpu)1686 int k_thread_cpu_pin(k_tid_t thread, int cpu)
1687 {
1688 int ret;
1689
1690 ret = k_thread_cpu_mask_clear(thread);
1691 if (ret == 0) {
1692 return k_thread_cpu_mask_enable(thread, cpu);
1693 }
1694 return ret;
1695 }
1696
1697 #endif /* CONFIG_SCHED_CPU_MASK */
1698
unpend_all(_wait_q_t * wait_q)1699 static inline void unpend_all(_wait_q_t *wait_q)
1700 {
1701 struct k_thread *thread;
1702
1703 while ((thread = z_waitq_head(wait_q)) != NULL) {
1704 unpend_thread_no_timeout(thread);
1705 (void)z_abort_thread_timeout(thread);
1706 arch_thread_return_value_set(thread, 0);
1707 ready_thread(thread);
1708 }
1709 }
1710
1711 #ifdef CONFIG_CMSIS_RTOS_V1
1712 extern void z_thread_cmsis_status_mask_clear(struct k_thread *thread);
1713 #endif
1714
end_thread(struct k_thread * thread)1715 static void end_thread(struct k_thread *thread)
1716 {
1717 /* We hold the lock, and the thread is known not to be running
1718 * anywhere.
1719 */
1720 if ((thread->base.thread_state & _THREAD_DEAD) == 0U) {
1721 thread->base.thread_state |= _THREAD_DEAD;
1722 thread->base.thread_state &= ~_THREAD_ABORTING;
1723 if (z_is_thread_queued(thread)) {
1724 dequeue_thread(thread);
1725 }
1726 if (thread->base.pended_on != NULL) {
1727 unpend_thread_no_timeout(thread);
1728 }
1729 (void)z_abort_thread_timeout(thread);
1730 unpend_all(&thread->join_queue);
1731 update_cache(1);
1732
1733 #if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING)
1734 arch_float_disable(thread);
1735 #endif
1736
1737 SYS_PORT_TRACING_FUNC(k_thread, sched_abort, thread);
1738
1739 z_thread_monitor_exit(thread);
1740
1741 #ifdef CONFIG_CMSIS_RTOS_V1
1742 z_thread_cmsis_status_mask_clear(thread);
1743 #endif
1744
1745 #ifdef CONFIG_OBJ_CORE_THREAD
1746 #ifdef CONFIG_OBJ_CORE_STATS_THREAD
1747 k_obj_core_stats_deregister(K_OBJ_CORE(thread));
1748 #endif
1749 k_obj_core_unlink(K_OBJ_CORE(thread));
1750 #endif
1751
1752 #ifdef CONFIG_USERSPACE
1753 z_mem_domain_exit_thread(thread);
1754 z_thread_perms_all_clear(thread);
1755 z_object_uninit(thread->stack_obj);
1756 z_object_uninit(thread);
1757 #endif
1758 }
1759 }
1760
z_thread_abort(struct k_thread * thread)1761 void z_thread_abort(struct k_thread *thread)
1762 {
1763 k_spinlock_key_t key = k_spin_lock(&sched_spinlock);
1764
1765 if ((thread->base.user_options & K_ESSENTIAL) != 0) {
1766 k_spin_unlock(&sched_spinlock, key);
1767 __ASSERT(false, "aborting essential thread %p", thread);
1768 k_panic();
1769 return;
1770 }
1771
1772 if ((thread->base.thread_state & _THREAD_DEAD) != 0U) {
1773 k_spin_unlock(&sched_spinlock, key);
1774 return;
1775 }
1776
1777 #ifdef CONFIG_SMP
1778 if (is_aborting(thread) && thread == _current && arch_is_in_isr()) {
1779 /* Another CPU is spinning for us, don't deadlock */
1780 end_thread(thread);
1781 }
1782
1783 bool active = thread_active_elsewhere(thread);
1784
1785 if (active) {
1786 /* It's running somewhere else, flag and poke */
1787 thread->base.thread_state |= _THREAD_ABORTING;
1788
1789 /* We're going to spin, so need a true synchronous IPI
1790 * here, not deferred!
1791 */
1792 #ifdef CONFIG_SCHED_IPI_SUPPORTED
1793 arch_sched_ipi();
1794 #endif
1795 }
1796
1797 if (is_aborting(thread) && thread != _current) {
1798 if (arch_is_in_isr()) {
1799 /* ISRs can only spin waiting another CPU */
1800 k_spin_unlock(&sched_spinlock, key);
1801 while (is_aborting(thread)) {
1802 }
1803
1804 /* Now we know it's dying, but not necessarily
1805 * dead. Wait for the switch to happen!
1806 */
1807 key = k_spin_lock(&sched_spinlock);
1808 z_sched_switch_spin(thread);
1809 k_spin_unlock(&sched_spinlock, key);
1810 } else if (active) {
1811 /* Threads can join */
1812 add_to_waitq_locked(_current, &thread->join_queue);
1813 z_swap(&sched_spinlock, key);
1814 }
1815 return; /* lock has been released */
1816 }
1817 #endif
1818 end_thread(thread);
1819 if (thread == _current && !arch_is_in_isr()) {
1820 z_swap(&sched_spinlock, key);
1821 __ASSERT(false, "aborted _current back from dead");
1822 }
1823 k_spin_unlock(&sched_spinlock, key);
1824 }
1825
1826 #if !defined(CONFIG_ARCH_HAS_THREAD_ABORT)
z_impl_k_thread_abort(struct k_thread * thread)1827 void z_impl_k_thread_abort(struct k_thread *thread)
1828 {
1829 SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_thread, abort, thread);
1830
1831 z_thread_abort(thread);
1832
1833 SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_thread, abort, thread);
1834 }
1835 #endif
1836
z_impl_k_thread_join(struct k_thread * thread,k_timeout_t timeout)1837 int z_impl_k_thread_join(struct k_thread *thread, k_timeout_t timeout)
1838 {
1839 k_spinlock_key_t key = k_spin_lock(&sched_spinlock);
1840 int ret = 0;
1841
1842 SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_thread, join, thread, timeout);
1843
1844 if ((thread->base.thread_state & _THREAD_DEAD) != 0U) {
1845 z_sched_switch_spin(thread);
1846 ret = 0;
1847 } else if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {
1848 ret = -EBUSY;
1849 } else if ((thread == _current) ||
1850 (thread->base.pended_on == &_current->join_queue)) {
1851 ret = -EDEADLK;
1852 } else {
1853 __ASSERT(!arch_is_in_isr(), "cannot join in ISR");
1854 add_to_waitq_locked(_current, &thread->join_queue);
1855 add_thread_timeout(_current, timeout);
1856
1857 SYS_PORT_TRACING_OBJ_FUNC_BLOCKING(k_thread, join, thread, timeout);
1858 ret = z_swap(&sched_spinlock, key);
1859 SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_thread, join, thread, timeout, ret);
1860
1861 return ret;
1862 }
1863
1864 SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_thread, join, thread, timeout, ret);
1865
1866 k_spin_unlock(&sched_spinlock, key);
1867 return ret;
1868 }
1869
1870 #ifdef CONFIG_USERSPACE
1871 /* Special case: don't oops if the thread is uninitialized. This is because
1872 * the initialization bit does double-duty for thread objects; if false, means
1873 * the thread object is truly uninitialized, or the thread ran and exited for
1874 * some reason.
1875 *
1876 * Return true in this case indicating we should just do nothing and return
1877 * success to the caller.
1878 */
thread_obj_validate(struct k_thread * thread)1879 static bool thread_obj_validate(struct k_thread *thread)
1880 {
1881 struct z_object *ko = z_object_find(thread);
1882 int ret = z_object_validate(ko, K_OBJ_THREAD, _OBJ_INIT_TRUE);
1883
1884 switch (ret) {
1885 case 0:
1886 return false;
1887 case -EINVAL:
1888 return true;
1889 default:
1890 #ifdef CONFIG_LOG
1891 z_dump_object_error(ret, thread, ko, K_OBJ_THREAD);
1892 #endif
1893 Z_OOPS(Z_SYSCALL_VERIFY_MSG(ret, "access denied"));
1894 }
1895 CODE_UNREACHABLE; /* LCOV_EXCL_LINE */
1896 }
1897
z_vrfy_k_thread_join(struct k_thread * thread,k_timeout_t timeout)1898 static inline int z_vrfy_k_thread_join(struct k_thread *thread,
1899 k_timeout_t timeout)
1900 {
1901 if (thread_obj_validate(thread)) {
1902 return 0;
1903 }
1904
1905 return z_impl_k_thread_join(thread, timeout);
1906 }
1907 #include <syscalls/k_thread_join_mrsh.c>
1908
z_vrfy_k_thread_abort(k_tid_t thread)1909 static inline void z_vrfy_k_thread_abort(k_tid_t thread)
1910 {
1911 if (thread_obj_validate(thread)) {
1912 return;
1913 }
1914
1915 Z_OOPS(Z_SYSCALL_VERIFY_MSG(!(thread->base.user_options & K_ESSENTIAL),
1916 "aborting essential thread %p", thread));
1917
1918 z_impl_k_thread_abort((struct k_thread *)thread);
1919 }
1920 #include <syscalls/k_thread_abort_mrsh.c>
1921 #endif /* CONFIG_USERSPACE */
1922
1923 /*
1924 * future scheduler.h API implementations
1925 */
z_sched_wake(_wait_q_t * wait_q,int swap_retval,void * swap_data)1926 bool z_sched_wake(_wait_q_t *wait_q, int swap_retval, void *swap_data)
1927 {
1928 struct k_thread *thread;
1929 bool ret = false;
1930
1931 K_SPINLOCK(&sched_spinlock) {
1932 thread = _priq_wait_best(&wait_q->waitq);
1933
1934 if (thread != NULL) {
1935 z_thread_return_value_set_with_data(thread,
1936 swap_retval,
1937 swap_data);
1938 unpend_thread_no_timeout(thread);
1939 (void)z_abort_thread_timeout(thread);
1940 ready_thread(thread);
1941 ret = true;
1942 }
1943 }
1944
1945 return ret;
1946 }
1947
z_sched_wait(struct k_spinlock * lock,k_spinlock_key_t key,_wait_q_t * wait_q,k_timeout_t timeout,void ** data)1948 int z_sched_wait(struct k_spinlock *lock, k_spinlock_key_t key,
1949 _wait_q_t *wait_q, k_timeout_t timeout, void **data)
1950 {
1951 int ret = z_pend_curr(lock, key, wait_q, timeout);
1952
1953 if (data != NULL) {
1954 *data = _current->base.swap_data;
1955 }
1956 return ret;
1957 }
1958
z_sched_waitq_walk(_wait_q_t * wait_q,int (* func)(struct k_thread *,void *),void * data)1959 int z_sched_waitq_walk(_wait_q_t *wait_q,
1960 int (*func)(struct k_thread *, void *), void *data)
1961 {
1962 struct k_thread *thread;
1963 int status = 0;
1964
1965 K_SPINLOCK(&sched_spinlock) {
1966 _WAIT_Q_FOR_EACH(wait_q, thread) {
1967
1968 /*
1969 * Invoke the callback function on each waiting thread
1970 * for as long as there are both waiting threads AND
1971 * it returns 0.
1972 */
1973
1974 status = func(thread, data);
1975 if (status != 0) {
1976 break;
1977 }
1978 }
1979 }
1980
1981 return status;
1982 }
1983