/* * Copyright (c) 2016-2017 Wind River Systems, Inc. * Copyright (c) 2024 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ #ifndef ZEPHYR_KERNEL_INCLUDE_THREAD_H_ #define ZEPHYR_KERNEL_INCLUDE_THREAD_H_ #include #include #include #define Z_STATE_STR_DUMMY "dummy" #define Z_STATE_STR_PENDING "pending" #define Z_STATE_STR_PRESTART "prestart" #define Z_STATE_STR_DEAD "dead" #define Z_STATE_STR_SUSPENDED "suspended" #define Z_STATE_STR_ABORTING "aborting" #define Z_STATE_STR_SUSPENDING "suspending" #define Z_STATE_STR_QUEUED "queued" #ifdef CONFIG_THREAD_MONITOR /* This lock protects the linked list of active threads; i.e. the * initial _kernel.threads pointer and the linked list made up of * thread->next_thread (until NULL) */ extern struct k_spinlock z_thread_monitor_lock; #endif /* CONFIG_THREAD_MONITOR */ void idle(void *unused1, void *unused2, void *unused3); /* clean up when a thread is aborted */ #if defined(CONFIG_THREAD_MONITOR) void z_thread_monitor_exit(struct k_thread *thread); #else #define z_thread_monitor_exit(thread) \ do {/* nothing */ \ } while (false) #endif /* CONFIG_THREAD_MONITOR */ static inline void thread_schedule_new(struct k_thread *thread, k_timeout_t delay) { #ifdef CONFIG_SYS_CLOCK_EXISTS if (K_TIMEOUT_EQ(delay, K_NO_WAIT)) { k_thread_start(thread); } else { z_add_thread_timeout(thread, delay); } #else ARG_UNUSED(delay); k_thread_start(thread); #endif /* CONFIG_SYS_CLOCK_EXISTS */ } static inline int thread_is_preemptible(struct k_thread *thread) { /* explanation in kernel_struct.h */ return thread->base.preempt <= _PREEMPT_THRESHOLD; } static inline int thread_is_metairq(struct k_thread *thread) { #if CONFIG_NUM_METAIRQ_PRIORITIES > 0 return (thread->base.prio - K_HIGHEST_THREAD_PRIO) < CONFIG_NUM_METAIRQ_PRIORITIES; #else ARG_UNUSED(thread); return 0; #endif /* CONFIG_NUM_METAIRQ_PRIORITIES */ } #ifdef CONFIG_ASSERT static inline bool is_thread_dummy(struct k_thread *thread) { return (thread->base.thread_state & _THREAD_DUMMY) != 0U; } #endif /* CONFIG_ASSERT */ static inline bool z_is_thread_suspended(struct k_thread *thread) { return (thread->base.thread_state & _THREAD_SUSPENDED) != 0U; } static inline bool z_is_thread_pending(struct k_thread *thread) { return (thread->base.thread_state & _THREAD_PENDING) != 0U; } static inline bool z_is_thread_prevented_from_running(struct k_thread *thread) { uint8_t state = thread->base.thread_state; return (state & (_THREAD_PENDING | _THREAD_PRESTART | _THREAD_DEAD | _THREAD_DUMMY | _THREAD_SUSPENDED)) != 0U; } static inline bool z_is_thread_timeout_active(struct k_thread *thread) { return !z_is_inactive_timeout(&thread->base.timeout); } static inline bool z_is_thread_ready(struct k_thread *thread) { return !((z_is_thread_prevented_from_running(thread)) != 0U || z_is_thread_timeout_active(thread)); } static inline bool z_has_thread_started(struct k_thread *thread) { return (thread->base.thread_state & _THREAD_PRESTART) == 0U; } static inline bool z_is_thread_state_set(struct k_thread *thread, uint32_t state) { return (thread->base.thread_state & state) != 0U; } static inline bool z_is_thread_queued(struct k_thread *thread) { return z_is_thread_state_set(thread, _THREAD_QUEUED); } static inline void z_mark_thread_as_suspended(struct k_thread *thread) { thread->base.thread_state |= _THREAD_SUSPENDED; SYS_PORT_TRACING_FUNC(k_thread, sched_suspend, thread); } static inline void z_mark_thread_as_not_suspended(struct k_thread *thread) { thread->base.thread_state &= ~_THREAD_SUSPENDED; SYS_PORT_TRACING_FUNC(k_thread, sched_resume, thread); } static inline void z_mark_thread_as_started(struct k_thread *thread) { thread->base.thread_state &= ~_THREAD_PRESTART; } static inline void z_mark_thread_as_pending(struct k_thread *thread) { thread->base.thread_state |= _THREAD_PENDING; } static inline void z_mark_thread_as_not_pending(struct k_thread *thread) { thread->base.thread_state &= ~_THREAD_PENDING; } /* * This function tags the current thread as essential to system operation. * Exceptions raised by this thread will be treated as a fatal system error. */ static inline void z_thread_essential_set(struct k_thread *thread) { thread->base.user_options |= K_ESSENTIAL; } /* * This function tags the current thread as not essential to system operation. * Exceptions raised by this thread may be recoverable. * (This is the default tag for a thread.) */ static inline void z_thread_essential_clear(struct k_thread *thread) { thread->base.user_options &= ~K_ESSENTIAL; } /* * This routine indicates if the current thread is an essential system thread. * * Returns true if current thread is essential, false if it is not. */ static inline bool z_is_thread_essential(struct k_thread *thread) { return (thread->base.user_options & K_ESSENTIAL) == K_ESSENTIAL; } static ALWAYS_INLINE bool should_preempt(struct k_thread *thread, int preempt_ok) { /* Preemption is OK if it's being explicitly allowed by * software state (e.g. the thread called k_yield()) */ if (preempt_ok != 0) { return true; } __ASSERT(_current != NULL, ""); /* Or if we're pended/suspended/dummy (duh) */ if (z_is_thread_prevented_from_running(_current)) { return true; } /* Edge case on ARM where a thread can be pended out of an * interrupt handler before the "synchronous" swap starts * context switching. Platforms with atomic swap can never * hit this. */ if (IS_ENABLED(CONFIG_SWAP_NONATOMIC) && z_is_thread_timeout_active(thread)) { return true; } /* Otherwise we have to be running a preemptible thread or * switching to a metairq */ if (thread_is_preemptible(_current) || thread_is_metairq(thread)) { return true; } return false; } static inline bool z_is_idle_thread_entry(void *entry_point) { return entry_point == idle; } static inline bool z_is_idle_thread_object(struct k_thread *thread) { #ifdef CONFIG_MULTITHREADING #ifdef CONFIG_SMP return thread->base.is_idle; #else return thread == &z_idle_threads[0]; #endif /* CONFIG_SMP */ #else return false; #endif /* CONFIG_MULTITHREADING */ } #endif /* ZEPHYR_KERNEL_INCLUDE_THREAD_H_ */