/* SPDX-License-Identifier: GPL-2.0-only */ #ifndef THREAD_H_ #define THREAD_H_ #include #include #include #include struct thread_mutex { bool locked; }; enum thread_state { THREAD_UNINITIALIZED, THREAD_STARTED, THREAD_DONE, }; struct thread_handle { enum thread_state state; /* Only valid when state == THREAD_DONE */ enum cb_err error; }; /* Run func(arg) on a new thread. Return 0 on successful start of thread, < 0 * when thread could not be started. The thread handle if populated, will * reflect the state and return code of the thread. */ int thread_run(struct thread_handle *handle, enum cb_err (*func)(void *), void *arg); /* thread_run_until is the same as thread_run() except that it blocks state * transitions from occurring in the (state, seq) pair of the boot state * machine. */ int thread_run_until(struct thread_handle *handle, enum cb_err (*func)(void *), void *arg, boot_state_t state, boot_state_sequence_t seq); /* Waits until the thread has terminated and returns the error code */ enum cb_err thread_join(struct thread_handle *handle); #if ENV_RAMSTAGE && CONFIG(COOP_MULTITASKING) struct thread { int id; uintptr_t stack_current; uintptr_t stack_orig; struct thread *next; enum cb_err (*entry)(void *); void *entry_arg; int can_yield; struct thread_handle *handle; }; void threads_initialize(void); /* Get the base of the thread stacks. * Returns pointer to CONFIG_NUM_THREADS*CONFIG_STACK_SIZE contiguous bytes * aligned to CONFIG_STACK_SIZE, or NULL. */ void *arch_get_thread_stackbase(void); /* Return 0 on successful yield, < 0 when thread did not yield. */ int thread_yield(void); /* Return 0 on successful yield for the given amount of time, < 0 when thread * did not yield. */ int thread_yield_microseconds(unsigned int microsecs); /* Allow and prevent thread cooperation on current running thread. By default * all threads are marked to be cooperative. That means a thread can yield * to another thread at a pre-determined switch point. i.e., udelay, * thread_yield, or thread_yield_microseconds. * * These methods should be used to guard critical sections so a dead lock does * not occur. The critical sections can be nested. Just make sure the methods * are used in pairs. */ void thread_coop_enable(void); void thread_coop_disable(void); void thread_mutex_lock(struct thread_mutex *mutex); void thread_mutex_unlock(struct thread_mutex *mutex); static inline void thread_init_cpu_info_non_bsp(struct cpu_info *ci) { ci->thread = NULL; } /* Architecture specific thread functions. */ asmlinkage void switch_to_thread(uintptr_t new_stack, uintptr_t *saved_stack); /* Set up the stack frame for a new thread so that a switch_to_thread() call * will enter the thread_entry() function with arg as a parameter. The * saved_stack field in the struct thread needs to be updated accordingly. */ void arch_prepare_thread(struct thread *t, asmlinkage void (*thread_entry)(void *), void *arg); #else static inline void threads_initialize(void) {} static inline int thread_yield(void) { return -1; } static inline int thread_yield_microseconds(unsigned int microsecs) { return -1; } static inline void thread_coop_enable(void) {} static inline void thread_coop_disable(void) {} struct cpu_info; static inline void thread_init_cpu_info_non_bsp(struct cpu_info *ci) { } static inline void thread_mutex_lock(struct thread_mutex *mutex) {} static inline void thread_mutex_unlock(struct thread_mutex *mutex) {} #endif #endif /* THREAD_H_ */