PatchworkOS  19e446b
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/fs.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 * ### "segfault" (SIGSEGV)
74 *
75 * Indicates that the thread made an invalid memory access, that dident cause a page fault, such as executing a invalid
76 * instruction.
77 *
78 * ### "terminate" (SIGTERM)
79 *
80 * Indicates that the process should perform any necessary cleanup and exit gracefully.
81 *
82 * ## User-defined Notes
83 *
84 * All system notes will always start with a single word consisting of only lowercase letters.
85 *
86 * If a program wishes to define its own notes, it is best practice to avoid using such words to prevent conflicts with
87 * future system notes. For example, here are some safe to use user-defined notes:
88 * - "user_note ..."
89 * - "UserNote ..."
90 * - "USER-NOTE ..."
91 * - "1usernote ..."
92 *
93 * @{
94 */
95
96/**
97 * @brief Maximum size of a notes buffer.
98 */
99#define NOTE_MAX 256
100
101/**
102 * @brief Note queue flags.
103 * @enum note_queue_flag_t
104 *
105 * Its vital that a certain special notes get handled, even if we run out of memory. Since these notes have a predefined
106 * value and we dont care if they get sent multiple times, we can simplify the system such that when the note queue
107 * receives a special note instead of pushing it to the queue we just set the corresponding flag.
108 */
109typedef enum
110{
113 NOTE_QUEUE_HANDLING = 1 << 1, ///< User space is currently handling a note.
115
116/**
117 * @brief Note structure.
118 * @struct note_t
119 */
120typedef struct note
121{
124} note_t;
125
126/**
127 * @brief Per-process note handler.
128 * @struct note_handler_t
129 */
135
136/**
137 * @brief Per-thread note queue.
138 * @struct note_queue_t
139 */
140typedef struct
141{
143 size_t readIndex;
147 interrupt_frame_t noteFrame; ///< The interrupt frame to return to after handling a note.
150
151/**
152 * @brief Initialize a note handler.
153 *
154 * @param handler The handler to initialize.
155 */
156void note_handler_init(note_handler_t* handler);
157
158/**
159 * @brief Initialize a note queue.
160 *
161 * @param queue The queue to initialize.
162 */
163void note_queue_init(note_queue_t* queue);
164
165/**
166 * @brief The amount of pending notes in a note queue, including special notes.
167 *
168 * @param queue The queue to query.
169 * @return The amount of pending notes.
170 */
172
173/**
174 * @brief Write a note to a note queue.
175 *
176 * @param queue The destination queue.
177 * @param string The string to write, should be a null-terminated string.
178 * @return On success, `0`. On failure, `ERR` and `errno` is set.
179 */
180uint64_t note_send(note_queue_t* queue, const char* string);
181
182/**
183 * @brief Handle pending notes for the current thread.
184 *
185 * Should only be called from an interrupt context.
186 *
187 * If the frame is not from user space, this function will return immediately.
188 *
189 * @param frame The interrupt frame.
190 * @return `true` if a note was handled, `false` otherwise.
191 */
193
194/** @} */
EFI_PHYSICAL_ADDRESS buffer
Definition main.c:237
#define CONFIG_MAX_NOTES
Maximum note queue configuration.
Definition config.h:69
#define NOTE_MAX
Maximum size of a notes buffer.
Definition note.h:99
bool note_handle_pending(interrupt_frame_t *frame)
Handle pending notes for the current thread.
Definition note.c:87
note_queue_flag_t
Note queue flags.
Definition note.h:110
uint64_t note_send(note_queue_t *queue, const char *string)
Write a note to a note queue.
Definition note.c:46
uint64_t note_amount(note_queue_t *queue)
The amount of pending notes in a note queue, including special notes.
Definition note.c:35
void note_handler_init(note_handler_t *handler)
Initialize a note handler.
Definition note.c:19
void note_queue_init(note_queue_t *queue)
Initialize a note queue.
Definition note.c:25
@ NOTE_QUEUE_RECEIVED_KILL
Definition note.h:112
@ NOTE_QUEUE_NONE
Definition note.h:111
@ NOTE_QUEUE_HANDLING
User space is currently handling a note.
Definition note.h:113
void(* note_func_t)(char *note)
Note handler function type.
Definition proc.h:255
__UINT64_TYPE__ pid_t
Process Identifier.
Definition pid_t.h:11
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
CPU structure.
Definition cpu.h:84
Trap Frame Structure.
Definition interrupt.h:195
A simple ticket lock implementation.
Definition lock.h:44
Per-process note handler.
Definition note.h:131
lock_t lock
Definition note.h:133
note_func_t func
Definition note.h:132
Per-thread note queue.
Definition note.h:141
note_queue_flag_t flags
Definition note.h:146
lock_t lock
Definition note.h:148
uint64_t length
Definition note.h:145
size_t writeIndex
Definition note.h:144
size_t readIndex
Definition note.h:143
interrupt_frame_t noteFrame
The interrupt frame to return to after handling a note.
Definition note.h:147
Note structure.
Definition note.h:121
pid_t sender
Definition note.h:123