LCOV - code coverage report
Current view: top level - home/runner/zephyrproject/zephyr/kernel - sched.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 197 427 46.1 %
Date: 2024-11-24 18:13:42 Functions: 35 63 55.6 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 55 198 27.8 %

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

Generated by: LCOV version 1.14