PatchworkOS  966e257
A non-POSIX operating system.
Loading...
Searching...
No Matches
note.h
Go to the documentation of this file.
1#pragma once
2
3#include <kernel/config.h>
5#include <kernel/sync/lock.h>
6
7#include <kernel/utils/map.h>
8#include <sys/io.h>
9#include <sys/proc.h>
10
11typedef struct cpu cpu_t;
12
13/**
14 * @brief Signal style inter-process communication.
15 * @defgroup kernel_ipc_note Notes
16 * @ingroup kernel_ipc
17 *
18 * Notes are exposed in the `/proc/[pid]/note` file and are used for inter-process communication (IPC) similarly to
19 * signals in Unix-like operating systems. However, instead of being limited to a predefined set of integer values,
20 * notes can send arbitrary strings.
21 *
22 * ## Using Notes
23 *
24 * To send or receive notes, each process exposes a set of files in its `/proc/[pid]` directory.
25 *
26 * @see kernel_proc_process
27 *
28 * ## Receiving Notes
29 *
30 * In the kernel, notes are received and handled in the `note_handle_pending()` function, which is called from an
31 * interrupt context.
32 *
33 * From the perspective of user space, a thread will be interrupted the next time a kernel to user boundary is crossed,
34 * asuming there is a note pending.
35 *
36 * The interruption works by having the kernel save the current interrupt frame of the thread and replacing it with a
37 * new frame that calls the note handler function registered using `notify()`. During the handling of the note, no
38 * further notes will be delivered to the thread.
39 *
40 * Later, when the note handler function calls `noted()`, the kernel will restore the saved interrupt frame and continue
41 * execution from where it left off as if nothing happened. Alternatively, the note handler can choose to exit the
42 * thread. If no handler is registered, the thread is killed.
43 *
44 * ## System Notes
45 *
46 * Certain notes will cause the kernel to take special actions and for the sake of consistency, we define
47 * some notes that all user processes are expected to handle in a standardized way.
48 *
49 * Any such notes are written as a word optionally followed by additional data. For example, a "terminate" note could be
50 * send as is or with a reason string like "terminate due to low memory".
51 *
52 * ### "kill" (SIGKILL)
53 *
54 * When a thread receives this note, it will immediately transition to the `THREAD_DYING` state, causing the scheduler
55 * to kill and free the thread. User space will never see this note.
56 *
57 * ### "divbyzero" (SIGFPE)
58 *
59 * The thread attempted to divide by zero.
60 *
61 * ### "illegal" (SIGILL)
62 *
63 * The thread attempted to execute an illegal instruction.
64 *
65 * ### "interrupt" (SIGINT)
66 *
67 * Indicates an interrupt from the user, typically initiated by pressing `Ctrl+C` in a terminal.
68 *
69 * ### "pagefault" (SIGSEGV)
70 *
71 * Indicates that the thread made an invalid memory access, such as dereferencing a null or invalid pointer.
72 *
73 * ### "terminate" (SIGTERM)
74 *
75 * Indicates that the process should perform any necessary cleanup and exit gracefully.
76 *
77 * ## User-defined Notes
78 *
79 * All system notes will always start with a single word consisting of only lowercase letters.
80 *
81 * If a program wishes to define its own notes, it is best practice to avoid using such words to prevent conflicts with
82 * future system notes. For example, here are some safe to use user-defined notes:
83 * - "user_note ..."
84 * - "UserNote ..."
85 * - "USER-NOTE ..."
86 * - "1usernote ..."
87 *
88 * @{
89 */
90
91/**
92 * @brief Maximum size of a notes buffer.
93 */
94#define NOTE_MAX 256
95
96/**
97 * @brief Note queue flags.
98 * @enum note_queue_flag_t
99 *
100 * Its vital that a certain special notes get handled, even if we run out of memory. Since these notes have a predefined
101 * value and we dont care if they get sent multiple times, we can simplify the system such that when the note queue
102 * receives a special note instead of pushing it to the queue we just set the corresponding flag.
103 */
104typedef enum
105{
108 NOTE_QUEUE_HANDLING = 1 << 1, ///< User space is currently handling a note.
110
111/**
112 * @brief Note structure.
113 * @struct note_t
114 */
115typedef struct note
116{
119} note_t;
120
121/**
122 * @brief Per-process note handler.
123 * @struct note_handler_t
124 */
130
131/**
132 * @brief Per-thread note queue.
133 * @struct note_queue_t
134 */
135typedef struct
136{
142 interrupt_frame_t noteFrame; ///< The interrupt frame to return to after handling a note.
145
146/**
147 * @brief Initialize a note handler.
148 *
149 * @param handler The handler to initialize.
150 */
151void note_handler_init(note_handler_t* handler);
152
153/**
154 * @brief Initialize a note queue.
155 *
156 * @param queue The queue to initialize.
157 */
158void note_queue_init(note_queue_t* queue);
159
160/**
161 * @brief The amount of pending notes in a note queue, including special notes.
162 *
163 * @param queue The queue to query.
164 * @return The amount of pending notes.
165 */
167
168/**
169 * @brief Write a note to a note queue.
170 *
171 * @param queue The destination queue.
172 * @param string The string to write, should be a null-terminated string.
173 * @return On success, `0`. On failure, `ERR` and `errno` is set.
174 */
175uint64_t note_send(note_queue_t* queue, const char* string);
176
177/**
178 * @brief Handle pending notes for the current thread.
179 *
180 * Should only be called from an interrupt context.
181 *
182 * If the frame is not from user space, this function will return immediately.
183 *
184 * @param frame The interrupt frame.
185 * @param self The current CPU.
186 * @return `true` if a note was handled, `false` otherwise.
187 */
189
190/** @} */
#define NOTE_MAX
Maximum size of a notes buffer.
Definition note.h:94
bool note_handle_pending(interrupt_frame_t *frame, cpu_t *self)
Handle pending notes for the current thread.
Definition note.c:86
note_queue_flag_t
Note queue flags.
Definition note.h:105
uint64_t note_send(note_queue_t *queue, const char *string)
Write a note to a note queue.
Definition note.c:45
uint64_t note_amount(note_queue_t *queue)
The amount of pending notes in a note queue, including special notes.
Definition note.c:34
void note_handler_init(note_handler_t *handler)
Initialize a note handler.
Definition note.c:18
void note_queue_init(note_queue_t *queue)
Initialize a note queue.
Definition note.c:24
@ NOTE_QUEUE_RECEIVED_KILL
Definition note.h:107
@ NOTE_QUEUE_NONE
Definition note.h:106
@ NOTE_QUEUE_HANDLING
User space is currently handling a note.
Definition note.h:108
#define CONFIG_MAX_NOTES
Maximum note queue configuration.
Definition config.h:67
void(* note_func_t)(char *note)
Note handler function type.
Definition proc.h:262
__UINT64_TYPE__ pid_t
Process Identifier.
Definition pid_t.h:11
EFI_PHYSICAL_ADDRESS buffer
Definition mem.c:15
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
CPU structure.
Definition cpu.h:122
Trap Frame Structure.
Definition interrupt.h:146
A simple ticket lock implementation.
Definition lock.h:43
Per-process note handler.
Definition note.h:126
lock_t lock
Definition note.h:128
note_func_t func
Definition note.h:127
Per-thread note queue.
Definition note.h:136
note_queue_flag_t flags
Definition note.h:141
uint64_t readIndex
Definition note.h:138
lock_t lock
Definition note.h:143
uint64_t writeIndex
Definition note.h:139
uint64_t length
Definition note.h:140
interrupt_frame_t noteFrame
The interrupt frame to return to after handling a note.
Definition note.h:142
Note structure.
Definition note.h:116
pid_t sender
Definition note.h:118