PatchworkOS  19e446b
A non-POSIX operating system.
Loading...
Searching...
No Matches
thread.h
Go to the documentation of this file.
1#pragma once
2
3#include <kernel/cpu/gdt.h>
5#include <kernel/cpu/simd.h>
9#include <kernel/fs/path.h>
10#include <kernel/ipc/note.h>
11#include <kernel/sched/sched.h>
12#include <kernel/sched/wait.h>
13#include <kernel/sync/rcu.h>
14#include <kernel/utils/ref.h>
15
16#include <sys/list.h>
17#include <sys/proc.h>
18
19typedef struct process process_t;
20typedef struct thread thread_t;
21
22/**
23 * @brief Thread of execution.
24 * @ingroup kernel_sched
25 * @defgroup kernel_sched_thread Threads
26 * @{
27 */
28
29/**
30 * @brief Thread state enum.
31 * @enum thread_state_t
32 *
33 */
34typedef enum
35{
36 THREAD_PARKED = 0, ///< Is doing nothing, not in a queue, not blocking, think of it as "other".
37 THREAD_ACTIVE, ///< Is either running or ready to run.
38 THREAD_PRE_BLOCK, ///< Has started the process of blocking but has not yet been given to a owner cpu.
39 THREAD_BLOCKED, ///< Is blocking and waiting in one or multiple wait queues.
40 THREAD_UNBLOCKING, ///< Has started unblocking, used to prevent the same thread being unblocked multiple times.
41 THREAD_DYING, ///< The thread is currently dying, it will be freed by the scheduler once its invoked.
43
44/**
45 * @brief Thread of execution structure.
46 * @struct thread_t
47 *
48 * A `thread_t` represents an independent thread of execution within a `process_t`.
49 *
50 * ## Thread Stacks
51 * The position of a thread user stack is decided based on its thread id. The user stack of the thread with id 0 is
52 * located at the top of the lower half of the address space, the user stack is `CONFIG_MAX_USER_STACK_PAGES` pages
53 * long, and below it is the guard page. Below that is the user stack of the thread with id 1, below that is its guard
54 * page, it then continues like that for however many threads there are.
55 *
56 * The kernel stack works the same way, but instead starts just under the kernel code and data section, at the top of
57 * the kernel stacks region and each stack is `CONFIG_MAX_KERNEL_STACK_PAGES` pages long.
58 *
59 */
60typedef struct thread
61{
62 process_t* process; ///< The parent process that the thread executes within.
63 list_entry_t processEntry; ///< The entry for the parent process.
64 tid_t id; ///< The thread id, unique within a `process_t`.
65 /**
66 * The current state of the thread, used to prevent race conditions and make debugging easier.
67 */
69 /**
70 * The last error that occurred while the thread was running, specified using errno codes.
71 */
73 stack_pointer_t kernelStack; ///< The kernel stack of the thread.
74 stack_pointer_t userStack; ///< The user stack of the thread.
82 uintptr_t fsBase; ///< The FS base address for the thread.
83 /**
84 * The threads interrupt frame is used to save the values in the CPU registers such that the scheduler can continue
85 * executing the thread later on.
86 */
88} thread_t;
89
90/**
91 * @brief Creates a new thread structure.
92 *
93 * Does not push the created thread to the scheduler or similar, merely handling allocation and initialization.
94 *
95 * @param process The parent process that the thread will execute within.
96 * @return On success, returns the newly created thread. On failure, returns `NULL` and `errno` is set.
97 */
99
100/**
101 * @brief Frees a thread structure.
102 *
103 * @param thread The thread to be freed.
104 */
105void thread_free(thread_t* thread);
106
107/**
108 * @brief Kernel thread entry point function type.
109 */
110typedef void (*thread_kernel_entry_t)(void* arg);
111
112/**
113 * @brief Creates a new thread that runs in kernel mode and submits it to the scheduler.
114 *
115 * @param entry The entry point function for the thread.
116 * @param arg An argument to pass to the entry point function.
117 * @return On success, returns the newly created thread ID. On failure, returns `ERR` and `errno` is set.
118 */
120
121/**
122 * @brief Retrieves the currently running thread.
123 *
124 * @return The currently running thread.
125 */
126static inline thread_t* thread_current(void)
127{
128 CLI_SCOPE();
129 return _pcpu_sched->runThread;
130}
131
132/**
133 * @brief Retrieves the currently running thread without disabling interrupts.
134 *
135 * @return The currently running thread.
136 */
137static inline thread_t* thread_current_unsafe(void)
138{
139 return _pcpu_sched->runThread;
140}
141
142/**
143 * @brief Retrieves the idle thread for the current CPU.
144 *
145 * @return The idle thread for the current CPU.
146 */
147static inline thread_t* thread_idle(void)
148{
149 CLI_SCOPE();
150 return _pcpu_sched->idleThread;
151}
152
153/**
154 * @brief Retrieves the idle thread for the current CPU without disabling interrupts.
155 *
156 * @return The idle thread for the current CPU.
157 */
158static inline thread_t* thread_idle_unsafe(void)
159{
160 return _pcpu_sched->idleThread;
161}
162
163/**
164 * @brief Save state to a thread.
165 *
166 * @param thread The destination thread where the state will be saved.
167 * @param frame The source frame..
168 */
169void thread_save(thread_t* thread, const interrupt_frame_t* frame);
170
171/**
172 * @brief Load state from a thread.
173 *
174 * Will retrieve the interrupt frame and setup the CPU with the threads contexts/data.
175 *
176 * @param thread The source thread to load state from.
177 * @param frame The destination interrupt frame.
178 */
179void thread_load(thread_t* thread, interrupt_frame_t* frame);
180
181/**
182 * @brief Check if a thread has a note pending.
183 *
184 * @param thread The thread to query.
185 * @return True if there is a note pending, false otherwise.
186 */
187bool thread_is_note_pending(thread_t* thread);
188
189/**
190 * @brief Send a note to a thread.
191 *
192 * This function should always be used over the `note_queue_push()` function, as it performs additional checks, like
193 * unblocking the thread to notify it of the received note.
194 *
195 * @param thread The destination thread.
196 * @param string The note string to send, should be a null-terminated string.
197 * @return On success, `0`. On failure, `ERR` and `errno` is set to:
198 * - See `note_send()` for possible error codes.
199 */
200uint64_t thread_send_note(thread_t* thread, const char* string);
201
202/**
203 * @brief Safely copy data from user space.
204 *
205 * Will pin the user pages in memory while performing the copy and expand the user stack if necessary.
206 *
207 * @param thread The thread performing the operation.
208 * @param dest The destination buffer in kernel space.
209 * @param userSrc The source buffer in user space.
210 * @param length The number of bytes to copy.
211 * @return On success, `0`. On failure, `ERR` and `errno` is set.
212 */
213uint64_t thread_copy_from_user(thread_t* thread, void* dest, const void* userSrc, uint64_t length);
214
215/**
216 * @brief Safely copy data to user space.
217 *
218 * Will pin the user pages in memory while performing the copy and expand the user stack if necessary.
219 *
220 * @param thread The thread performing the operation.
221 * @param userDest The destination buffer in user space.
222 * @param src The source buffer in kernel space.
223 * @param length The number of bytes to copy.
224 * @return On success, `0`. On failure, `ERR` and `errno` is set.
225 */
226uint64_t thread_copy_to_user(thread_t* thread, void* userDest, const void* src, uint64_t length);
227
228/**
229 * @brief Safely copy a null-terminated array of objects from user space.
230 *
231 * @param thread The thread performing the operation.
232 * @param userArray The source array in user space.
233 * @param terminator A pointer to the terminator object.
234 * @param objectSize The size of each object in the array.
235 * @param maxCount The maximum number of objects to copy.
236 * @param outArray Output pointer to store the allocated array in kernel space, must be freed by the caller.
237 * @param outCount Output pointer to store the number of objects copied, can be `NULL`.
238 * @return On success, `0`. On failure, `ERR` and `errno` is set.
239 */
240uint64_t thread_copy_from_user_terminated(thread_t* thread, const void* userArray, const void* terminator,
241 uint8_t objectSize, uint64_t maxCount, void** outArray, uint64_t* outCount);
242
243/**
244 * @brief Safely copy a string from user space.
245 *
246 * @param thread The thread performing the operation.
247 * @param dest The destination buffer in kernel space.
248 * @param userSrc The source buffer in user space.
249 * @param size The size of the destination buffer.
250 * @return On success, `0`. On failure, `ERR` and `errno` is set.
251 */
252uint64_t thread_copy_from_user_string(thread_t* thread, char* dest, const char* userSrc, uint64_t size);
253
254/**
255 * @brief Safely copy a string from user space and use it to initialize a pathname.
256 *
257 * @param thread The thread performing the operation.
258 * @param pathname A pointer to the pathname to initialize.
259 * @param userPath The string in user space.
260 * @return On success, `0`. On failure, `ERR` and `errno` is set.
261 */
262uint64_t thread_copy_from_user_pathname(thread_t* thread, pathname_t* pathname, const char* userPath);
263
264/**
265 * @brief Safely copy a null-terminated array of strings and their contents from user space into a string vector.
266 *
267 * @param thread The thread performing the operation.
268 * @param user The source array of strings in user space.
269 * @param out Output pointer to store the allocated array of strings in kernel space, must be freed by the caller.
270 * @param outAmount Output pointer to store the number of strings copied, can be `NULL`.
271 * @return On success, `0`. On failure, `ERR` and `errno` is set.
272 */
273uint64_t thread_copy_from_user_string_array(thread_t* thread, const char** user, char*** out, uint64_t* outAmount);
274
275/**
276 * @brief Atomically load a 64-bit value from a user-space atomic variable.
277 *
278 * Will pin the user pages in memory while performing the load and expand the user stack if necessary.
279 *
280 * @param thread The thread performing the operation.
281 * @param userObj The user-space atomic variable to load from.
282 * @param outValue Output pointer to store the loaded value.
283 * @return On success, `0`. On failure, `ERR` and `errno` is set.
284 */
285uint64_t thread_load_atomic_from_user(thread_t* thread, atomic_uint64_t* userObj, uint64_t* outValue);
286
287/**
288 * @brief Jump to a thread by calling `thread_load()` and then loading its interrupt frame.
289 *
290 * Must be done in assembly as it requires directly modifying registers.
291 *
292 * Will never return instead it ends up at `thread->frame.rip`.
293 *
294 * @param thread The thread to jump to.
295 */
296_NORETURN extern void thread_jump(thread_t* thread);
297
298/** @} */
#define _NORETURN
Definition config.h:28
int errno_t
Definition errno_t.h:4
#define CLI_SCOPE()
Macro to increment CLI depth for the duration of the current scope.
Definition cli.h:56
uint64_t thread_copy_from_user_string_array(thread_t *thread, const char **user, char ***out, uint64_t *outAmount)
Safely copy a null-terminated array of strings and their contents from user space into a string vecto...
Definition thread.c:328
bool thread_is_note_pending(thread_t *thread)
Check if a thread has a note pending.
Definition thread.c:171
void thread_free(thread_t *thread)
Frees a thread structure.
Definition thread.c:111
uint64_t thread_copy_from_user(thread_t *thread, void *dest, const void *userSrc, uint64_t length)
Safely copy data from user space.
Definition thread.c:202
void thread_load(thread_t *thread, interrupt_frame_t *frame)
Load state from a thread.
Definition thread.c:160
static thread_t * thread_idle(void)
Retrieves the idle thread for the current CPU.
Definition thread.h:147
static thread_t * thread_current(void)
Retrieves the currently running thread.
Definition thread.h:126
_NORETURN void thread_jump(thread_t *thread)
Jump to a thread by calling thread_load() and then loading its interrupt frame.
static thread_t * thread_idle_unsafe(void)
Retrieves the idle thread for the current CPU without disabling interrupts.
Definition thread.h:158
uint64_t thread_load_atomic_from_user(thread_t *thread, atomic_uint64_t *userObj, uint64_t *outValue)
Atomically load a 64-bit value from a user-space atomic variable.
Definition thread.c:373
uint64_t thread_copy_from_user_terminated(thread_t *thread, const void *userArray, const void *terminator, uint8_t objectSize, uint64_t maxCount, void **outArray, uint64_t *outCount)
Safely copy a null-terminated array of objects from user space.
Definition thread.c:238
static thread_t * thread_current_unsafe(void)
Retrieves the currently running thread without disabling interrupts.
Definition thread.h:137
uint64_t thread_copy_from_user_pathname(thread_t *thread, pathname_t *pathname, const char *userPath)
Safely copy a string from user space and use it to initialize a pathname.
Definition thread.c:300
uint64_t thread_copy_from_user_string(thread_t *thread, char *dest, const char *userSrc, uint64_t size)
Safely copy a string from user space.
Definition thread.c:278
thread_t * thread_new(process_t *process)
Creates a new thread structure.
Definition thread.c:50
uint64_t thread_copy_to_user(thread_t *thread, void *userDest, const void *src, uint64_t length)
Safely copy data to user space.
Definition thread.c:220
void thread_save(thread_t *thread, const interrupt_frame_t *frame)
Save state to a thread.
Definition thread.c:153
thread_state_t
Thread state enum.
Definition thread.h:35
void(* thread_kernel_entry_t)(void *arg)
Kernel thread entry point function type.
Definition thread.h:110
tid_t thread_kernel_create(thread_kernel_entry_t entry, void *arg)
Creates a new thread that runs in kernel mode and submits it to the scheduler.
Definition thread.c:126
uint64_t thread_send_note(thread_t *thread, const char *string)
Send a note to a thread.
Definition thread.c:176
@ THREAD_UNBLOCKING
Has started unblocking, used to prevent the same thread being unblocked multiple times.
Definition thread.h:40
@ THREAD_PRE_BLOCK
Has started the process of blocking but has not yet been given to a owner cpu.
Definition thread.h:38
@ THREAD_BLOCKED
Is blocking and waiting in one or multiple wait queues.
Definition thread.h:39
@ THREAD_PARKED
Is doing nothing, not in a queue, not blocking, think of it as "other".
Definition thread.h:36
@ THREAD_DYING
The thread is currently dying, it will be freed by the scheduler once its invoked.
Definition thread.h:41
@ THREAD_ACTIVE
Is either running or ready to run.
Definition thread.h:37
sched_t PERCPU _pcpu_sched
The per CPU scheduler.
__UINT64_TYPE__ tid_t
Thread Identifier.
Definition tid_t.h:12
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__UINT8_TYPE__ uint8_t
Definition stdint.h:11
__UINTPTR_TYPE__ uintptr_t
Definition stdint.h:43
Trap Frame Structure.
Definition interrupt.h:195
A entry in a doubly linked list.
Definition list.h:37
Per-thread note queue.
Definition note.h:141
Pathname structure.
Definition path.h:139
Per-Thread performance context.
Definition perf.h:64
Process structure.
Definition process.h:76
Intrusive RCU head structure.
Definition rcu.h:65
Per-thread scheduler context.
Definition sched.h:375
thread_t *volatile runThread
The currently running thread on this CPU.
Definition sched.h:406
thread_t *volatile idleThread
The idle thread for this CPU.
Definition sched.h:405
Structure to define a stack in memory.
Per thread syscall context.
Definition syscall.h:133
Thread of execution structure.
Definition thread.h:61
perf_thread_ctx_t perf
Definition thread.h:80
list_entry_t processEntry
The entry for the parent process.
Definition thread.h:63
process_t * process
The parent process that the thread executes within.
Definition thread.h:62
_Atomic(thread_state_t) state
interrupt_frame_t frame
Definition thread.h:87
rcu_entry_t rcu
Definition thread.h:81
stack_pointer_t kernelStack
The kernel stack of the thread.
Definition thread.h:73
uintptr_t fsBase
The FS base address for the thread.
Definition thread.h:82
errno_t error
Definition thread.h:72
note_queue_t notes
Definition thread.h:78
syscall_ctx_t syscall
Definition thread.h:79
stack_pointer_t userStack
The user stack of the thread.
Definition thread.h:74
wait_client_t wait
Definition thread.h:76
tid_t id
The thread id, unique within a process_t.
Definition thread.h:64
sched_client_t sched
Definition thread.h:75
simd_ctx_t simd
Definition thread.h:77
Represents a thread in the waiting subsystem.
Definition wait.h:198