| 1 | /* @title: Thread Enumerations and Types */ |
| 2 | #pragma once |
| 3 | #include <mem/page.h> |
| 4 | #include <stdarg.h> |
| 5 | #include <stdint.h> |
| 6 | |
| 7 | struct thread; |
| 8 | struct thread_create_params; |
| 9 | struct cpu_context; |
| 10 | |
| 11 | typedef void (*thread_entry_fn_t)(void *arg); |
| 12 | typedef uint8_t thread_act_reason_t; /* Polymorphic type: |
| 13 | * all the THREAD_*_REASONs |
| 14 | * are uint8_t, and often, we |
| 15 | * may need just a generic reason. |
| 16 | * |
| 17 | * This is that. */ |
| 18 | |
| 19 | /* Both ASAN and the lock validator are very eager to consume |
| 20 | * stack memory, so we'll give threads 16 times as many pages |
| 21 | * if either of those happen to be on, and this should |
| 22 | * give enough headroom for when both are on too */ |
| 23 | #if defined(DEBUG_ASAN) || defined(DEBUG_LOCK_CHK) |
| 24 | #define THREAD_STACK_SIZE (PAGE_SIZE * 16) |
| 25 | #else |
| 26 | #define THREAD_STACK_SIZE (PAGE_SIZE * 4) |
| 27 | #endif |
| 28 | |
| 29 | #define THREAD_STACKS_HEAP_START 0xFFFFF10000000000ULL |
| 30 | #define THREAD_STACKS_HEAP_END 0xFFFFF20000000000ULL |
| 31 | |
| 32 | enum thread_state : uint8_t { |
| 33 | THREAD_STATE_IDLE_THREAD, /* Specifically the idle thread */ |
| 34 | THREAD_STATE_READY, /* Thread is ready to run but not currently running */ |
| 35 | THREAD_STATE_RUNNING, /* Thread is currently executing */ |
| 36 | THREAD_STATE_BLOCKED, /* Waiting on I/O, lock, or condition */ |
| 37 | THREAD_STATE_SLEEPING, /* Temporarily not runnable */ |
| 38 | THREAD_STATE_ZOMBIE, /* Finished executing but hasn't been reaped it yet */ |
| 39 | THREAD_STATE_TERMINATED, /* Fully done, can be cleaned up */ |
| 40 | THREAD_STATE_HALTED, /* Thread manually suspended */ |
| 41 | }; |
| 42 | |
| 43 | enum thread_wait_type : uint8_t { |
| 44 | THREAD_WAIT_NONE, |
| 45 | THREAD_WAIT_UNINTERRUPTIBLE, /* Only object matching/satisfaction ends it */ |
| 46 | THREAD_WAIT_INTERRUPTIBLE, /* APCs OK, alerts end the wait */ |
| 47 | }; |
| 48 | |
| 49 | enum thread_wait_status : uint8_t { |
| 50 | THREAD_WAIT_SATISFIED, |
| 51 | THREAD_WAIT_ALERTED, |
| 52 | THREAD_WAIT_TIMED_OUT, |
| 53 | }; |
| 54 | |
| 55 | /* thread_flags: 32 bit bitflags: |
| 56 | * |
| 57 | * ┌───────────────────────────────────────────────────────────┐ |
| 58 | * Bits │ 31..28 27..24 23..20 19..16 15..12 11..8 7..4 3..0 │ |
| 59 | * Use │ AAAA **** **** **** **** *adJ jRWY DEF* │ |
| 60 | * └───────────────────────────────────────────────────────────┘ |
| 61 | * F - Flexible RT - realtime scheduler related stuff |
| 62 | * E - Executing APC |
| 63 | * D - Dying |
| 64 | * Y - Yielded after a wait (block, sleep) |
| 65 | * W - Available |
| 66 | * r - Realtime fault tolerance |
| 67 | * j - Joinable - someone holds a join reference on this thread |
| 68 | * J - Joined - a join is in progress or consumed the join reference |
| 69 | * d - Diagnostic - Diagnostics enabled for this thread in debug |
| 70 | * a - Delivering APCs - In the APC delivery code |
| 71 | * |
| 72 | * A - Unused (Available) |
| 73 | * * - Unused (Unavailable) |
| 74 | * |
| 75 | */ |
| 76 | enum thread_flags : uint32_t { |
| 77 | THREAD_FLAG_RESV0 = 1, |
| 78 | THREAD_FLAG_FLEXIBLE_RT = 1 << 1, |
| 79 | THREAD_FLAG_EXECUTING_APC = 1 << 2, |
| 80 | THREAD_FLAG_DYING = 1 << 3, |
| 81 | THREAD_FLAG_YIELDED = 1 << 4, |
| 82 | THREAD_FLAG_RT_FAULT_TOLERANCE = 1 << 6, |
| 83 | THREAD_FLAG_JOINABLE = 1 << 7, |
| 84 | THREAD_FLAG_JOINED = 1 << 8, |
| 85 | |
| 86 | THREAD_FLAG_DIAG = 1 << 9, |
| 87 | |
| 88 | /* This is for when inside the APC subsystem, whereas |
| 89 | * THREAD_FLAG_EXECUTING_APC is for an actual APC callback */ |
| 90 | THREAD_FLAG_DELIVERING_APCS = 1 << 10, |
| 91 | |
| 92 | }; |
| 93 | |
| 94 | enum thread_prio_class : uint8_t { |
| 95 | THREAD_PRIO_CLASS_BACKGROUND = 0, /* Background thread */ |
| 96 | THREAD_PRIO_CLASS_TIMESHARE = 1, /* Timesharing thread */ |
| 97 | THREAD_PRIO_CLASS_REALTIME = 2, /* Realtime thread */ |
| 98 | THREAD_PRIO_CLASS_URGENT = 3, /* Urgent thread - ran before RT */ |
| 99 | }; |
| 100 | #define THREAD_PRIO_CLASS_COUNT (4) |
| 101 | #define THREAD_PRIO_CLASS_BIT_COUNT 2 |
| 102 | #define THREAD_PRIO_CLASS_MASK 0x3 |
| 103 | |
| 104 | /* Different enums are used for the little |
| 105 | * bit of type safety since different ringbuffers |
| 106 | * are used to keep track of different reasons */ |
| 107 | enum thread_resume_reason : uint8_t { |
| 108 | THREAD_WAKE_REASON_BLOCKING_IO = 1, |
| 109 | THREAD_WAKE_REASON_BLOCKING_MANUAL = 2, |
| 110 | THREAD_WAKE_REASON_SLEEP_TIMEOUT = 3, |
| 111 | THREAD_WAKE_REASON_SLEEP_MANUAL = 4, |
| 112 | }; |
| 113 | |
| 114 | enum thread_block_reason : uint8_t { |
| 115 | THREAD_BLOCK_REASON_IO = 5, |
| 116 | THREAD_BLOCK_REASON_MANUAL = 6, |
| 117 | }; |
| 118 | |
| 119 | enum thread_sleep_reason : uint8_t { |
| 120 | THREAD_SLEEP_REASON_MANUAL = 7, |
| 121 | }; |
| 122 | |
| 123 | /* Used in condvars, totally separate from thread_resume_reason */ |
| 124 | enum wake_reason { |
| 125 | WAKE_REASON_NONE = 0, /* No reason specified */ |
| 126 | WAKE_REASON_SIGNAL = 1, /* Signal from something */ |
| 127 | WAKE_REASON_TIMEOUT = 2, /* Timeout */ |
| 128 | }; |
| 129 | |
| 130 | struct thread_class_donation { |
| 131 | struct thread *target; |
| 132 | enum thread_prio_class class : 2; |
| 133 | bool active; |
| 134 | }; |
| 135 | |
| 136 | #define THREAD_CLASS_DONATION_EMPTY \ |
| 137 | ((struct thread_class_donation) {.target = NULL, \ |
| 138 | .class = THREAD_PRIO_CLASS_BACKGROUND, \ |
| 139 | .active = false}) |
| 140 | |
| 141 | struct thread *thread_create_full(char *cc_nonnull_ptr name, |
| 142 | thread_entry_fn_t entry, |
| 143 | struct thread_create_params *params, |
| 144 | va_list args) cc_printf_like(1, 0); |
| 145 | |