PatchworkOS  966e257
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/sync/lock.h>
11
12#include <assert.h>
13#include <errno.h>
14#include <stdlib.h>
15#include <string.h>
16#include <sys/math.h>
17
19{
20 handler->func = NULL;
21 lock_init(&handler->lock);
22}
23
25{
26 queue->readIndex = 0;
27 queue->writeIndex = 0;
28 queue->length = 0;
29 queue->flags = NOTE_QUEUE_NONE;
30 memset_s(&queue->noteFrame, sizeof(interrupt_frame_t), 0, sizeof(interrupt_frame_t));
31 lock_init(&queue->lock);
32}
33
35{
36 LOCK_SCOPE(&queue->lock);
37 uint64_t length = queue->length;
39 {
40 length++;
41 }
42 return length;
43}
44
45uint64_t note_send(note_queue_t* queue, const char* string)
46{
47 if (queue == NULL || string == NULL)
48 {
49 errno = EINVAL;
50 return ERR;
51 }
52
53 size_t count = strnlen_s(string, NOTE_MAX);
54 if (count == 0 || count >= NOTE_MAX)
55 {
56 errno = EINVAL;
57 return ERR;
58 }
59
60 process_t* sender = sched_process();
61
62 LOCK_SCOPE(&queue->lock);
63
64 if (strcmp(string, "kill") == 0)
65 {
67 return 0;
68 }
69
70 if (queue->length >= CONFIG_MAX_NOTES)
71 {
72 errno = EAGAIN;
73 return ERR;
74 }
75
76 note_t* note = &queue->notes[queue->writeIndex];
77 queue->writeIndex = (queue->writeIndex + 1) % CONFIG_MAX_NOTES;
78 queue->length++;
79
80 memcpy_s(note->buffer, NOTE_MAX, string, count);
81 note->buffer[count] = '\0';
82 note->sender = sender->id;
83 return 0;
84}
85
87{
88 (void)frame;
89 (void)self;
90
92 {
93 return false;
94 }
95
96 thread_t* thread = sched_thread_unsafe();
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 = sched_process();
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 = sched_thread();
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 INTERRUPT_FRAME_IN_USER_SPACE(frame)
Checks if a interrupt frame is from user space.
Definition interrupt.h:180
#define SYSCALL_DEFINE(num, returnType,...)
Macro to define a syscall.
Definition syscall.h:163
@ SYS_NOTIFY
Definition syscall.h:99
@ SYS_NOTED
Definition syscall.h:100
@ SYSCALL_FORCE_FAKE_INTERRUPT
Definition syscall.h:116
#define RED_ZONE_SIZE
The size of the red zone in bytes.
Definition defs.h:90
#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
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 LOG_DEBUG(format,...)
Definition log.h:100
uint64_t space_check_access(space_t *space, const void *addr, uint64_t length)
Checks if a virtual memory region is within the allowed address range of the space.
Definition space.c:478
uint64_t thread_copy_to_user(thread_t *thread, void *dest, const void *userSrc, uint64_t length)
Safely copy data to user space.
Definition thread.c:200
@ THREAD_DYING
The thread is currently dying, it will be freed by the scheduler once its invoked.
Definition thread.h:36
process_t * sched_process(void)
Retrieves the process of the currently running thread.
Definition sched.c:620
thread_t * sched_thread(void)
Retrieves the currently running thread.
Definition sched.c:612
thread_t * sched_thread_unsafe(void)
Retrieves the currently running thread without disabling interrupts.
Definition sched.c:626
_NORETURN void sched_thread_exit(void)
Terminates the currently executing thread.
Definition sched.c:658
static void lock_init(lock_t *lock)
Initializes a lock.
Definition lock.h:86
#define LOCK_SCOPE(lock)
Acquires a lock for the reminder of the current scope.
Definition lock.h:57
static void lock_release(lock_t *lock)
Releases a lock.
Definition lock.h:146
static void lock_acquire(lock_t *lock)
Acquires a lock, blocking until it is available.
Definition lock.h:103
#define CONFIG_MAX_NOTES
Maximum note queue configuration.
Definition config.h:67
#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 ROUND_DOWN(number, multiple)
Definition math.h:21
void(* note_func_t)(char *note)
Note handler function type.
Definition proc.h:262
#define NULL
Pointer error value.
Definition NULL.h:23
#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:10
#define RFLAGS_INTERRUPT_ENABLE
Definition regs.h:32
#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
CPU structure.
Definition cpu.h:122
Trap Frame Structure.
Definition interrupt.h:146
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
note_t notes[CONFIG_MAX_NOTES]
Definition note.h:137
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
char buffer[NOTE_MAX]
Definition note.h:117
pid_t sender
Definition note.h:118
Process structure.
Definition process.h:205
note_handler_t noteHandler
Definition process.h:216
space_t space
Definition process.h:210
pid_t id
Definition process.h:206
interrupt_frame_t * frame
If a fake interrupt is generated, this is the interrupt frame to return to.
Definition syscall.h:127
syscall_flags_t flags
Flags for the current syscall.
Definition syscall.h:128
Thread of execution structure.
Definition thread.h:56
process_t * process
The parent process that the thread executes within.
Definition thread.h:57
note_queue_t notes
Definition thread.h:73
syscall_ctx_t syscall
Definition thread.h:74