PatchworkOS  19e446b
A non-POSIX operating system.
Loading...
Searching...
No Matches
note.c
Go to the documentation of this file.
2#include <kernel/ipc/note.h>
3
4#include <kernel/cpu/cpu.h>
5#include <kernel/log/log.h>
6#include <kernel/log/panic.h>
7#include <kernel/mem/space.h>
10#include <kernel/sched/thread.h>
11#include <kernel/sync/lock.h>
12
13#include <assert.h>
14#include <errno.h>
15#include <stdlib.h>
16#include <string.h>
17#include <sys/math.h>
18
20{
21 handler->func = NULL;
22 lock_init(&handler->lock);
23}
24
26{
27 queue->readIndex = 0;
28 queue->writeIndex = 0;
29 queue->length = 0;
30 queue->flags = NOTE_QUEUE_NONE;
31 memset_s(&queue->noteFrame, sizeof(interrupt_frame_t), 0, sizeof(interrupt_frame_t));
32 lock_init(&queue->lock);
33}
34
36{
37 LOCK_SCOPE(&queue->lock);
38 uint64_t length = queue->length;
40 {
41 length++;
42 }
43 return length;
44}
45
46uint64_t note_send(note_queue_t* queue, const char* string)
47{
48 if (queue == NULL || string == NULL)
49 {
50 errno = EINVAL;
51 return ERR;
52 }
53
54 size_t count = strnlen_s(string, NOTE_MAX);
55 if (count == 0 || count >= NOTE_MAX)
56 {
57 errno = EINVAL;
58 return ERR;
59 }
60
61 process_t* sender = process_current();
62
63 LOCK_SCOPE(&queue->lock);
64
65 if (strcmp(string, "kill") == 0)
66 {
68 return 0;
69 }
70
71 if (queue->length >= CONFIG_MAX_NOTES)
72 {
73 errno = EAGAIN;
74 return ERR;
75 }
76
77 note_t* note = &queue->notes[queue->writeIndex];
78 queue->writeIndex = (queue->writeIndex + 1) % CONFIG_MAX_NOTES;
79 queue->length++;
80
81 memcpy_s(note->buffer, NOTE_MAX, string, count);
82 note->buffer[count] = '\0';
83 note->sender = sender->id;
84 return 0;
85}
86
88{
89 UNUSED(frame);
90
92 {
93 return false;
94 }
95
97 process_t* process = thread->process;
98 note_queue_t* queue = &thread->notes;
99 note_handler_t* handler = &process->noteHandler;
100
101 LOCK_SCOPE(&queue->lock);
102
103 if (queue->flags & NOTE_QUEUE_RECEIVED_KILL)
104 {
105 atomic_store(&thread->state, THREAD_DYING);
106 queue->flags &= ~NOTE_QUEUE_RECEIVED_KILL;
107 return true;
108 }
109
110 if (queue->length == 0 || (queue->flags & NOTE_QUEUE_HANDLING))
111 {
112 return false;
113 }
114
115 LOCK_SCOPE(&handler->lock);
116
117 if (handler->func == NULL)
118 {
119 atomic_store(&thread->state, THREAD_DYING);
120 return false;
121 }
122
123 note_t* note = &queue->notes[queue->readIndex];
124 queue->readIndex = (queue->readIndex + 1) % CONFIG_MAX_NOTES;
125 queue->length--;
126
127 queue->noteFrame = *frame;
128 queue->flags |= NOTE_QUEUE_HANDLING;
129
130 // func(note->buffer)
131 frame->rsp = ROUND_DOWN(frame->rsp - (RED_ZONE_SIZE + NOTE_MAX), 16);
132 if (thread_copy_to_user(thread, (void*)frame->rsp, note->buffer, NOTE_MAX) == ERR)
133 {
134 atomic_store(&thread->state, THREAD_DYING);
135 return true;
136 }
137 frame->rip = (uint64_t)handler->func;
138 frame->rdi = frame->rsp;
140
141 LOG_DEBUG("delivering note '%s' to pid=%d rsp=%p rip=%p\n", note->buffer, process->id, (void*)frame->rsp,
142 (void*)frame->rip);
143
144 return true;
145}
146
148{
149 process_t* process = process_current();
150 note_handler_t* noteHandler = &process->noteHandler;
151
152 if (handler != NULL && space_check_access(&process->space, (void*)handler, 1) == ERR)
153 {
154 return ERR;
155 }
156
157 lock_acquire(&noteHandler->lock);
158 noteHandler->func = handler;
159 lock_release(&noteHandler->lock);
160
161 return 0;
162}
163
165{
166 thread_t* thread = thread_current();
167 note_queue_t* queue = &thread->notes;
168
169 lock_acquire(&queue->lock);
170
171 if (!(queue->flags & NOTE_QUEUE_HANDLING))
172 {
173 lock_release(&queue->lock);
175 }
176
177 queue->flags &= ~NOTE_QUEUE_HANDLING;
178
179 // Causes the system call to return to the saved interrupt frame.
180 memcpy_s(thread->syscall.frame, sizeof(interrupt_frame_t), &queue->noteFrame, sizeof(interrupt_frame_t));
182
183 lock_release(&queue->lock);
184}
#define assert(expression)
Definition assert.h:29
#define CONFIG_MAX_NOTES
Maximum note queue configuration.
Definition config.h:69
#define INTERRUPT_FRAME_IN_USER_SPACE(frame)
Checks if a interrupt frame is from user space.
Definition interrupt.h:229
#define SYSCALL_DEFINE(num, returnType,...)
Macro to define a syscall.
Definition syscall.h:172
@ SYS_NOTIFY
Definition syscall.h:98
@ SYS_NOTED
Definition syscall.h:99
@ SYSCALL_FORCE_FAKE_INTERRUPT
Definition syscall.h:125
#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
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
#define LOG_DEBUG(format,...)
Definition log.h:85
uint64_t space_check_access(space_t *space, const void *addr, size_t length)
Checks if a virtual memory region is within the allowed address range of the space.
Definition space.c:444
static process_t * process_current(void)
Retrieves the process of the currently running thread.
Definition process.h:131
static thread_t * thread_current(void)
Retrieves the currently running thread.
Definition thread.h:126
static thread_t * thread_current_unsafe(void)
Retrieves the currently running thread without disabling interrupts.
Definition thread.h:137
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
@ THREAD_DYING
The thread is currently dying, it will be freed by the scheduler once its invoked.
Definition thread.h:41
_NORETURN void sched_thread_exit(void)
Terminates the currently executing thread.
Definition sched.c:664
static void lock_init(lock_t *lock)
Initializes a lock.
Definition lock.h:79
#define LOCK_SCOPE(lock)
Acquires a lock for the reminder of the current scope.
Definition lock.h:58
static void lock_release(lock_t *lock)
Releases a lock.
Definition lock.h:175
static void lock_acquire(lock_t *lock)
Acquires a lock, blocking until it is available.
Definition lock.h:96
#define EINVAL
Invalid argument.
Definition errno.h:142
#define errno
Error number variable.
Definition errno.h:27
#define EAGAIN
Try again.
Definition errno.h:87
#define UNUSED(x)
Mark a variable as unused.
Definition defs.h:96
#define RED_ZONE_SIZE
The size of the red zone in bytes.
Definition defs.h:87
#define ROUND_DOWN(number, multiple)
Definition math.h:23
void(* note_func_t)(char *note)
Note handler function type.
Definition proc.h:255
#define NULL
Pointer error value.
Definition NULL.h:25
#define ERR
Integer error value.
Definition ERR.h:17
errno_t memcpy_s(void *_RESTRICT s1, rsize_t s1max, const void *_RESTRICT s2, rsize_t n)
Definition memcpy_s.c:9
errno_t memset_s(void *s, rsize_t smax, int c, rsize_t n)
Definition memset_s.c:9
static atomic_long count
Definition main.c:11
#define RFLAGS_INTERRUPT_ENABLE
Definition regs.h:34
#define atomic_store(object, desired)
Definition stdatomic.h:289
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
_PUBLIC int strcmp(const char *s1, const char *s2)
Definition strcmp.c:3
size_t strnlen_s(const char *s, size_t maxsize)
Definition strnlen_s.c:4
Trap Frame Structure.
Definition interrupt.h:195
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
note_t notes[CONFIG_MAX_NOTES]
Definition note.h:142
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
char buffer[NOTE_MAX]
Definition note.h:122
pid_t sender
Definition note.h:123
Process structure.
Definition process.h:76
note_handler_t noteHandler
Definition process.h:92
space_t space
Definition process.h:84
pid_t id
Definition process.h:81
interrupt_frame_t * frame
If a fake interrupt is generated, this is the interrupt frame to return to.
Definition syscall.h:136
syscall_flags_t flags
Flags for the current syscall.
Definition syscall.h:137
Thread of execution structure.
Definition thread.h:61
process_t * process
The parent process that the thread executes within.
Definition thread.h:62
note_queue_t notes
Definition thread.h:78
syscall_ctx_t syscall
Definition thread.h:79