123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814 |
- /*
- * Copyright (c) 2012-2018 Richard Braun.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- *
- * The thread module aims at providing an interface suitable to implement
- * POSIX scheduling policies. As such, it provides scheduling classes and
- * policies that closely match the standard ones. The "real-time" policies
- * (FIFO and RR) directly map the first-in first-out (SCHED_FIFO) and
- * round-robin (SCHED_RR) policies, while the "fair-scheduling" policy (FS)
- * can be used for the normal SCHED_OTHER policy. The idle policy is reserved
- * for idling kernel threads.
- *
- * By convention, the name of a kernel thread is built by concatenating the
- * kernel name and the name of the start function, separated with an underscore.
- * Threads that are bound to a processor also include the "/cpu_id" suffix.
- * For example, "x15_thread_balance/1" is the name of the inter-processor
- * balancer thread of the second processor.
- */
- #ifndef KERN_THREAD_H
- #define KERN_THREAD_H
- #include <assert.h>
- #include <stdbool.h>
- #include <stddef.h>
- #include <stdint.h>
- #include <stdnoreturn.h>
- #include <kern/atomic.h>
- #include <kern/init.h>
- #include <kern/cpumap.h>
- #include <kern/kernel.h>
- #include <kern/macros.h>
- #include <kern/spinlock_types.h>
- #include <kern/turnstile_types.h>
- #include <machine/cpu.h>
- #include <machine/tcb.h>
- /*
- * Thread structure.
- */
- struct thread;
- /*
- * The global priority of a thread is meant to be compared against
- * another global priority to determine which thread has higher priority.
- */
- struct thread_sched_data {
- unsigned char sched_policy;
- unsigned char sched_class;
- unsigned short priority;
- unsigned int global_priority;
- };
- /*
- * Thread name buffer size.
- */
- #define THREAD_NAME_SIZE 32
- #include <kern/thread_i.h>
- #define THREAD_KERNEL_PREFIX KERNEL_NAME "_"
- /*
- * Thread states.
- */
- #define THREAD_RUNNING 0
- #define THREAD_SLEEPING 1
- #define THREAD_DEAD 2
- #define THREAD_SUSPENDED 3
- /*
- * Scheduling policies.
- *
- * The idle policy is reserved for the per-CPU idle threads.
- */
- #define THREAD_SCHED_POLICY_FIFO 0
- #define THREAD_SCHED_POLICY_RR 1
- #define THREAD_SCHED_POLICY_FS 2
- #define THREAD_SCHED_POLICY_IDLE 3
- #define THREAD_NR_SCHED_POLICIES 4
- /*
- * Real-time priority properties.
- */
- #define THREAD_SCHED_RT_PRIO_MIN 0
- #define THREAD_SCHED_RT_PRIO_MAX 31
- /*
- * Fair-scheduling priority properties.
- */
- #define THREAD_SCHED_FS_PRIO_MIN 0
- #define THREAD_SCHED_FS_PRIO_DEFAULT 20
- #define THREAD_SCHED_FS_PRIO_MAX 39
- /*
- * Thread creation attributes.
- */
- struct thread_attr {
- const char *name;
- unsigned long flags;
- struct cpumap *cpumap;
- struct task *task;
- unsigned char policy;
- unsigned short priority;
- };
- /*
- * Initialize thread creation attributes with default values.
- *
- * It is guaranteed that these default values include :
- * - thread is joinable
- * - no processor affinity
- * - task is inherited from parent thread
- * - policy is fair-scheduling
- * - priority is fair-scheduling default
- *
- * If the policy is changed, the priority, if applicable, must be updated
- * as well.
- */
- static inline void
- thread_attr_init(struct thread_attr *attr, const char *name)
- {
- attr->name = name;
- attr->flags = 0;
- attr->cpumap = NULL;
- attr->task = NULL;
- attr->policy = THREAD_SCHED_POLICY_FS;
- attr->priority = THREAD_SCHED_FS_PRIO_DEFAULT;
- }
- static inline void
- thread_attr_set_detached(struct thread_attr *attr)
- {
- attr->flags |= THREAD_ATTR_DETACHED;
- }
- static inline void
- thread_attr_set_cpumap(struct thread_attr *attr, struct cpumap *cpumap)
- {
- attr->cpumap = cpumap;
- }
- static inline void
- thread_attr_set_task(struct thread_attr *attr, struct task *task)
- {
- attr->task = task;
- }
- static inline void
- thread_attr_set_policy(struct thread_attr *attr, unsigned char policy)
- {
- attr->policy = policy;
- }
- static inline void
- thread_attr_set_priority(struct thread_attr *attr, unsigned short priority)
- {
- attr->priority = priority;
- }
- /*
- * Thread entry point.
- *
- * Loaded TCBs are expected to call this function with interrupts disabled.
- */
- void thread_main(void (*fn)(void *), void *arg);
- /*
- * Initialization of the thread module on APs.
- */
- void thread_ap_setup(void);
- /*
- * Create a thread.
- *
- * Creation attributes must be passed, but some of them may be NULL, in which
- * case the value is inherited from the caller. The name attribute must not be
- * NULL.
- *
- * If successful, and if the caller passed a non-NULL thread pointer, it is
- * filled with the address of the newly created thread.
- */
- int thread_create(struct thread **threadp, const struct thread_attr *attr,
- void (*fn)(void *), void *arg);
- /*
- * Terminate the calling thread.
- */
- noreturn void thread_exit(void);
- /*
- * Wait for the given thread to terminate and release its resources.
- */
- void thread_join(struct thread *thread);
- /*
- * Make the current thread sleep while waiting for an event.
- *
- * The interlock is used to synchronize the thread state with respect to
- * wake-ups, i.e. a wake-up request sent by another thread cannot be missed
- * if that thread is holding the interlock.
- *
- * As a special exception, threads that use preemption as a synchronization
- * mechanism can omit the interlock and pass a NULL pointer instead.
- * In any case, the preemption nesting level must strictly be one when calling
- * this function.
- *
- * The wait channel describes the reason why the thread is sleeping. The
- * address should refer to a relevant synchronization object, normally
- * containing the interlock, but not necessarily.
- *
- * When bounding the duration of the sleep, the caller must pass an absolute
- * time in ticks, and ETIMEDOUT is returned if that time is reached before
- * the thread is awoken.
- *
- * Implies a memory barrier.
- */
- void thread_sleep(struct spinlock *interlock, const void *wchan_addr,
- const char *wchan_desc);
- int thread_timedsleep(struct spinlock *interlock, const void *wchan_addr,
- const char *wchan_desc, uint64_t ticks);
- /*
- * Schedule a thread for execution on a processor.
- *
- * If the target thread is NULL, the calling thread, or already in the
- * running state, or in the suspended state, no action is performed and
- * EINVAL is returned.
- *
- * TODO Describe memory ordering with regard to thread_sleep().
- */
- int thread_wakeup(struct thread *thread);
- /*
- * Suspend a thread.
- *
- * A suspended thread may only be resumed by calling thread_resume().
- *
- * This operation is asynchronous, i.e. the caller must not expect the target
- * thread to be suspended on return.
- *
- * If attempting to suspend core system threads, or threads in the dead state,
- * or if the given thread is NULL, the request is ignored and EINVAL is
- * returned. If the target thread is already suspended, the call turns into
- * a no-op and merely returns success.
- */
- int thread_suspend(struct thread *thread);
- /*
- * Resume a thread.
- *
- * This call is equivalent to thread_wakeup(), with the exception that
- * it may also wake up suspended threads.
- */
- int thread_resume(struct thread *thread);
- /*
- * Suspend execution of the calling thread.
- */
- void thread_delay(uint64_t ticks, bool absolute);
- /*
- * Start running threads on the local processor.
- *
- * Interrupts must be disabled when calling this function.
- */
- noreturn void thread_run_scheduler(void);
- /*
- * Make the calling thread release the processor.
- *
- * This call does nothing if preemption is disabled, or the scheduler
- * determines the caller should continue to run (e.g. it's currently the only
- * runnable thread).
- *
- * Implies a full memory barrier if a context switch occurred.
- */
- void thread_yield(void);
- /*
- * Report a scheduling interrupt from a remote processor.
- */
- void thread_schedule_intr(void);
- /*
- * Report a periodic event on the current processor.
- *
- * Interrupts and preemption must be disabled when calling this function.
- */
- void thread_report_periodic_event(void);
- /*
- * Set thread scheduling parameters.
- */
- void thread_setscheduler(struct thread *thread, unsigned char policy,
- unsigned short priority);
- /*
- * Variant used for priority inheritance.
- *
- * The caller must hold the turnstile thread data lock and no turnstile
- * locks when calling this function.
- */
- void thread_pi_setscheduler(struct thread *thread, unsigned char policy,
- unsigned short priority);
- static inline void
- thread_ref(struct thread *thread)
- {
- unsigned long nr_refs;
- nr_refs = atomic_fetch_add(&thread->nr_refs, 1UL, ATOMIC_RELAXED);
- assert(nr_refs != (unsigned long)-1);
- }
- static inline void
- thread_unref(struct thread *thread)
- {
- unsigned long nr_refs;
- nr_refs = atomic_fetch_sub(&thread->nr_refs, 1UL, ATOMIC_ACQ_REL);
- assert(nr_refs != 0);
- if (nr_refs == 1) {
- thread_terminate(thread);
- }
- }
- static inline const void *
- thread_wchan_addr(const struct thread *thread)
- {
- return thread->wchan_addr;
- }
- static inline const char *
- thread_wchan_desc(const struct thread *thread)
- {
- return thread->wchan_desc;
- }
- /*
- * Return a character representation of the state of a thread.
- */
- char thread_state_to_chr(unsigned int state);
- static inline const struct thread_sched_data *
- thread_get_user_sched_data(const struct thread *thread)
- {
- return &thread->user_sched_data;
- }
- static inline const struct thread_sched_data *
- thread_get_real_sched_data(const struct thread *thread)
- {
- return &thread->real_sched_data;
- }
- /*
- * If the caller requires the scheduling data to be stable, it
- * must lock one of the following objects :
- * - the containing run queue
- * - the per-thread turnstile data (turnstile_td)
- *
- * Both are locked when scheduling data are updated.
- */
- static inline unsigned char
- thread_user_sched_policy(const struct thread *thread)
- {
- return thread_get_user_sched_data(thread)->sched_policy;
- }
- static inline unsigned char
- thread_user_sched_class(const struct thread *thread)
- {
- return thread_get_user_sched_data(thread)->sched_class;
- }
- static inline unsigned short
- thread_user_priority(const struct thread *thread)
- {
- return thread_get_user_sched_data(thread)->priority;
- }
- static inline unsigned int
- thread_user_global_priority(const struct thread *thread)
- {
- return thread_get_user_sched_data(thread)->global_priority;
- }
- static inline unsigned char
- thread_real_sched_policy(const struct thread *thread)
- {
- return thread_get_real_sched_data(thread)->sched_policy;
- }
- static inline unsigned char
- thread_real_sched_class(const struct thread *thread)
- {
- return thread_get_real_sched_data(thread)->sched_class;
- }
- static inline unsigned short
- thread_real_priority(const struct thread *thread)
- {
- return thread_get_real_sched_data(thread)->priority;
- }
- static inline unsigned int
- thread_real_global_priority(const struct thread *thread)
- {
- return thread_get_real_sched_data(thread)->global_priority;
- }
- /*
- * Return a string representation of the scheduling class of a thread.
- */
- const char * thread_sched_class_to_str(unsigned char sched_class);
- static inline struct tcb *
- thread_get_tcb(struct thread *thread)
- {
- return &thread->tcb;
- }
- static inline struct thread *
- thread_from_tcb(struct tcb *tcb)
- {
- return structof(tcb, struct thread, tcb);
- }
- static inline struct thread *
- thread_self(void)
- {
- return thread_from_tcb(tcb_current());
- }
- /*
- * Main scheduler invocation call.
- *
- * Called on return from interrupt or when reenabling preemption.
- */
- void thread_schedule(void);
- /*
- * Sleep queue lending functions.
- */
- static inline struct sleepq *
- thread_sleepq_lend(void)
- {
- struct sleepq *sleepq;
- sleepq = thread_self()->priv_sleepq;
- assert(sleepq != NULL);
- thread_self()->priv_sleepq = NULL;
- return sleepq;
- }
- static inline void
- thread_sleepq_return(struct sleepq *sleepq)
- {
- assert(sleepq != NULL);
- assert(thread_self()->priv_sleepq == NULL);
- thread_self()->priv_sleepq = sleepq;
- }
- /*
- * Turnstile lending functions.
- */
- static inline struct turnstile *
- thread_turnstile_lend(void)
- {
- struct turnstile *turnstile;
- turnstile = thread_self()->priv_turnstile;
- assert(turnstile != NULL);
- thread_self()->priv_turnstile = NULL;
- return turnstile;
- }
- static inline void
- thread_turnstile_return(struct turnstile *turnstile)
- {
- assert(turnstile != NULL);
- assert(thread_self()->priv_turnstile == NULL);
- thread_self()->priv_turnstile = turnstile;
- }
- static inline struct turnstile_td *
- thread_turnstile_td(struct thread *thread)
- {
- return &thread->turnstile_td;
- }
- /*
- * Priority propagation functions.
- */
- static inline bool
- thread_priority_propagation_needed(void)
- {
- return thread_self()->propagate_priority;
- }
- static inline void
- thread_set_priority_propagation_needed(void)
- {
- thread_self()->propagate_priority = true;
- }
- void thread_propagate_priority(void);
- /*
- * Migration control functions.
- *
- * Functions that change the migration state are implicit compiler barriers.
- */
- static inline int
- thread_pinned(void)
- {
- return thread_self()->pin_level != 0;
- }
- static inline void
- thread_pin(void)
- {
- struct thread *thread;
- thread = thread_self();
- thread->pin_level++;
- assert(thread->pin_level != 0);
- barrier();
- }
- static inline void
- thread_unpin(void)
- {
- struct thread *thread;
- barrier();
- thread = thread_self();
- assert(thread->pin_level != 0);
- thread->pin_level--;
- }
- /*
- * Preemption control functions.
- *
- * Functions that change the preemption state are implicit compiler barriers.
- */
- static inline int
- thread_preempt_enabled(void)
- {
- return thread_self()->preempt_level == 0;
- }
- static inline void
- thread_preempt_disable(void)
- {
- struct thread *thread;
- thread = thread_self();
- thread->preempt_level++;
- assert(thread->preempt_level != 0);
- barrier();
- }
- static inline void
- thread_preempt_enable_no_resched(void)
- {
- struct thread *thread;
- barrier();
- thread = thread_self();
- assert(thread->preempt_level != 0);
- thread->preempt_level--;
- /*
- * Don't perform priority propagation here, because this function is
- * called on return from interrupt, where the transient state may
- * incorrectly trigger it.
- */
- }
- static inline void
- thread_preempt_enable(void)
- {
- thread_preempt_enable_no_resched();
- if (thread_priority_propagation_needed()
- && thread_preempt_enabled()) {
- thread_propagate_priority();
- }
- thread_schedule();
- }
- static inline void
- thread_preempt_disable_intr_save(unsigned long *flags)
- {
- thread_preempt_disable();
- cpu_intr_save(flags);
- }
- static inline void
- thread_preempt_enable_intr_restore(unsigned long flags)
- {
- cpu_intr_restore(flags);
- thread_preempt_enable();
- }
- /*
- * Interrupt level control functions.
- *
- * Functions that change the interrupt level are implicit compiler barriers.
- */
- static inline bool
- thread_interrupted(void)
- {
- return thread_self()->intr_level != 0;
- }
- static inline bool
- thread_check_intr_context(void)
- {
- return thread_interrupted()
- && !cpu_intr_enabled()
- && !thread_preempt_enabled();
- }
- static inline void
- thread_intr_enter(void)
- {
- struct thread *thread;
- thread = thread_self();
- if (thread->intr_level == 0) {
- thread_preempt_disable();
- }
- thread->intr_level++;
- assert(thread->intr_level != 0);
- barrier();
- }
- static inline void
- thread_intr_leave(void)
- {
- struct thread *thread;
- barrier();
- thread = thread_self();
- assert(thread->intr_level != 0);
- thread->intr_level--;
- if (thread->intr_level == 0) {
- thread_preempt_enable_no_resched();
- }
- }
- /*
- * RCU functions.
- */
- static inline struct rcu_reader *
- thread_rcu_reader(struct thread *thread)
- {
- return &thread->rcu_reader;
- }
- /*
- * Thread-specific data functions.
- */
- #if CONFIG_THREAD_MAX_TSD_KEYS != 0
- /*
- * Type for thread-specific data destructor.
- */
- typedef void (*thread_tsd_dtor_fn_t)(void *);
- /*
- * Allocate a TSD key.
- *
- * If not NULL, the destructor is called on thread destruction on the pointer
- * associated with the allocated key.
- */
- void thread_key_create(unsigned int *keyp, thread_tsd_dtor_fn_t dtor);
- /*
- * Set the pointer associated with a key for the given thread.
- */
- static inline void
- thread_tsd_set(struct thread *thread, unsigned int key, void *ptr)
- {
- thread->tsd[key] = ptr;
- }
- /*
- * Return the pointer associated with a key for the given thread.
- */
- static inline void *
- thread_tsd_get(struct thread *thread, unsigned int key)
- {
- return thread->tsd[key];
- }
- /*
- * Set the pointer associated with a key for the calling thread.
- */
- static inline void
- thread_set_specific(unsigned int key, void *ptr)
- {
- thread_tsd_set(thread_self(), key, ptr);
- }
- /*
- * Return the pointer associated with a key for the calling thread.
- */
- static inline void *
- thread_get_specific(unsigned int key)
- {
- return thread_tsd_get(thread_self(), key);
- }
- #endif /* CONFIG_THREAD_MAX_TSD_KEYS != 0 */
- static inline const char *
- thread_name(const struct thread *thread)
- {
- return thread->name;
- }
- #ifdef CONFIG_PERFMON
- static inline struct perfmon_td *
- thread_get_perfmon_td(struct thread *thread)
- {
- return &thread->perfmon_td;
- }
- #endif /* CONFIG_PERFMON */
- /*
- * Return the last CPU on which the thread has been scheduled.
- *
- * This call isn't synchronized, and the caller may obtain an outdated value.
- */
- unsigned int thread_cpu(const struct thread *thread);
- /*
- * Return the current state of the given thread.
- *
- * This call isn't synchronized, and the caller may obtain an outdated value.
- */
- unsigned int thread_state(const struct thread *thread);
- /*
- * Return true if the given thread is running.
- *
- * This call isn't synchronized, and the caller may obtain an outdated value.
- */
- bool thread_is_running(const struct thread *thread);
- /*
- * Get the CPU affinity mask of the specified thread.
- */
- int thread_get_affinity(const struct thread *thread, struct cpumap *cpumap);
- /*
- * Set the CPU affinity mask for the specified thread.
- */
- int thread_set_affinity(struct thread *thread, const struct cpumap *cpumap);
- /*
- * This init operation provides :
- * - a dummy thread context for the BSP, allowing the use of thread_self()
- */
- INIT_OP_DECLARE(thread_setup_booter);
- /*
- * This init operation provides :
- * - same as thread_setup_booter
- * - BSP run queue initialization
- */
- INIT_OP_DECLARE(thread_bootstrap);
- /*
- * This init operation provides :
- * - thread creation
- * - module fully initialized
- */
- INIT_OP_DECLARE(thread_setup);
- #endif /* KERN_THREAD_H */
|