LCOV - code coverage report
Current view: top level - /home/runner/zephyrproject/zephyr/kernel - sched.c (source / functions) Coverage Total Hit
Test: lcov.info Lines: 47.1 % 418 197
Test Date: 2026-01-29 09:48:10 Functions: 55.0 % 60 33
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 29.7 % 192 57

             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                 :           0 : void z_impl_k_thread_resume(k_tid_t thread)
     534                 :             : {
     535                 :           0 :         SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_thread, resume, thread);
     536                 :             : 
     537                 :           0 :         k_spinlock_key_t key = k_spin_lock(&_sched_spinlock);
     538                 :             : 
     539                 :             :         /* Do not try to resume a thread that was not suspended */
     540         [ #  # ]:           0 :         if (unlikely(!z_is_thread_suspended(thread))) {
     541                 :           0 :                 k_spin_unlock(&_sched_spinlock, key);
     542                 :           0 :                 return;
     543                 :             :         }
     544                 :             : 
     545                 :           0 :         z_mark_thread_as_not_suspended(thread);
     546                 :           0 :         ready_thread(thread);
     547                 :             : 
     548                 :           0 :         z_reschedule(&_sched_spinlock, key);
     549                 :             : 
     550                 :           0 :         SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_thread, resume, thread);
     551                 :             : }
     552                 :             : 
     553                 :             : #ifdef CONFIG_USERSPACE
     554                 :             : static inline void z_vrfy_k_thread_resume(k_tid_t thread)
     555                 :             : {
     556                 :             :         K_OOPS(K_SYSCALL_OBJ(thread, K_OBJ_THREAD));
     557                 :             :         z_impl_k_thread_resume(thread);
     558                 :             : }
     559                 :             : #include <zephyr/syscalls/k_thread_resume_mrsh.c>
     560                 :             : #endif /* CONFIG_USERSPACE */
     561                 :             : 
     562                 :          10 : static void unready_thread(struct k_thread *thread)
     563                 :             : {
     564         [ +  - ]:          10 :         if (z_is_thread_queued(thread)) {
     565                 :          10 :                 dequeue_thread(thread);
     566                 :             :         }
     567                 :          10 :         update_cache(thread == _current);
     568                 :          10 : }
     569                 :             : 
     570                 :             : /* _sched_spinlock must be held */
     571                 :             : #ifdef IAR_SUPPRESS_ALWAYS_INLINE_WARNING_FLAG
     572                 :             : TOOLCHAIN_DISABLE_WARNING(TOOLCHAIN_WARNING_ALWAYS_INLINE)
     573                 :             : #endif
     574                 :          10 : static void add_to_waitq_locked(struct k_thread *thread, _wait_q_t *wait_q)
     575                 :             : {
     576                 :          10 :         unready_thread(thread);
     577                 :          10 :         z_mark_thread_as_pending(thread);
     578                 :             : 
     579                 :          10 :         SYS_PORT_TRACING_FUNC(k_thread, sched_pend, thread);
     580                 :             : 
     581         [ +  - ]:          10 :         if (wait_q != NULL) {
     582                 :          10 :                 thread->base.pended_on = wait_q;
     583                 :          10 :                 _priq_wait_add(&wait_q->waitq, thread);
     584                 :             :         }
     585                 :          10 : }
     586                 :             : #ifdef IAR_SUPPRESS_ALWAYS_INLINE_WARNING_FLAG
     587                 :             : TOOLCHAIN_ENABLE_WARNING(TOOLCHAIN_WARNING_ALWAYS_INLINE)
     588                 :             : #endif
     589                 :             : 
     590                 :          10 : static void add_thread_timeout(struct k_thread *thread, k_timeout_t timeout)
     591                 :             : {
     592         [ -  + ]:          10 :         if (!K_TIMEOUT_EQ(timeout, K_FOREVER)) {
     593                 :           0 :                 z_add_thread_timeout(thread, timeout);
     594                 :             :         }
     595                 :          10 : }
     596                 :             : 
     597                 :           4 : static void pend_locked(struct k_thread *thread, _wait_q_t *wait_q,
     598                 :             :                         k_timeout_t timeout)
     599                 :             : {
     600                 :             : #ifdef CONFIG_KERNEL_COHERENCE
     601                 :             :         __ASSERT_NO_MSG(wait_q == NULL || sys_cache_is_mem_coherent(wait_q));
     602                 :             : #endif /* CONFIG_KERNEL_COHERENCE */
     603                 :           4 :         add_to_waitq_locked(thread, wait_q);
     604                 :           4 :         add_thread_timeout(thread, timeout);
     605                 :           4 : }
     606                 :             : 
     607                 :           0 : void z_pend_thread(struct k_thread *thread, _wait_q_t *wait_q,
     608                 :             :                    k_timeout_t timeout)
     609                 :             : {
     610   [ #  #  #  # ]:           0 :         __ASSERT_NO_MSG(thread == _current || is_thread_dummy(thread));
     611         [ #  # ]:           0 :         K_SPINLOCK(&_sched_spinlock) {
     612                 :           0 :                 pend_locked(thread, wait_q, timeout);
     613                 :             :         }
     614                 :           0 : }
     615                 :             : 
     616                 :           0 : void z_unpend_thread_no_timeout(struct k_thread *thread)
     617                 :             : {
     618         [ #  # ]:           0 :         K_SPINLOCK(&_sched_spinlock) {
     619         [ #  # ]:           0 :                 if (thread->base.pended_on != NULL) {
     620                 :           0 :                         unpend_thread_no_timeout(thread);
     621                 :             :                 }
     622                 :             :         }
     623                 :           0 : }
     624                 :             : 
     625                 :           0 : void z_sched_wake_thread(struct k_thread *thread, bool is_timeout)
     626                 :             : {
     627         [ #  # ]:           0 :         K_SPINLOCK(&_sched_spinlock) {
     628                 :           0 :                 bool killed = (thread->base.thread_state &
     629                 :             :                                 (_THREAD_DEAD | _THREAD_ABORTING));
     630                 :             : 
     631                 :             : #ifdef CONFIG_EVENTS
     632                 :             :                 bool do_nothing = thread->no_wake_on_timeout && is_timeout;
     633                 :             : 
     634                 :             :                 thread->no_wake_on_timeout = false;
     635                 :             : 
     636                 :             :                 if (do_nothing) {
     637                 :             :                         continue;
     638                 :             :                 }
     639                 :             : #endif /* CONFIG_EVENTS */
     640                 :             : 
     641         [ #  # ]:           0 :                 if (!killed) {
     642                 :             :                         /* The thread is not being killed */
     643         [ #  # ]:           0 :                         if (thread->base.pended_on != NULL) {
     644                 :           0 :                                 unpend_thread_no_timeout(thread);
     645                 :             :                         }
     646                 :           0 :                         z_mark_thread_as_not_sleeping(thread);
     647                 :           0 :                         ready_thread(thread);
     648                 :             :                 }
     649                 :             :         }
     650                 :             : 
     651                 :           0 : }
     652                 :             : 
     653                 :             : #ifdef CONFIG_SYS_CLOCK_EXISTS
     654                 :             : /* Timeout handler for *_thread_timeout() APIs */
     655                 :           0 : void z_thread_timeout(struct _timeout *timeout)
     656                 :             : {
     657                 :           0 :         struct k_thread *thread = CONTAINER_OF(timeout,
     658                 :             :                                                struct k_thread, base.timeout);
     659                 :             : 
     660                 :           0 :         z_sched_wake_thread(thread, true);
     661                 :           0 : }
     662                 :             : #endif /* CONFIG_SYS_CLOCK_EXISTS */
     663                 :             : 
     664                 :           4 : int z_pend_curr(struct k_spinlock *lock, k_spinlock_key_t key,
     665                 :             :                _wait_q_t *wait_q, k_timeout_t timeout)
     666                 :             : {
     667                 :             : #if defined(CONFIG_TIMESLICING) && defined(CONFIG_SWAP_NONATOMIC)
     668                 :             :         pending_current = _current;
     669                 :             : #endif /* CONFIG_TIMESLICING && CONFIG_SWAP_NONATOMIC */
     670         [ -  + ]:           4 :         __ASSERT_NO_MSG(sizeof(_sched_spinlock) == 0 || lock != &_sched_spinlock);
     671                 :             : 
     672                 :             :         /* We do a "lock swap" prior to calling z_swap(), such that
     673                 :             :          * the caller's lock gets released as desired.  But we ensure
     674                 :             :          * that we hold the scheduler lock and leave local interrupts
     675                 :             :          * masked until we reach the context switch.  z_swap() itself
     676                 :             :          * has similar code; the duplication is because it's a legacy
     677                 :             :          * API that doesn't expect to be called with scheduler lock
     678                 :             :          * held.
     679                 :             :          */
     680                 :           4 :         (void) k_spin_lock(&_sched_spinlock);
     681                 :           4 :         pend_locked(_current, wait_q, timeout);
     682                 :           4 :         k_spin_release(lock);
     683                 :           4 :         return z_swap(&_sched_spinlock, key);
     684                 :             : }
     685                 :             : 
     686                 :           0 : struct k_thread *z_unpend1_no_timeout(_wait_q_t *wait_q)
     687                 :             : {
     688                 :           0 :         struct k_thread *thread = NULL;
     689                 :             : 
     690         [ #  # ]:           0 :         K_SPINLOCK(&_sched_spinlock) {
     691                 :           0 :                 thread = _priq_wait_best(&wait_q->waitq);
     692                 :             : 
     693         [ #  # ]:           0 :                 if (thread != NULL) {
     694                 :           0 :                         unpend_thread_no_timeout(thread);
     695                 :             :                 }
     696                 :             :         }
     697                 :             : 
     698                 :           0 :         return thread;
     699                 :             : }
     700                 :             : 
     701                 :           0 : void z_unpend_thread(struct k_thread *thread)
     702                 :             : {
     703                 :           0 :         z_unpend_thread_no_timeout(thread);
     704                 :           0 :         z_abort_thread_timeout(thread);
     705                 :           0 : }
     706                 :             : 
     707                 :             : /* Priority set utility that does no rescheduling, it just changes the
     708                 :             :  * run queue state, returning true if a reschedule is needed later.
     709                 :             :  */
     710                 :             : #ifdef IAR_SUPPRESS_ALWAYS_INLINE_WARNING_FLAG
     711                 :             : TOOLCHAIN_DISABLE_WARNING(TOOLCHAIN_WARNING_ALWAYS_INLINE)
     712                 :             : #endif
     713                 :           0 : bool z_thread_prio_set(struct k_thread *thread, int prio)
     714                 :             : {
     715                 :           0 :         bool need_sched = 0;
     716                 :           0 :         int old_prio = thread->base.prio;
     717                 :             : 
     718         [ #  # ]:           0 :         K_SPINLOCK(&_sched_spinlock) {
     719                 :           0 :                 need_sched = z_is_thread_ready(thread);
     720                 :             : 
     721         [ #  # ]:           0 :                 if (need_sched) {
     722                 :           0 :                         if (!IS_ENABLED(CONFIG_SMP) || z_is_thread_queued(thread)) {
     723                 :           0 :                                 dequeue_thread(thread);
     724                 :           0 :                                 thread->base.prio = prio;
     725                 :           0 :                                 queue_thread(thread);
     726                 :             : 
     727                 :           0 :                                 if (old_prio > prio) {
     728                 :           0 :                                         flag_ipi(ipi_mask_create(thread));
     729                 :             :                                 }
     730                 :             :                         } else {
     731                 :             :                                 /*
     732                 :             :                                  * This is a running thread on SMP. Update its
     733                 :             :                                  * priority, but do not requeue it. An IPI is
     734                 :             :                                  * needed if the priority is both being lowered
     735                 :             :                                  * and it is running on another CPU.
     736                 :             :                                  */
     737                 :             : 
     738                 :             :                                 thread->base.prio = prio;
     739                 :             : 
     740                 :             :                                 struct _cpu *cpu;
     741                 :             : 
     742                 :             :                                 cpu = thread_active_elsewhere(thread);
     743                 :             :                                 if ((cpu != NULL) && (old_prio < prio)) {
     744                 :           0 :                                         flag_ipi(IPI_CPU_MASK(cpu->id));
     745                 :             :                                 }
     746                 :             :                         }
     747                 :             : 
     748                 :           0 :                         update_cache(1);
     749         [ #  # ]:           0 :                 } else if (z_is_thread_pending(thread)) {
     750                 :             :                         /* Thread is pending, remove it from the waitq
     751                 :             :                          * and reinsert it with the new priority to avoid
     752                 :             :                          * violating waitq ordering and rb assumptions.
     753                 :             :                          */
     754                 :           0 :                         _wait_q_t *wait_q = pended_on_thread(thread);
     755                 :             : 
     756                 :           0 :                         _priq_wait_remove(&wait_q->waitq, thread);
     757                 :           0 :                         thread->base.prio = prio;
     758                 :           0 :                         _priq_wait_add(&wait_q->waitq, thread);
     759                 :             :                 } else {
     760                 :           0 :                         thread->base.prio = prio;
     761                 :             :                 }
     762                 :             :         }
     763                 :             : 
     764                 :           0 :         SYS_PORT_TRACING_OBJ_FUNC(k_thread, sched_priority_set, thread, prio);
     765                 :             : 
     766                 :           0 :         return need_sched;
     767                 :             : }
     768                 :             : #ifdef IAR_SUPPRESS_ALWAYS_INLINE_WARNING_FLAG
     769                 :             : TOOLCHAIN_ENABLE_WARNING(TOOLCHAIN_WARNING_ALWAYS_INLINE)
     770                 :             : #endif
     771                 :             : 
     772                 :          93 : static inline bool resched(uint32_t key)
     773                 :             : {
     774                 :             : #ifdef CONFIG_SMP
     775                 :             :         _current_cpu->swap_ok = 0;
     776                 :             : #endif /* CONFIG_SMP */
     777                 :             : 
     778   [ +  -  -  + ]:          93 :         return arch_irq_unlocked(key) && !arch_is_in_isr();
     779                 :             : }
     780                 :             : 
     781                 :             : /*
     782                 :             :  * Check if the next ready thread is the same as the current thread
     783                 :             :  * and save the trip if true.
     784                 :             :  */
     785                 :          93 : static inline bool need_swap(void)
     786                 :             : {
     787                 :             :         /* the SMP case will be handled in C based z_swap() */
     788                 :             : #ifdef CONFIG_SMP
     789                 :             :         return true;
     790                 :             : #else
     791                 :          93 :         struct k_thread *new_thread;
     792                 :             : 
     793                 :             :         /* Check if the next ready thread is the same as the current thread */
     794                 :          93 :         new_thread = _kernel.ready_q.cache;
     795                 :          93 :         return new_thread != _current;
     796                 :             : #endif /* CONFIG_SMP */
     797                 :             : }
     798                 :             : 
     799                 :          50 : void z_reschedule(struct k_spinlock *lock, k_spinlock_key_t key)
     800                 :             : {
     801   [ +  -  +  + ]:          50 :         if (resched(key.key) && need_swap()) {
     802                 :          42 :                 z_swap(lock, key);
     803                 :             :         } else {
     804                 :           8 :                 k_spin_unlock(lock, key);
     805                 :          50 :                 signal_pending_ipi();
     806                 :             :         }
     807                 :          50 : }
     808                 :             : 
     809                 :          43 : void z_reschedule_irqlock(uint32_t key)
     810                 :             : {
     811   [ +  -  -  + ]:          43 :         if (resched(key) && need_swap()) {
     812                 :           0 :                 z_swap_irqlock(key);
     813                 :             :         } else {
     814                 :          43 :                 irq_unlock(key);
     815                 :          43 :                 signal_pending_ipi();
     816                 :             :         }
     817                 :          43 : }
     818                 :             : 
     819                 :           1 : void k_sched_lock(void)
     820                 :             : {
     821                 :           1 :         LOG_DBG("scheduler locked (%p:%d)",
     822                 :             :                 _current, _current->base.sched_locked);
     823                 :             : 
     824         [ +  + ]:           2 :         K_SPINLOCK(&_sched_spinlock) {
     825                 :           1 :                 SYS_PORT_TRACING_FUNC(k_thread, sched_lock);
     826                 :             : 
     827         [ -  + ]:           1 :                 __ASSERT(!arch_is_in_isr(), "");
     828         [ -  + ]:           1 :                 __ASSERT(_current->base.sched_locked != 1U, "");
     829                 :             : 
     830                 :           1 :                 --_current->base.sched_locked;
     831                 :             : 
     832                 :           1 :                 compiler_barrier();
     833                 :             :         }
     834                 :           1 : }
     835                 :             : 
     836                 :           1 : void k_sched_unlock(void)
     837                 :             : {
     838         [ +  + ]:           2 :         K_SPINLOCK(&_sched_spinlock) {
     839         [ -  + ]:           1 :                 __ASSERT(_current->base.sched_locked != 0U, "");
     840         [ -  + ]:           1 :                 __ASSERT(!arch_is_in_isr(), "");
     841                 :             : 
     842                 :           1 :                 ++_current->base.sched_locked;
     843                 :           1 :                 update_cache(0);
     844                 :             :         }
     845                 :             : 
     846                 :           1 :         LOG_DBG("scheduler unlocked (%p:%d)",
     847                 :             :                 _current, _current->base.sched_locked);
     848                 :             : 
     849                 :           1 :         SYS_PORT_TRACING_FUNC(k_thread, sched_unlock);
     850                 :             : 
     851                 :           1 :         z_reschedule_unlocked();
     852                 :           1 : }
     853                 :             : 
     854                 :           0 : struct k_thread *z_swap_next_thread(void)
     855                 :             : {
     856                 :             : #ifdef CONFIG_SMP
     857                 :             :         struct k_thread *ret = next_up();
     858                 :             : 
     859                 :             :         if (ret == _current) {
     860                 :             :                 /* When not swapping, have to signal IPIs here.  In
     861                 :             :                  * the context switch case it must happen later, after
     862                 :             :                  * _current gets requeued.
     863                 :             :                  */
     864                 :             :                 signal_pending_ipi();
     865                 :             :         }
     866                 :             :         return ret;
     867                 :             : #else
     868                 :           0 :         return _kernel.ready_q.cache;
     869                 :             : #endif /* CONFIG_SMP */
     870                 :             : }
     871                 :             : 
     872                 :             : #ifdef CONFIG_USE_SWITCH
     873                 :             : /* Just a wrapper around z_current_thread_set(xxx) with tracing */
     874                 :             : static inline void set_current(struct k_thread *new_thread)
     875                 :             : {
     876                 :             :         /* If the new thread is the same as the current thread, we
     877                 :             :          * don't need to do anything.
     878                 :             :          */
     879                 :             :         if (IS_ENABLED(CONFIG_INSTRUMENT_THREAD_SWITCHING) && new_thread != _current) {
     880                 :             :                 z_thread_mark_switched_out();
     881                 :             :         }
     882                 :             :         z_current_thread_set(new_thread);
     883                 :             : }
     884                 :             : 
     885                 :             : /**
     886                 :             :  * @brief Determine next thread to execute upon completion of an interrupt
     887                 :             :  *
     888                 :             :  * Thread preemption is performed by context switching after the completion
     889                 :             :  * of a non-recursed interrupt. This function determines which thread to
     890                 :             :  * switch to if any. This function accepts as @p interrupted either:
     891                 :             :  *
     892                 :             :  * - The handle for the interrupted thread in which case the thread's context
     893                 :             :  *   must already be fully saved and ready to be picked up by a different CPU.
     894                 :             :  *
     895                 :             :  * - NULL if more work is required to fully save the thread's state after
     896                 :             :  *   it is known that a new thread is to be scheduled. It is up to the caller
     897                 :             :  *   to store the handle resulting from the thread that is being switched out
     898                 :             :  *   in that thread's "switch_handle" field after its
     899                 :             :  *   context has fully been saved, following the same requirements as with
     900                 :             :  *   the @ref arch_switch() function.
     901                 :             :  *
     902                 :             :  * If a new thread needs to be scheduled then its handle is returned.
     903                 :             :  * Otherwise the same value provided as @p interrupted is returned back.
     904                 :             :  * Those handles are the same opaque types used by the @ref arch_switch()
     905                 :             :  * function.
     906                 :             :  *
     907                 :             :  * @warning
     908                 :             :  * The _current value may have changed after this call and not refer
     909                 :             :  * to the interrupted thread anymore. It might be necessary to make a local
     910                 :             :  * copy before calling this function.
     911                 :             :  *
     912                 :             :  * @param interrupted Handle for the thread that was interrupted or NULL.
     913                 :             :  * @retval Handle for the next thread to execute, or @p interrupted when
     914                 :             :  *         no new thread is to be scheduled.
     915                 :             :  */
     916                 :             : void *z_get_next_switch_handle(void *interrupted)
     917                 :             : {
     918                 :             :         z_check_stack_sentinel();
     919                 :             : 
     920                 :             : #ifdef CONFIG_SMP
     921                 :             :         void *ret = NULL;
     922                 :             : 
     923                 :             :         K_SPINLOCK(&_sched_spinlock) {
     924                 :             :                 struct k_thread *old_thread = _current, *new_thread;
     925                 :             : 
     926                 :             :                 __ASSERT(old_thread->switch_handle == NULL || is_thread_dummy(old_thread),
     927                 :             :                         "old thread handle should be null.");
     928                 :             : 
     929                 :             :                 new_thread = next_up();
     930                 :             : 
     931                 :             :                 z_sched_usage_switch(new_thread);
     932                 :             : 
     933                 :             :                 if (old_thread != new_thread) {
     934                 :             :                         uint8_t  cpu_id;
     935                 :             : 
     936                 :             :                         z_sched_switch_spin(new_thread);
     937                 :             :                         arch_cohere_stacks(old_thread, interrupted, new_thread);
     938                 :             : 
     939                 :             :                         _current_cpu->swap_ok = 0;
     940                 :             :                         cpu_id = arch_curr_cpu()->id;
     941                 :             :                         new_thread->base.cpu = cpu_id;
     942                 :             :                         set_current(new_thread);
     943                 :             : 
     944                 :             : #ifdef CONFIG_TIMESLICING
     945                 :             :                         z_reset_time_slice(new_thread);
     946                 :             : #endif /* CONFIG_TIMESLICING */
     947                 :             : 
     948                 :             : #ifdef CONFIG_SPIN_VALIDATE
     949                 :             :                         /* Changed _current!  Update the spinlock
     950                 :             :                          * bookkeeping so the validation doesn't get
     951                 :             :                          * confused when the "wrong" thread tries to
     952                 :             :                          * release the lock.
     953                 :             :                          */
     954                 :             :                         z_spin_lock_set_owner(&_sched_spinlock);
     955                 :             : #endif /* CONFIG_SPIN_VALIDATE */
     956                 :             : 
     957                 :             :                         /* A queued (runnable) old/current thread
     958                 :             :                          * needs to be added back to the run queue
     959                 :             :                          * here, and atomically with its switch handle
     960                 :             :                          * being set below.  This is safe now, as we
     961                 :             :                          * will not return into it.
     962                 :             :                          */
     963                 :             :                         if (z_is_thread_queued(old_thread)) {
     964                 :             : #ifdef CONFIG_SCHED_IPI_CASCADE
     965                 :             :                                 if ((new_thread->base.cpu_mask != -1) &&
     966                 :             :                                     (old_thread->base.cpu_mask != BIT(cpu_id))) {
     967                 :             :                                         flag_ipi(ipi_mask_create(old_thread));
     968                 :             :                                 }
     969                 :             : #endif
     970                 :             :                                 runq_add(old_thread);
     971                 :             :                         }
     972                 :             :                 }
     973                 :             :                 old_thread->switch_handle = interrupted;
     974                 :             :                 ret = new_thread->switch_handle;
     975                 :             :                 /* Active threads MUST have a null here */
     976                 :             :                 new_thread->switch_handle = NULL;
     977                 :             :         }
     978                 :             :         signal_pending_ipi();
     979                 :             :         return ret;
     980                 :             : #else
     981                 :             :         z_sched_usage_switch(_kernel.ready_q.cache);
     982                 :             :         _current->switch_handle = interrupted;
     983                 :             :         set_current(_kernel.ready_q.cache);
     984                 :             :         return _current->switch_handle;
     985                 :             : #endif /* CONFIG_SMP */
     986                 :             : }
     987                 :             : #endif /* CONFIG_USE_SWITCH */
     988                 :             : 
     989                 :           0 : int z_unpend_all(_wait_q_t *wait_q)
     990                 :             : {
     991                 :           0 :         int need_sched = 0;
     992                 :           0 :         struct k_thread *thread;
     993                 :             : 
     994         [ #  # ]:           0 :         for (thread = z_waitq_head(wait_q); thread != NULL; thread = z_waitq_head(wait_q)) {
     995                 :           0 :                 z_unpend_thread(thread);
     996                 :           0 :                 z_ready_thread(thread);
     997                 :           0 :                 need_sched = 1;
     998                 :             :         }
     999                 :             : 
    1000                 :           0 :         return need_sched;
    1001                 :             : }
    1002                 :             : 
    1003                 :           1 : void init_ready_q(struct _ready_q *ready_q)
    1004                 :             : {
    1005                 :           1 :         _priq_run_init(&ready_q->runq);
    1006                 :           1 : }
    1007                 :             : 
    1008                 :           1 : void z_sched_init(void)
    1009                 :             : {
    1010                 :             : #ifdef CONFIG_SCHED_CPU_MASK_PIN_ONLY
    1011                 :             :         for (int i = 0; i < CONFIG_MP_MAX_NUM_CPUS; i++) {
    1012                 :             :                 init_ready_q(&_kernel.cpus[i].ready_q);
    1013                 :             :         }
    1014                 :             : #else
    1015                 :           1 :         init_ready_q(&_kernel.ready_q);
    1016                 :             : #endif /* CONFIG_SCHED_CPU_MASK_PIN_ONLY */
    1017                 :           1 : }
    1018                 :             : 
    1019                 :           0 : void z_impl_k_thread_priority_set(k_tid_t thread, int prio)
    1020                 :             : {
    1021                 :             :         /*
    1022                 :             :          * Use NULL, since we cannot know what the entry point is (we do not
    1023                 :             :          * keep track of it) and idle cannot change its priority.
    1024                 :             :          */
    1025   [ #  #  #  #  :           0 :         Z_ASSERT_VALID_PRIO(prio, NULL);
                   #  # ]
    1026                 :             : 
    1027                 :           0 :         bool need_sched = z_thread_prio_set((struct k_thread *)thread, prio);
    1028                 :             : 
    1029         [ #  # ]:           0 :         if ((need_sched) && (IS_ENABLED(CONFIG_SMP) ||
    1030         [ #  # ]:           0 :                              (_current->base.sched_locked == 0U))) {
    1031                 :           0 :                 z_reschedule_unlocked();
    1032                 :             :         }
    1033                 :           0 : }
    1034                 :             : 
    1035                 :             : #ifdef CONFIG_USERSPACE
    1036                 :             : static inline void z_vrfy_k_thread_priority_set(k_tid_t thread, int prio)
    1037                 :             : {
    1038                 :             :         K_OOPS(K_SYSCALL_OBJ(thread, K_OBJ_THREAD));
    1039                 :             :         K_OOPS(K_SYSCALL_VERIFY_MSG(_is_valid_prio(prio, NULL),
    1040                 :             :                                     "invalid thread priority %d", prio));
    1041                 :             : #ifndef CONFIG_USERSPACE_THREAD_MAY_RAISE_PRIORITY
    1042                 :             :         K_OOPS(K_SYSCALL_VERIFY_MSG((int8_t)prio >= thread->base.prio,
    1043                 :             :                                     "thread priority may only be downgraded (%d < %d)",
    1044                 :             :                                     prio, thread->base.prio));
    1045                 :             : #endif /* CONFIG_USERSPACE_THREAD_MAY_RAISE_PRIORITY */
    1046                 :             :         z_impl_k_thread_priority_set(thread, prio);
    1047                 :             : }
    1048                 :             : #include <zephyr/syscalls/k_thread_priority_set_mrsh.c>
    1049                 :             : #endif /* CONFIG_USERSPACE */
    1050                 :             : 
    1051                 :             : #ifdef CONFIG_SCHED_DEADLINE
    1052                 :             : void z_impl_k_thread_absolute_deadline_set(k_tid_t tid, int deadline)
    1053                 :             : {
    1054                 :             :         struct k_thread *thread = tid;
    1055                 :             : 
    1056                 :             :         /* The prio_deadline field changes the sorting order, so can't
    1057                 :             :          * change it while the thread is in the run queue (dlists
    1058                 :             :          * actually are benign as long as we requeue it before we
    1059                 :             :          * release the lock, but an rbtree will blow up if we break
    1060                 :             :          * sorting!)
    1061                 :             :          */
    1062                 :             :         K_SPINLOCK(&_sched_spinlock) {
    1063                 :             :                 if (z_is_thread_queued(thread)) {
    1064                 :             :                         dequeue_thread(thread);
    1065                 :             :                         thread->base.prio_deadline = deadline;
    1066                 :             :                         queue_thread(thread);
    1067                 :             :                 } else {
    1068                 :             :                         thread->base.prio_deadline = deadline;
    1069                 :             :                 }
    1070                 :             :         }
    1071                 :             : }
    1072                 :             : 
    1073                 :             : void z_impl_k_thread_deadline_set(k_tid_t tid, int deadline)
    1074                 :             : {
    1075                 :             : 
    1076                 :             :         deadline = clamp(deadline, 0, INT_MAX);
    1077                 :             : 
    1078                 :             :         int32_t newdl = k_cycle_get_32() + deadline;
    1079                 :             : 
    1080                 :             :         z_impl_k_thread_absolute_deadline_set(tid, newdl);
    1081                 :             : }
    1082                 :             : 
    1083                 :             : #ifdef CONFIG_USERSPACE
    1084                 :             : static inline void z_vrfy_k_thread_absolute_deadline_set(k_tid_t tid, int deadline)
    1085                 :             : {
    1086                 :             :         struct k_thread *thread = tid;
    1087                 :             : 
    1088                 :             :         K_OOPS(K_SYSCALL_OBJ(thread, K_OBJ_THREAD));
    1089                 :             : 
    1090                 :             :         z_impl_k_thread_absolute_deadline_set((k_tid_t)thread, deadline);
    1091                 :             : }
    1092                 :             : #include <zephyr/syscalls/k_thread_absolute_deadline_set_mrsh.c>
    1093                 :             : 
    1094                 :             : static inline void z_vrfy_k_thread_deadline_set(k_tid_t tid, int deadline)
    1095                 :             : {
    1096                 :             :         struct k_thread *thread = tid;
    1097                 :             : 
    1098                 :             :         K_OOPS(K_SYSCALL_OBJ(thread, K_OBJ_THREAD));
    1099                 :             :         K_OOPS(K_SYSCALL_VERIFY_MSG(deadline > 0,
    1100                 :             :                                     "invalid thread deadline %d",
    1101                 :             :                                     (int)deadline));
    1102                 :             : 
    1103                 :             :         z_impl_k_thread_deadline_set((k_tid_t)thread, deadline);
    1104                 :             : }
    1105                 :             : #include <zephyr/syscalls/k_thread_deadline_set_mrsh.c>
    1106                 :             : #endif /* CONFIG_USERSPACE */
    1107                 :             : #endif /* CONFIG_SCHED_DEADLINE */
    1108                 :             : 
    1109                 :           0 : void z_impl_k_reschedule(void)
    1110                 :             : {
    1111                 :           0 :         k_spinlock_key_t key;
    1112                 :             : 
    1113                 :           0 :         key = k_spin_lock(&_sched_spinlock);
    1114                 :             : 
    1115                 :           0 :         update_cache(0);
    1116                 :             : 
    1117                 :           0 :         z_reschedule(&_sched_spinlock, key);
    1118                 :           0 : }
    1119                 :             : 
    1120                 :             : #ifdef CONFIG_USERSPACE
    1121                 :             : static inline void z_vrfy_k_reschedule(void)
    1122                 :             : {
    1123                 :             :         z_impl_k_reschedule();
    1124                 :             : }
    1125                 :             : #include <zephyr/syscalls/k_reschedule_mrsh.c>
    1126                 :             : #endif /* CONFIG_USERSPACE */
    1127                 :             : 
    1128                 :           0 : bool k_can_yield(void)
    1129                 :             : {
    1130   [ #  #  #  # ]:           0 :         return !(k_is_pre_kernel() || k_is_in_isr() ||
    1131         [ #  # ]:           0 :                  z_is_idle_thread_object(_current));
    1132                 :             : }
    1133                 :             : 
    1134                 :           0 : void z_impl_k_yield(void)
    1135                 :             : {
    1136         [ #  # ]:           0 :         __ASSERT(!arch_is_in_isr(), "");
    1137                 :             : 
    1138                 :           0 :         SYS_PORT_TRACING_FUNC(k_thread, yield);
    1139                 :             : 
    1140                 :           0 :         k_spinlock_key_t key = k_spin_lock(&_sched_spinlock);
    1141                 :             : 
    1142                 :           0 :         runq_yield();
    1143                 :             : 
    1144                 :           0 :         update_cache(1);
    1145                 :           0 :         z_swap(&_sched_spinlock, key);
    1146                 :           0 : }
    1147                 :             : 
    1148                 :             : #ifdef CONFIG_USERSPACE
    1149                 :             : static inline void z_vrfy_k_yield(void)
    1150                 :             : {
    1151                 :             :         z_impl_k_yield();
    1152                 :             : }
    1153                 :             : #include <zephyr/syscalls/k_yield_mrsh.c>
    1154                 :             : #endif /* CONFIG_USERSPACE */
    1155                 :             : 
    1156                 :           0 : static int32_t z_tick_sleep(k_timeout_t timeout)
    1157                 :             : {
    1158                 :           0 :         uint32_t expected_wakeup_ticks;
    1159                 :             : 
    1160         [ #  # ]:           0 :         __ASSERT(!arch_is_in_isr(), "");
    1161                 :             : 
    1162                 :           0 :         LOG_DBG("thread %p for %lu ticks", _current, (unsigned long)timeout.ticks);
    1163                 :             : 
    1164                 :             :         /* K_NO_WAIT is treated as a 'yield' */
    1165         [ #  # ]:           0 :         if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {
    1166                 :           0 :                 k_yield();
    1167                 :           0 :                 return 0;
    1168                 :             :         }
    1169                 :             : 
    1170                 :           0 :         k_spinlock_key_t key = k_spin_lock(&_sched_spinlock);
    1171                 :             : 
    1172                 :             : #if defined(CONFIG_TIMESLICING) && defined(CONFIG_SWAP_NONATOMIC)
    1173                 :             :         pending_current = _current;
    1174                 :             : #endif /* CONFIG_TIMESLICING && CONFIG_SWAP_NONATOMIC */
    1175                 :           0 :         unready_thread(_current);
    1176                 :           0 :         expected_wakeup_ticks = (uint32_t)z_add_thread_timeout(_current, timeout);
    1177                 :           0 :         z_mark_thread_as_sleeping(_current);
    1178                 :             : 
    1179                 :           0 :         (void)z_swap(&_sched_spinlock, key);
    1180                 :             : 
    1181         [ #  # ]:           0 :         if (!z_is_aborted_thread_timeout(_current)) {
    1182                 :             :                 return 0;
    1183                 :             :         }
    1184                 :             : 
    1185                 :             :         /* We require a 32 bit unsigned subtraction to care a wraparound */
    1186                 :           0 :         uint32_t left_ticks = expected_wakeup_ticks - sys_clock_tick_get_32();
    1187                 :             : 
    1188                 :             :         /* To handle a negative value correctly, once type-cast it to signed 32 bit */
    1189                 :           0 :         k_ticks_t ticks = (k_ticks_t)(int32_t)left_ticks;
    1190                 :             : 
    1191         [ #  # ]:           0 :         if (ticks > 0) {
    1192                 :             :                 return ticks;
    1193                 :             :         }
    1194                 :             : 
    1195                 :             :         return 0;
    1196                 :             : }
    1197                 :             : 
    1198                 :           0 : int32_t z_impl_k_sleep(k_timeout_t timeout)
    1199                 :             : {
    1200                 :           0 :         k_ticks_t ticks;
    1201                 :             : 
    1202         [ #  # ]:           0 :         __ASSERT(!arch_is_in_isr(), "");
    1203                 :             : 
    1204                 :           0 :         SYS_PORT_TRACING_FUNC_ENTER(k_thread, sleep, timeout);
    1205                 :             : 
    1206                 :           0 :         ticks = z_tick_sleep(timeout);
    1207                 :             : 
    1208                 :             :         /* k_sleep() still returns 32 bit milliseconds for compatibility */
    1209         [ #  # ]:           0 :         int64_t ms = K_TIMEOUT_EQ(timeout, K_FOREVER) ? K_TICKS_FOREVER :
    1210                 :           0 :                 clamp(k_ticks_to_ms_ceil64(ticks), 0, INT_MAX);
    1211                 :             : 
    1212                 :           0 :         SYS_PORT_TRACING_FUNC_EXIT(k_thread, sleep, timeout, ms);
    1213                 :           0 :         return (int32_t) ms;
    1214                 :             : }
    1215                 :             : 
    1216                 :             : #ifdef CONFIG_USERSPACE
    1217                 :             : static inline int32_t z_vrfy_k_sleep(k_timeout_t timeout)
    1218                 :             : {
    1219                 :             :         return z_impl_k_sleep(timeout);
    1220                 :             : }
    1221                 :             : #include <zephyr/syscalls/k_sleep_mrsh.c>
    1222                 :             : #endif /* CONFIG_USERSPACE */
    1223                 :             : 
    1224                 :           0 : int32_t z_impl_k_usleep(int32_t us)
    1225                 :             : {
    1226                 :           0 :         int32_t ticks;
    1227                 :             : 
    1228                 :           0 :         SYS_PORT_TRACING_FUNC_ENTER(k_thread, usleep, us);
    1229                 :             : 
    1230                 :           0 :         ticks = k_us_to_ticks_ceil64(us);
    1231                 :           0 :         ticks = z_tick_sleep(Z_TIMEOUT_TICKS(ticks));
    1232                 :             : 
    1233                 :           0 :         int32_t ret = k_ticks_to_us_ceil64(ticks);
    1234                 :             : 
    1235                 :           0 :         SYS_PORT_TRACING_FUNC_EXIT(k_thread, usleep, us, ret);
    1236                 :             : 
    1237                 :           0 :         return ret;
    1238                 :             : }
    1239                 :             : 
    1240                 :             : #ifdef CONFIG_USERSPACE
    1241                 :             : static inline int32_t z_vrfy_k_usleep(int32_t us)
    1242                 :             : {
    1243                 :             :         return z_impl_k_usleep(us);
    1244                 :             : }
    1245                 :             : #include <zephyr/syscalls/k_usleep_mrsh.c>
    1246                 :             : #endif /* CONFIG_USERSPACE */
    1247                 :             : 
    1248                 :          50 : void z_impl_k_wakeup(k_tid_t thread)
    1249                 :             : {
    1250                 :          50 :         SYS_PORT_TRACING_OBJ_FUNC(k_thread, wakeup, thread);
    1251                 :             : 
    1252                 :          50 :         k_spinlock_key_t  key = k_spin_lock(&_sched_spinlock);
    1253                 :             : 
    1254         [ +  + ]:          50 :         if (z_is_thread_sleeping(thread)) {
    1255                 :          46 :                 z_abort_thread_timeout(thread);
    1256                 :          46 :                 z_mark_thread_as_not_sleeping(thread);
    1257                 :          46 :                 ready_thread(thread);
    1258                 :          46 :                 z_reschedule(&_sched_spinlock, key);
    1259                 :             :         } else {
    1260                 :           4 :                 k_spin_unlock(&_sched_spinlock, key);
    1261                 :             :         }
    1262                 :          50 : }
    1263                 :             : 
    1264                 :             : #ifdef CONFIG_USERSPACE
    1265                 :             : static inline void z_vrfy_k_wakeup(k_tid_t thread)
    1266                 :             : {
    1267                 :             :         K_OOPS(K_SYSCALL_OBJ(thread, K_OBJ_THREAD));
    1268                 :             :         z_impl_k_wakeup(thread);
    1269                 :             : }
    1270                 :             : #include <zephyr/syscalls/k_wakeup_mrsh.c>
    1271                 :             : #endif /* CONFIG_USERSPACE */
    1272                 :             : 
    1273                 :          46 : k_tid_t z_impl_k_sched_current_thread_query(void)
    1274                 :             : {
    1275                 :          46 :         return _current;
    1276                 :             : }
    1277                 :             : 
    1278                 :             : #ifdef CONFIG_USERSPACE
    1279                 :             : static inline k_tid_t z_vrfy_k_sched_current_thread_query(void)
    1280                 :             : {
    1281                 :             :         return z_impl_k_sched_current_thread_query();
    1282                 :             : }
    1283                 :             : #include <zephyr/syscalls/k_sched_current_thread_query_mrsh.c>
    1284                 :             : #endif /* CONFIG_USERSPACE */
    1285                 :             : 
    1286                 :          46 : static inline void unpend_all(_wait_q_t *wait_q)
    1287                 :             : {
    1288                 :          46 :         struct k_thread *thread;
    1289                 :             : 
    1290         [ +  + ]:          52 :         for (thread = z_waitq_head(wait_q); thread != NULL; thread = z_waitq_head(wait_q)) {
    1291                 :           6 :                 unpend_thread_no_timeout(thread);
    1292                 :           6 :                 z_abort_thread_timeout(thread);
    1293                 :           6 :                 arch_thread_return_value_set(thread, 0);
    1294                 :           6 :                 ready_thread(thread);
    1295                 :             :         }
    1296                 :          46 : }
    1297                 :             : 
    1298                 :             : #ifdef CONFIG_THREAD_ABORT_HOOK
    1299                 :             : extern void thread_abort_hook(struct k_thread *thread);
    1300                 :             : #endif /* CONFIG_THREAD_ABORT_HOOK */
    1301                 :             : 
    1302                 :             : /**
    1303                 :             :  * @brief Dequeues the specified thread
    1304                 :             :  *
    1305                 :             :  * Dequeues the specified thread and move it into the specified new state.
    1306                 :             :  *
    1307                 :             :  * @param thread Identify the thread to halt
    1308                 :             :  * @param new_state New thread state (_THREAD_DEAD or _THREAD_SUSPENDED)
    1309                 :             :  */
    1310                 :             : #ifdef IAR_SUPPRESS_ALWAYS_INLINE_WARNING_FLAG
    1311                 :             : TOOLCHAIN_DISABLE_WARNING(TOOLCHAIN_WARNING_ALWAYS_INLINE)
    1312                 :             : #endif
    1313                 :          46 : static ALWAYS_INLINE void halt_thread(struct k_thread *thread, uint8_t new_state)
    1314                 :             : {
    1315                 :          46 :         bool dummify = false;
    1316                 :             : 
    1317                 :             :         /* We hold the lock, and the thread is known not to be running
    1318                 :             :          * anywhere.
    1319                 :             :          */
    1320         [ +  - ]:          46 :         if ((thread->base.thread_state & new_state) == 0U) {
    1321                 :          46 :                 thread->base.thread_state |= new_state;
    1322         [ +  - ]:          46 :                 if (z_is_thread_queued(thread)) {
    1323                 :          46 :                         dequeue_thread(thread);
    1324                 :             :                 }
    1325                 :             : 
    1326         [ +  - ]:          46 :                 if (new_state == _THREAD_DEAD) {
    1327         [ -  + ]:          46 :                         if (thread->base.pended_on != NULL) {
    1328                 :           0 :                                 unpend_thread_no_timeout(thread);
    1329                 :             :                         }
    1330                 :          46 :                         z_abort_thread_timeout(thread);
    1331                 :          46 :                         unpend_all(&thread->join_queue);
    1332                 :             : 
    1333                 :             :                         /* Edge case: aborting _current from within an
    1334                 :             :                          * ISR that preempted it requires clearing the
    1335                 :             :                          * _current pointer so the upcoming context
    1336                 :             :                          * switch doesn't clobber the now-freed
    1337                 :             :                          * memory
    1338                 :             :                          */
    1339                 :          46 :                         if (thread == _current && arch_is_in_isr()) {
    1340                 :             :                                 dummify = true;
    1341                 :             :                         }
    1342                 :             :                 }
    1343                 :             : #ifdef CONFIG_SMP
    1344                 :             :                 unpend_all(&thread->halt_queue);
    1345                 :             : #endif /* CONFIG_SMP */
    1346                 :          46 :                 update_cache(1);
    1347                 :             : 
    1348         [ +  - ]:          46 :                 if (new_state == _THREAD_SUSPENDED) {
    1349                 :             :                         clear_halting(thread);
    1350                 :             :                         return;
    1351                 :             :                 }
    1352                 :             : 
    1353                 :          46 :                 arch_coprocessors_disable(thread);
    1354                 :             : 
    1355                 :          46 :                 SYS_PORT_TRACING_FUNC(k_thread, sched_abort, thread);
    1356                 :             : 
    1357                 :          46 :                 z_thread_monitor_exit(thread);
    1358                 :             : #ifdef CONFIG_THREAD_ABORT_HOOK
    1359                 :             :                 thread_abort_hook(thread);
    1360                 :             : #endif /* CONFIG_THREAD_ABORT_HOOK */
    1361                 :             : 
    1362                 :             : #ifdef CONFIG_OBJ_CORE_THREAD
    1363                 :             : #ifdef CONFIG_OBJ_CORE_STATS_THREAD
    1364                 :             :                 k_obj_core_stats_deregister(K_OBJ_CORE(thread));
    1365                 :             : #endif /* CONFIG_OBJ_CORE_STATS_THREAD */
    1366                 :             :                 k_obj_core_unlink(K_OBJ_CORE(thread));
    1367                 :             : #endif /* CONFIG_OBJ_CORE_THREAD */
    1368                 :             : 
    1369                 :             : #ifdef CONFIG_USERSPACE
    1370                 :             :                 z_mem_domain_exit_thread(thread);
    1371                 :             :                 k_thread_perms_all_clear(thread);
    1372                 :             :                 k_object_uninit(thread->stack_obj);
    1373                 :             :                 k_object_uninit(thread);
    1374                 :             : #endif /* CONFIG_USERSPACE */
    1375                 :             : 
    1376                 :             : #ifdef CONFIG_THREAD_ABORT_NEED_CLEANUP
    1377                 :             :                 k_thread_abort_cleanup(thread);
    1378                 :             : #endif /* CONFIG_THREAD_ABORT_NEED_CLEANUP */
    1379                 :             : 
    1380                 :             :                 /* Do this "set _current to dummy" step last so that
    1381                 :             :                  * subsystems above can rely on _current being
    1382                 :             :                  * unchanged.  Disabled for posix as that arch
    1383                 :             :                  * continues to use the _current pointer in its swap
    1384                 :             :                  * code.  Note that we must leave a non-null switch
    1385                 :             :                  * handle for any threads spinning in join() (this can
    1386                 :             :                  * never be used, as our thread is flagged dead, but
    1387                 :             :                  * it must not be NULL otherwise join can deadlock).
    1388                 :             :                  * Use 1 as a clearly invalid but non-NULL value.
    1389                 :             :                  */
    1390                 :          46 :                 if (dummify && !IS_ENABLED(CONFIG_ARCH_POSIX)) {
    1391                 :             : #ifdef CONFIG_USE_SWITCH
    1392                 :             :                         _current->switch_handle = (void *)1;
    1393                 :             : #endif
    1394                 :             :                         z_dummy_thread_init(&_thread_dummy);
    1395                 :             : 
    1396                 :             :                 }
    1397                 :             : 
    1398                 :             :                 /* Finally update the halting thread state, on which
    1399                 :             :                  * other CPUs might be spinning (see
    1400                 :             :                  * thread_halt_spin()).
    1401                 :             :                  */
    1402                 :          46 :                 clear_halting(thread);
    1403                 :             :         }
    1404                 :             : }
    1405                 :             : #ifdef IAR_SUPPRESS_ALWAYS_INLINE_WARNING_FLAG
    1406                 :             : TOOLCHAIN_ENABLE_WARNING(TOOLCHAIN_WARNING_ALWAYS_INLINE)
    1407                 :             : #endif
    1408                 :             : 
    1409                 :          88 : void z_thread_abort(struct k_thread *thread)
    1410                 :             : {
    1411                 :          88 :         bool essential = z_is_thread_essential(thread);
    1412                 :          88 :         k_spinlock_key_t key = k_spin_lock(&_sched_spinlock);
    1413                 :             : 
    1414         [ +  + ]:          88 :         if (z_is_thread_dead(thread)) {
    1415                 :          42 :                 k_spin_unlock(&_sched_spinlock, key);
    1416                 :          42 :                 return;
    1417                 :             :         }
    1418                 :             : 
    1419                 :          46 :         z_thread_halt(thread, key, true);
    1420                 :             : 
    1421         [ #  # ]:           0 :         if (essential) {
    1422                 :           0 :                 __ASSERT(!essential, "aborted essential thread %p", thread);
    1423                 :           0 :                 k_panic();
    1424                 :             :         }
    1425                 :             : }
    1426                 :             : 
    1427                 :             : #if !defined(CONFIG_ARCH_HAS_THREAD_ABORT)
    1428                 :             : void z_impl_k_thread_abort(k_tid_t thread)
    1429                 :             : {
    1430                 :             :         SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_thread, abort, thread);
    1431                 :             : 
    1432                 :             :         z_thread_abort(thread);
    1433                 :             : 
    1434                 :             :         __ASSERT_NO_MSG(z_is_thread_dead(thread));
    1435                 :             : 
    1436                 :             :         SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_thread, abort, thread);
    1437                 :             : }
    1438                 :             : #endif /* !CONFIG_ARCH_HAS_THREAD_ABORT */
    1439                 :             : 
    1440                 :          46 : int z_impl_k_thread_join(struct k_thread *thread, k_timeout_t timeout)
    1441                 :             : {
    1442                 :          46 :         k_spinlock_key_t key = k_spin_lock(&_sched_spinlock);
    1443                 :          46 :         int ret;
    1444                 :             : 
    1445                 :          46 :         SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_thread, join, thread, timeout);
    1446                 :             : 
    1447         [ +  + ]:          46 :         if (z_is_thread_dead(thread)) {
    1448                 :             :                 z_sched_switch_spin(thread);
    1449                 :          40 :                 ret = 0;
    1450         [ +  - ]:           6 :         } else if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {
    1451                 :             :                 ret = -EBUSY;
    1452         [ +  - ]:           6 :         } else if ((thread == _current) ||
    1453         [ +  - ]:           6 :                    (thread->base.pended_on == &_current->join_queue)) {
    1454                 :             :                 ret = -EDEADLK;
    1455                 :             :         } else {
    1456         [ -  + ]:           6 :                 __ASSERT(!arch_is_in_isr(), "cannot join in ISR");
    1457                 :           6 :                 add_to_waitq_locked(_current, &thread->join_queue);
    1458                 :           6 :                 add_thread_timeout(_current, timeout);
    1459                 :             : 
    1460                 :           6 :                 SYS_PORT_TRACING_OBJ_FUNC_BLOCKING(k_thread, join, thread, timeout);
    1461                 :           6 :                 ret = z_swap(&_sched_spinlock, key);
    1462                 :           6 :                 SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_thread, join, thread, timeout, ret);
    1463                 :             : 
    1464                 :           6 :                 return ret;
    1465                 :             :         }
    1466                 :             : 
    1467                 :          40 :         SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_thread, join, thread, timeout, ret);
    1468                 :             : 
    1469                 :          40 :         k_spin_unlock(&_sched_spinlock, key);
    1470                 :          40 :         return ret;
    1471                 :             : }
    1472                 :             : 
    1473                 :             : #ifdef CONFIG_USERSPACE
    1474                 :             : /* Special case: don't oops if the thread is uninitialized.  This is because
    1475                 :             :  * the initialization bit does double-duty for thread objects; if false, means
    1476                 :             :  * the thread object is truly uninitialized, or the thread ran and exited for
    1477                 :             :  * some reason.
    1478                 :             :  *
    1479                 :             :  * Return true in this case indicating we should just do nothing and return
    1480                 :             :  * success to the caller.
    1481                 :             :  */
    1482                 :             : static bool thread_obj_validate(struct k_thread *thread)
    1483                 :             : {
    1484                 :             :         struct k_object *ko = k_object_find(thread);
    1485                 :             :         int ret = k_object_validate(ko, K_OBJ_THREAD, _OBJ_INIT_TRUE);
    1486                 :             : 
    1487                 :             :         switch (ret) {
    1488                 :             :         case 0:
    1489                 :             :                 return false;
    1490                 :             :         case -EINVAL:
    1491                 :             :                 return true;
    1492                 :             :         default:
    1493                 :             : #ifdef CONFIG_LOG
    1494                 :             :                 k_object_dump_error(ret, thread, ko, K_OBJ_THREAD);
    1495                 :             : #endif /* CONFIG_LOG */
    1496                 :             :                 K_OOPS(K_SYSCALL_VERIFY_MSG(ret, "access denied"));
    1497                 :             :         }
    1498                 :             :         CODE_UNREACHABLE; /* LCOV_EXCL_LINE */
    1499                 :             : }
    1500                 :             : 
    1501                 :             : static inline int z_vrfy_k_thread_join(struct k_thread *thread,
    1502                 :             :                                        k_timeout_t timeout)
    1503                 :             : {
    1504                 :             :         if (thread_obj_validate(thread)) {
    1505                 :             :                 return 0;
    1506                 :             :         }
    1507                 :             : 
    1508                 :             :         return z_impl_k_thread_join(thread, timeout);
    1509                 :             : }
    1510                 :             : #include <zephyr/syscalls/k_thread_join_mrsh.c>
    1511                 :             : 
    1512                 :             : static inline void z_vrfy_k_thread_abort(k_tid_t thread)
    1513                 :             : {
    1514                 :             :         if (thread_obj_validate(thread)) {
    1515                 :             :                 return;
    1516                 :             :         }
    1517                 :             : 
    1518                 :             :         K_OOPS(K_SYSCALL_VERIFY_MSG(!z_is_thread_essential(thread),
    1519                 :             :                                     "aborting essential thread %p", thread));
    1520                 :             : 
    1521                 :             :         z_impl_k_thread_abort((struct k_thread *)thread);
    1522                 :             : }
    1523                 :             : #include <zephyr/syscalls/k_thread_abort_mrsh.c>
    1524                 :             : #endif /* CONFIG_USERSPACE */
    1525                 :             : 
    1526                 :             : /*
    1527                 :             :  * future scheduler.h API implementations
    1528                 :             :  */
    1529                 :           0 : bool z_sched_wake(_wait_q_t *wait_q, int swap_retval, void *swap_data)
    1530                 :             : {
    1531                 :           0 :         struct k_thread *thread;
    1532                 :           0 :         bool ret = false;
    1533                 :             : 
    1534         [ #  # ]:           0 :         K_SPINLOCK(&_sched_spinlock) {
    1535                 :           0 :                 thread = _priq_wait_best(&wait_q->waitq);
    1536                 :             : 
    1537         [ #  # ]:           0 :                 if (thread != NULL) {
    1538                 :           0 :                         z_thread_return_value_set_with_data(thread,
    1539                 :             :                                                             swap_retval,
    1540                 :             :                                                             swap_data);
    1541                 :           0 :                         unpend_thread_no_timeout(thread);
    1542                 :           0 :                         z_abort_thread_timeout(thread);
    1543                 :           0 :                         ready_thread(thread);
    1544                 :           0 :                         ret = true;
    1545                 :             :                 }
    1546                 :             :         }
    1547                 :             : 
    1548                 :           0 :         return ret;
    1549                 :             : }
    1550                 :             : 
    1551                 :           0 : int z_sched_wait(struct k_spinlock *lock, k_spinlock_key_t key,
    1552                 :             :                  _wait_q_t *wait_q, k_timeout_t timeout, void **data)
    1553                 :             : {
    1554                 :           0 :         int ret = z_pend_curr(lock, key, wait_q, timeout);
    1555                 :             : 
    1556         [ #  # ]:           0 :         if (data != NULL) {
    1557                 :           0 :                 *data = _current->base.swap_data;
    1558                 :             :         }
    1559                 :           0 :         return ret;
    1560                 :             : }
    1561                 :             : 
    1562                 :           0 : int z_sched_waitq_walk(_wait_q_t  *wait_q,
    1563                 :             :                        int (*func)(struct k_thread *, void *), void *data)
    1564                 :             : {
    1565                 :           0 :         struct k_thread *thread;
    1566                 :           0 :         int  status = 0;
    1567                 :             : 
    1568         [ #  # ]:           0 :         K_SPINLOCK(&_sched_spinlock) {
    1569         [ #  # ]:           0 :                 _WAIT_Q_FOR_EACH(wait_q, thread) {
    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 = func(thread, data);
    1578         [ #  # ]:           0 :                         if (status != 0) {
    1579                 :             :                                 break;
    1580                 :             :                         }
    1581                 :             :                 }
    1582                 :             :         }
    1583                 :             : 
    1584                 :           0 :         return status;
    1585                 :             : }
    1586                 :             : 
    1587                 :             : /* This routine exists for benchmarking purposes. It is not used in
    1588                 :             :  * general production code.
    1589                 :             :  */
    1590                 :           0 : void z_unready_thread(struct k_thread *thread)
    1591                 :             : {
    1592         [ #  # ]:           0 :         K_SPINLOCK(&_sched_spinlock) {
    1593                 :           0 :                 unready_thread(thread);
    1594                 :             :         }
    1595                 :           0 : }
        

Generated by: LCOV version 2.0-1