Threads
include/thread/thread.h View source View on GitHubThis header has little business being in here, we should consider moving it out of this
Structs
Section titled “Structs”cpu_context
Section titled “cpu_context” struct cpu_context (8 fields) source
thread_event_reason
Section titled “thread_event_reason” struct thread_event_reason (3 fields) source
uint16_t duration_ms wait duration (clamped to UINT16_MAX ms)
thread_act_reason_t wait_reason thread_act_reason_t wake_reason WAKE_IO, WAKE_MANUAL, WAKE_TIMEOUT…
thread_activity_bucket
Section titled “thread_activity_bucket” struct thread_activity_bucket (5 fields) source
We’re using 1024 for power of 2 division strength reduction optimizations
uint32_t epoch time_ms >> THREAD_ACTIVITY_BUCKET_SHIFT
uint16_t run_ms run duration in window (0..1024)
uint16_t block_ms blocked duration in window (0..1024)
uint16_t sleep_ms sleeping duration in window (0..1024)
uint16_t wake_count saturating wake count in window
thread_activity_stats
Section titled “thread_activity_stats” struct thread_activity_stats (1 field) source
struct thread_activity_bucket buckets[THREAD_ACTIVITY_BUCKET_COUNT] thread_activity_data
Section titled “thread_activity_data” struct thread_activity_data (4 fields) source
uint32_t wait_start_ms low 32 bits of wait start time
struct thread_event_reason events[THREAD_EVENT_RINGBUFFER_CAPACITY] uint8_t head next slot index
thread_act_reason_t active_wait_reason NONE if not waiting
thread_create_params
Section titled “thread_create_params” struct thread_create_params (10 fields) source
enum thread_prio_class base_prio_class enum thread_flags flags size_t stack_pages void *arg void *stack_internal bool pinned bool joinable void *private thread_activity_metrics
Section titled “thread_activity_metrics” struct thread_activity_metrics (4 fields) source
thread
Section titled “thread” struct thread (83 fields) source
thread_id_t id Unique ID allocated from global thread ID tree
char *name thread_entry_fn_t entry Stack
void *stack cc_sized_by(stack_size) size_t stack_size uint32_t yield_nesting we should isolate this into the debug nesting
mode, as this helps us identify scheduler_yield() nesting
uint32_t yield_nesting_max Preserves the highest point yield_nesting ever reached
struct cpu_context regs Registers
union union union int32_t wq_prio turnstile sort key TODO: there is probably a smarter way
uint64_t wq_seq Turnstile arrival order sequence count
atomic(enum thread_state) state State
atomic_uint32_t pinned_depth Who is allowed to run us?
atomic_int64_t migrate_to -1 if no migration target
Flags
enum rt_scheduler_capability accepted_rt_caps atomic(enum thread_flags) flags atomic_size_t migration_generation thread_prio_t activity_score Priorities
int32_t dynamic_delta Signed delta applied to base
size_t weight cpu_perf_t wanted_perf This is the cpu_perf_t the thread’s current CPU should try to match or do better than.
If the current CPU’s current wanted_perf does not satisfy the thread, we will try to either increase it for this CPU, or migrate the thread to another CPU.
uint64_t completed_period Timeslice info and periods
uint32_t virtual_period_runtime uint32_t virtual_budget uint32_t virtual_runtime_left enum thread_activity_class activity_class : 4 enum thread_prio_class perceived_prio_class : THREAD_PRIO_CLASS_BIT_COUNT enum thread_prio_class base_prio_class for class boosts
Rules with this lock:
This lock is meant to synchronize updates to perceived_prio_class and base_prio_class. It is only meant to be used when
(1) you are updating a thread on another CPU OR a non-running thread on THIS CPU and ALSO have the runqueue lock held prior to taking this, and will update the thread positions after doing this, OR
(2) you are updating the currently running thread on the calling CPU, it is OK to NOT have the runqueue lock held.
In any case, the scheduler will not see an invalid perceived_prio_class, and should be able to make decisions based on it, as it would be properly locked.
uint8_t class_floors[THREAD_PRIO_CLASS_COUNT] Also protected by pi_lock, perceived_prio_class = max(base_prio_class, highest class with a boost). remember to thread_recompute_prio_class_locked after changing things
Activity data
struct thread_activity_data activity_data struct thread_activity_stats activity_stats struct thread_activity_metrics activity_metrics “Overview” derived from data and stats
Lock + rc
refcount_t refcount int exit_status uint32_t rcu_nesting RCU stuff:
rcu_nesting and rcu_read_seq are written ONLY by this thread
rcu_leaf, rcu_blocked_seq, and rcu_list_node are how readers that get preempted mid-section get registered in RCU,
those are written under the leaf’s lock, either by us or the CPU switching us out
read section depth
uint64_t rcu_read_seq GP sequence at the outermost lock
uint64_t rcu_blocked_seq GP we are counted against or 0
enum thread_state wait_state enum thread_resume_reason wait_completion_reason Storage
struct thread_wait_block wait_blocks[THREAD_NUM_WAIT_BLOCKS] struct thread_wait_block *active_wait_blocks size_t wait_block_count atomic_uint64_t wait_epoch Every new wait bumps this, and it gets updated under wait_lock.
While any block of the wait remains linked, the wait header’s lock prevents this from changing, since waits can’t end, and new ones can’t start, without unlinking the respective block.
uint16_t wait_key enum thread_wait_status wait_status bool wait_done : 1 bool alert_pending : 1 bool object_wait : 1 atomic(enum thread_wait_type) wait_type uint64_t wait_timer_epoch epoch the armed timer could end
struct climb_thread_data climb_data struct wroost_thread_data wroost_data tlb_stamp_t lazy_tlb_gen struct apc_queue apc_head[APC_TYPE_COUNT] Standard APC queues
atomic_uint8_t apc_pending_mask Any APC pending
bitmask of APC_TYPE_* pending
APC disable counts
uint32_t special_apc_disable uint32_t kernel_apc_disable void *private Misc. private field for whatever needs it
Activity aggregations
thread_activity_class
Section titled “thread_activity_class” enum thread_activity_class (5 variants) source
Functions
Section titled “Functions”thread_create_internal
Section titled “thread_create_internal”struct thread * thread_create_internal(
thread_entry_fn_t entry,
struct thread_create_params params,
char *fmt
) source thread_spawn_internal
Section titled “thread_spawn_internal”struct thread * thread_spawn_internal(
thread_entry_fn_t entry,
struct thread_create_params params,
char *fmt
) source thread_set_joinable
Section titled “thread_set_joinable”thread_free
Section titled “thread_free”thread_init_thread_ids
Section titled “thread_init_thread_ids”void thread_init_thread_ids(void) source thread_exit
Section titled “thread_exit”cc_noreturn void thread_exit(void) source thread_print
Section titled “thread_print”thread_classify_activity
Section titled “thread_classify_activity”thread_update_runtime_buckets
Section titled “thread_update_runtime_buckets”thread_apply_wake_boost
Section titled “thread_apply_wake_boost”thread_update_effective_priority
Section titled “thread_update_effective_priority”thread_apply_cpu_penalty
Section titled “thread_apply_cpu_penalty”thread_add_wake_reason
Section titled “thread_add_wake_reason”void thread_add_wake_reason(
struct thread *t,
thread_act_reason_t reason
) source thread_calculate_activity_data
Section titled “thread_calculate_activity_data”thread_add_block_reason
Section titled “thread_add_block_reason”void thread_add_block_reason(
struct thread *t,
thread_act_reason_t reason
) source thread_add_sleep_reason
Section titled “thread_add_sleep_reason”void thread_add_sleep_reason(
struct thread *t,
thread_act_reason_t reason
) source thread_set_timesharing
Section titled “thread_set_timesharing”thread_set_background
Section titled “thread_set_background”thread_migrate
Section titled “thread_migrate”thread_boost_self
Section titled “thread_boost_self”void thread_boost_self(enum thread_prio_class class) source thread_unboost_self
Section titled “thread_unboost_self”void thread_unboost_self(enum thread_prio_class class) source thread_enqueue
Section titled “thread_enqueue”thread_enqueue_on_core
Section titled “thread_enqueue_on_core”thread_recompute_prio_class_locked
Section titled “thread_recompute_prio_class_locked”struct wroost_kicks cc_warn_unused_result thread_recompute_prio_class_locked(struct thread *t) source thread_recompute_prio_class_dry_locked
Section titled “thread_recompute_prio_class_dry_locked”enum thread_prio_class thread_recompute_prio_class_dry_locked(
struct thread *t,
enum thread_prio_class *old_out,
enum thread_prio_class *new_out
) source Dry run: see what the new prio would be, don’t set anything
thread_recompute_prio_class_raw_locked
Section titled “thread_recompute_prio_class_raw_locked”void thread_recompute_prio_class_raw_locked(
struct thread *t,
enum thread_prio_class *old_out,
enum thread_prio_class *new_out
) source thread_inherit_priority
Section titled “thread_inherit_priority”bool thread_inherit_priority(
struct thread *boosted,
struct thread *from,
struct thread_class_donation *d,
struct wroost_kicks *kicks_out
) source thread_donate_class
Section titled “thread_donate_class”void thread_donate_class(
struct thread *boosted,
enum thread_prio_class class,
struct thread_class_donation *d
) source thread_uninherit_priority
Section titled “thread_uninherit_priority”void thread_uninherit_priority(struct thread_class_donation *d) source thread_remove_boost
Section titled “thread_remove_boost”void thread_remove_boost(void) source thread_exit_with_status
Section titled “thread_exit_with_status”cc_noreturn void thread_exit_with_status(int status) source thread_join
Section titled “thread_join”thread_join_timeout
Section titled “thread_join_timeout”thread_detach
Section titled “thread_detach”thread_lock_two_runqueues
Section titled “thread_lock_two_runqueues”thread_lock_thread_and_rq
Section titled “thread_lock_thread_and_rq”thread_unlock_thread_and_rq
Section titled “thread_unlock_thread_and_rq”thread_in_context
Section titled “thread_in_context”bool thread_in_context(void) source thread_getref
Section titled “thread_getref” REFCOUNT_GENERATE_GETREF_FOR_STRUCT_WITH_FAILURE_COND(thread, refcount, flags, &THREAD_FLAG_DYING) (1 declaration) source
reaper_enqueue
Section titled “reaper_enqueue”thread_putref
Section titled “thread_putref”scheduler_yield_nesting
Section titled “scheduler_yield_nesting”scheduler_yield_nesting_enter
Section titled “scheduler_yield_nesting_enter”scheduler_yield_nesting_max
Section titled “scheduler_yield_nesting_max”scheduler_yield_nesting_exit
Section titled “scheduler_yield_nesting_exit”scheduler_yield_nesting_reset
Section titled “scheduler_yield_nesting_reset”thread_get_current
Section titled “thread_get_current”thread_set_migration_target
Section titled “thread_set_migration_target”thread_get_state
Section titled “thread_get_state”enum thread_state thread_get_state(struct thread *t) source thread_set_state
Section titled “thread_set_state”void thread_set_state(struct thread *t, enum thread_state state) source thread_get_flags
Section titled “thread_get_flags”enum thread_flags thread_get_flags(struct thread *t) source thread_set_flags
Section titled “thread_set_flags”void thread_set_flags(struct thread *t, enum thread_flags new) source thread_pin
Section titled “thread_pin”thread_unpin
Section titled “thread_unpin”thread_is_pinned
Section titled “thread_is_pinned”thread_or_flags
Section titled “thread_or_flags”enum thread_flags thread_or_flags(
struct thread *t,
enum thread_flags flags
) source thread_and_flags
Section titled “thread_and_flags”enum thread_flags thread_and_flags(
struct thread *t,
enum thread_flags flags
) source thread_set_flag
Section titled “thread_set_flag”enum thread_flags thread_set_flag(
struct thread *t,
enum thread_flags flag
) source thread_clear_flag
Section titled “thread_clear_flag”enum thread_flags thread_clear_flag(
struct thread *t,
enum thread_flags flag
) source thread_test_flag
Section titled “thread_test_flag”bool thread_test_flag(struct thread *t, enum thread_flags flag) source thread_get_migration_generation
Section titled “thread_get_migration_generation”thread_get_scheduler_unsafe
Section titled “thread_get_scheduler_unsafe”thread_set_runqueue
Section titled “thread_set_runqueue”thread_getref_rcu
Section titled “thread_getref_rcu”RCU keeps the thread memory allocated so we inc_not_zero here and everything is fine and dandy, everything must be in a read side critical section, though
thread_acquire_internal
Section titled “thread_acquire_internal”thread_acquire
Section titled “thread_acquire”thread_acquire_rcu
Section titled “thread_acquire_rcu”thread_release
Section titled “thread_release”thread_is_rt
Section titled “thread_is_rt”thread_get_wait_type
Section titled “thread_get_wait_type”enum thread_wait_type thread_get_wait_type(struct thread *t) source Macros
Section titled “Macros”THREAD_DEFAULT_TIMESLICE
Section titled “THREAD_DEFAULT_TIMESLICE”#define THREAD_DEFAULT_TIMESLICE 15 source 15 ms
THREAD_CLASS_WIDTH
Section titled “THREAD_CLASS_WIDTH”#define THREAD_CLASS_WIDTH 1024 source THREAD_CLASS_HALF
Section titled “THREAD_CLASS_HALF”#define THREAD_CLASS_HALF (THREAD_CLASS_WIDTH / 2) source THREAD_BAND_MIN
Section titled “THREAD_BAND_MIN”#define THREAD_BAND_MIN(avg) source Expansion
#define THREAD_BAND_MIN(avg) ((avg) - THREAD_CLASS_HALF) THREAD_BAND_MAX
Section titled “THREAD_BAND_MAX”#define THREAD_BAND_MAX(avg) source Expansion
#define THREAD_BAND_MAX(avg) ((avg) + THREAD_CLASS_HALF) THREAD_ACT_INTERACTIVE_AVG
Section titled “THREAD_ACT_INTERACTIVE_AVG”#define THREAD_ACT_INTERACTIVE_AVG 4000u source THREAD_ACT_IO_BOUND_AVG
Section titled “THREAD_ACT_IO_BOUND_AVG”#define THREAD_ACT_IO_BOUND_AVG 2500u source THREAD_ACT_CPU_BOUND_AVG
Section titled “THREAD_ACT_CPU_BOUND_AVG”#define THREAD_ACT_CPU_BOUND_AVG 1200u source THREAD_ACT_SLEEPY_AVG
Section titled “THREAD_ACT_SLEEPY_AVG”#define THREAD_ACT_SLEEPY_AVG 4500u source THREAD_ACT_INTERACTIVE_MIN
Section titled “THREAD_ACT_INTERACTIVE_MIN”#define THREAD_ACT_INTERACTIVE_MIN THREAD_BAND_MIN(THREAD_ACT_INTERACTIVE_AVG) source THREAD_ACT_INTERACTIVE_MAX
Section titled “THREAD_ACT_INTERACTIVE_MAX”#define THREAD_ACT_INTERACTIVE_MAX THREAD_BAND_MAX(THREAD_ACT_INTERACTIVE_AVG) source THREAD_ACT_IO_BOUND_MIN
Section titled “THREAD_ACT_IO_BOUND_MIN”#define THREAD_ACT_IO_BOUND_MIN THREAD_BAND_MIN(THREAD_ACT_IO_BOUND_AVG) source THREAD_ACT_IO_BOUND_MAX
Section titled “THREAD_ACT_IO_BOUND_MAX”#define THREAD_ACT_IO_BOUND_MAX THREAD_BAND_MAX(THREAD_ACT_IO_BOUND_AVG) source THREAD_ACT_CPU_BOUND_MIN
Section titled “THREAD_ACT_CPU_BOUND_MIN”#define THREAD_ACT_CPU_BOUND_MIN THREAD_BAND_MIN(THREAD_ACT_CPU_BOUND_AVG) source THREAD_ACT_CPU_BOUND_MAX
Section titled “THREAD_ACT_CPU_BOUND_MAX”#define THREAD_ACT_CPU_BOUND_MAX THREAD_BAND_MAX(THREAD_ACT_CPU_BOUND_AVG) source THREAD_ACT_SLEEPY_MIN
Section titled “THREAD_ACT_SLEEPY_MIN”#define THREAD_ACT_SLEEPY_MIN THREAD_BAND_MIN(THREAD_ACT_SLEEPY_AVG) source THREAD_ACT_SLEEPY_MAX
Section titled “THREAD_ACT_SLEEPY_MAX”#define THREAD_ACT_SLEEPY_MAX THREAD_BAND_MAX(THREAD_ACT_SLEEPY_AVG) source THREAD_NICENESS_VALID
Section titled “THREAD_NICENESS_VALID”#define THREAD_NICENESS_VALID(n) source Expansion
#define THREAD_NICENESS_VALID(n) IN_RANGE((nice_t) (n), NICE_MIN, NICE_MAX) THREAD_EVENT_REASON_NONE
Section titled “THREAD_EVENT_REASON_NONE”#define THREAD_EVENT_REASON_NONE 0xFF source THREAD_PRIO_HAS_TIMESLICE
Section titled “THREAD_PRIO_HAS_TIMESLICE”#define THREAD_PRIO_HAS_TIMESLICE(prio) source Background threads share timeslices
Expansion
#define THREAD_PRIO_HAS_TIMESLICE(prio) \
(prio == THREAD_PRIO_CLASS_TIMESHARE || \
prio == THREAD_PRIO_CLASS_BACKGROUND) THREAD_ACTIVITY_BUCKET_COUNT
Section titled “THREAD_ACTIVITY_BUCKET_COUNT”#define THREAD_ACTIVITY_BUCKET_COUNT 4 source THREAD_ACTIVITY_BUCKET_SHIFT
Section titled “THREAD_ACTIVITY_BUCKET_SHIFT”#define THREAD_ACTIVITY_BUCKET_SHIFT 10 source THREAD_ACTIVITY_BUCKET_DURATION
Section titled “THREAD_ACTIVITY_BUCKET_DURATION”#define THREAD_ACTIVITY_BUCKET_DURATION source Expansion
#define THREAD_ACTIVITY_BUCKET_DURATION \
(1U << THREAD_ACTIVITY_BUCKET_SHIFT) /* 1024 ms (~1s) */ THREAD_ACTIVITY_BUCKET_MASK
Section titled “THREAD_ACTIVITY_BUCKET_MASK”#define THREAD_ACTIVITY_BUCKET_MASK (THREAD_ACTIVITY_BUCKET_DURATION - 1U) source THREAD_ACTIVITY_INDEX_MASK
Section titled “THREAD_ACTIVITY_INDEX_MASK”#define THREAD_ACTIVITY_INDEX_MASK (THREAD_ACTIVITY_BUCKET_COUNT - 1U) source THREAD_EVENT_RINGBUFFER_CAPACITY
Section titled “THREAD_EVENT_RINGBUFFER_CAPACITY”#define THREAD_EVENT_RINGBUFFER_CAPACITY THREAD_ACTIVITY_BUCKET_COUNT source THREAD_EVENT_RINGBUFFER_MASK
Section titled “THREAD_EVENT_RINGBUFFER_MASK”#define THREAD_EVENT_RINGBUFFER_MASK (THREAD_EVENT_RINGBUFFER_CAPACITY - 1U) source TOTAL_BUCKET_DURATION
Section titled “TOTAL_BUCKET_DURATION”#define TOTAL_BUCKET_DURATION source Expansion
#define TOTAL_BUCKET_DURATION \
(THREAD_ACTIVITY_BUCKET_COUNT * THREAD_ACTIVITY_BUCKET_DURATION) thread_from_rq_rbt_node
Section titled “thread_from_rq_rbt_node”#define thread_from_rq_rbt_node(node) source Expansion
#define thread_from_rq_rbt_node(node) \
rbt_entry(node, struct thread, rq_tree_node) thread_from_rq_list_node
Section titled “thread_from_rq_list_node”#define thread_from_rq_list_node(ln) source Expansion
#define thread_from_rq_list_node(ln) \
(container_of(ln, struct thread, rq_list_node)) thread_from_rcu_list_node
Section titled “thread_from_rcu_list_node”#define thread_from_rcu_list_node(ln) source Expansion
#define thread_from_rcu_list_node(ln) \
(container_of(ln, struct thread, rcu_list_node)) thread_from_wq_pairing_node
Section titled “thread_from_wq_pairing_node”#define thread_from_wq_pairing_node(pn) source Expansion
#define thread_from_wq_pairing_node(pn) \
(container_of(pn, struct thread, wq_pairing_node)) thread_from_wq_list_node
Section titled “thread_from_wq_list_node”#define thread_from_wq_list_node(ln) source Expansion
#define thread_from_wq_list_node(ln) \
(container_of(ln, struct thread, wq_list_node)) thread_from_wq_rbt_node
Section titled “thread_from_wq_rbt_node”#define thread_from_wq_rbt_node(ln) source Expansion
#define thread_from_wq_rbt_node(ln) \
(container_of(ln, struct thread, wq_tree_node)) thread_log
Section titled “thread_log”#define thread_log(lvl, fmt, ...) source Expansion
#define thread_log(lvl, fmt, ...) \
({ \
if (global.current_bootstage >= BOOTSTAGE_LATE) \
log(thread_get_current()->log_site, \
&thread_get_current()->log_handle, lvl, fmt, ##__VA_ARGS__); \
}) thread_err
Section titled “thread_err”#define thread_err(fmt, ...) source Expansion
#define thread_err(fmt, ...) thread_log(LOG_ERROR, fmt, ##__VA_ARGS__) thread_warn
Section titled “thread_warn”#define thread_warn(fmt, ...) source Expansion
#define thread_warn(fmt, ...) thread_log(LOG_WARN, fmt, ##__VA_ARGS__) thread_info
Section titled “thread_info”#define thread_info(fmt, ...) source Expansion
#define thread_info(fmt, ...) thread_log(LOG_INFO, fmt, ##__VA_ARGS__) thread_debug
Section titled “thread_debug”#define thread_debug(fmt, ...) source Expansion
#define thread_debug(fmt, ...) thread_log(LOG_DEBUG, fmt, ##__VA_ARGS__) thread_trace
Section titled “thread_trace”#define thread_trace(fmt, ...) source Expansion
#define thread_trace(fmt, ...) thread_log(LOG_TRACE, fmt, ##__VA_ARGS__) SCHED_MAX_YIELD_NESTING
Section titled “SCHED_MAX_YIELD_NESTING”#define SCHED_MAX_YIELD_NESTING 1 source THREAD_CREATE_PARAMS_DEFAULTS
Section titled “THREAD_CREATE_PARAMS_DEFAULTS”#define THREAD_CREATE_PARAMS_DEFAULTS source Expansion
#define THREAD_CREATE_PARAMS_DEFAULTS \
.stack_pages = (THREAD_STACK_SIZE / PAGE_SIZE), .on_cpu = CPU_ID_MAX, \
.joinable = false, .pinned = false, .allowed_cpus = CPU_MASK_INIT_ALL, \
.arg = NULL, .private = NULL, .stack_internal = NULL, .flags = 0, \
.base_prio_class = THREAD_PRIO_CLASS_TIMESHARE thread_params_with_defaults
Section titled “thread_params_with_defaults”#define thread_params_with_defaults(...) source Expansion
#define thread_params_with_defaults(...) \
cc_wno_override_init_expr( \
struct thread_create_params, \
((struct thread_create_params) {THREAD_CREATE_PARAMS_DEFAULTS, \
##__VA_ARGS__})) thread_create
Section titled “thread_create”Expansion
#define thread_create(name, entry, ...) \
thread_create_internal((entry), \
(struct thread_create_params) \
thread_params_with_defaults(__VA_ARGS__), \
PP_UNPAREN(name)) thread_spawn
Section titled “thread_spawn”Expansion
#define thread_spawn(name, entry, ...) \
thread_spawn_internal((entry), \
(struct thread_create_params) \
thread_params_with_defaults(__VA_ARGS__), \
PP_UNPAREN(name))