LCOV - code coverage report
Current view: top level - /home/runner/zephyrproject/zephyr/kernel - sched.c (source / functions) Coverage Total Hit
Test: lcov.info Lines: 46.5 % 430 200
Test Date: 2026-03-12 12:01:18 Functions: 55.7 % 61 34
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 27.8 % 198 55

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

Generated by: LCOV version 2.0-1