LCOV - code coverage report
Current view: top level - kernel - sched.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 172 474 36.3 %
Date: 2022-08-18 11:36:24 Functions: 38 79 48.1 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 54 242 22.3 %

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

Generated by: LCOV version 1.14