LCOV - code coverage report
Current view: top level - home/runner/zephyrproject/zephyr/kernel - sched.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 214 444 48.2 %
Date: 2024-09-16 20:15:30 Functions: 38 66 57.6 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 60 204 29.4 %

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

Generated by: LCOV version 1.14