PatchworkOS  966e257
A non-POSIX operating system.
Loading...
Searching...
No Matches
futex.c
Go to the documentation of this file.
2#include <kernel/log/log.h>
8#include <kernel/sched/wait.h>
9#include <kernel/sync/futex.h>
10#include <kernel/sync/lock.h>
11#include <kernel/utils/map.h>
12
13#include <errno.h>
14#include <stdlib.h>
15
17{
18 map_init(&ctx->futexes);
19 lock_init(&ctx->lock);
20}
21
23{
24 for (uint64_t i = 0; i < ctx->futexes.capacity; i++)
25 {
26 map_entry_t* entry = ctx->futexes.entries[i];
27 if (!MAP_ENTRY_PTR_IS_VALID(entry))
28 {
29 continue;
30 }
31
32 futex_t* futex = CONTAINER_OF(entry, futex_t, entry);
33 wait_queue_deinit(&futex->queue);
34 free(futex);
35 }
36 map_deinit(&ctx->futexes);
37}
38
39static futex_t* futex_ctx_get(futex_ctx_t* ctx, void* addr)
40{
41 LOCK_SCOPE(&ctx->lock);
42
44 futex_t* futex = CONTAINER_OF_SAFE(map_get(&ctx->futexes, &key), futex_t, entry);
45 if (futex != NULL)
46 {
47 return futex;
48 }
49
50 futex = malloc(sizeof(futex_t));
51 if (futex == NULL)
52 {
53 return NULL;
54 }
55 map_entry_init(&futex->entry);
56 wait_queue_init(&futex->queue);
57
58 map_insert(&ctx->futexes, &key, &futex->entry);
59 return futex;
60}
61
62SYSCALL_DEFINE(SYS_FUTEX, uint64_t, atomic_uint64_t* addr, uint64_t val, futex_op_t op, clock_t timeout)
63{
64 thread_t* thread = sched_thread();
65 process_t* process = thread->process;
66 futex_ctx_t* ctx = &process->futexCtx;
67
68 futex_t* futex = futex_ctx_get(ctx, addr);
69 if (futex == NULL)
70 {
71 return ERR;
72 }
73
74 switch (op)
75 {
76 case FUTEX_WAIT:
77 {
78 wait_queue_t* queue = &futex->queue;
79 if (wait_block_prepare(&queue, 1, timeout) == ERR)
80 {
81 return ERR;
82 }
83
84 uint64_t loadedVal;
85 if (thread_load_atomic_from_user(thread, addr, &loadedVal) == ERR)
86 {
88 return ERR;
89 }
90
91 if (loadedVal != val)
92 {
94 errno = EAGAIN;
95 return ERR;
96 }
97
98 if (wait_block_commit() == ERR)
99 {
100 return ERR;
101 }
102
103 return 0;
104 }
105 case FUTEX_WAKE:
106 {
107 uint64_t amount = wait_unblock(&futex->queue, val, EOK);
108 if (amount == ERR)
109 {
110 return ERR;
111 }
112
113 return amount;
114 }
115 default:
116 {
117 errno = EINVAL;
118 return ERR;
119 }
120 }
121}
#define SYSCALL_DEFINE(num, returnType,...)
Macro to define a syscall.
Definition syscall.h:163
@ SYS_FUTEX
Definition syscall.h:92
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:327
uint64_t wait_block_prepare(wait_queue_t **waitQueues, uint64_t amount, clock_t timeout)
Prepare to block the currently running thread.
Definition wait.c:103
uint64_t wait_unblock(wait_queue_t *queue, uint64_t amount, errno_t err)
Unblock threads waiting on a wait queue.
Definition wait.c:296
uint64_t wait_block_commit(void)
Block the currently running thread.
Definition wait.c:199
void wait_block_cancel(void)
Cancels blocking of the currently running thread.
Definition wait.c:178
void wait_queue_deinit(wait_queue_t *queue)
Deinitialize wait queue.
Definition wait.c:44
void wait_queue_init(wait_queue_t *queue)
Initialize wait queue.
Definition wait.c:38
thread_t * sched_thread(void)
Retrieves the currently running thread.
Definition sched.c:612
void futex_ctx_deinit(futex_ctx_t *ctx)
Deinitialize a per-process futex context. *.
Definition futex.c:22
void futex_ctx_init(futex_ctx_t *ctx)
Initialize a per-process futex context.
Definition futex.c:16
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
void map_init(map_t *map)
Initialize a map.
Definition map.c:176
void map_deinit(map_t *map)
Deinitialize a map.
Definition map.c:184
void map_entry_init(map_entry_t *entry)
Initialize a map entry.
Definition map.c:71
static map_key_t map_key_uint64(uint64_t uint64)
Create a map key from a uint64_t.
Definition map.h:128
uint64_t map_insert(map_t *map, const map_key_t *key, map_entry_t *value)
Insert a key-value pair into the map.
Definition map.c:204
#define MAP_ENTRY_PTR_IS_VALID(entryPtr)
Check if a map entry pointer is valid (not NULL or tombstone).
Definition map.h:80
map_entry_t * map_get(map_t *map, const map_key_t *key)
Get a value from the map by key.
Definition map.c:287
#define EINVAL
Invalid argument.
Definition errno.h:142
#define errno
Error number variable.
Definition errno.h:27
#define EOK
No error.
Definition errno.h:32
#define EAGAIN
Try again.
Definition errno.h:87
futex_op_t
Futex operation enum.
Definition proc.h:186
uint64_t futex(atomic_uint64_t *addr, uint64_t val, futex_op_t op, clock_t timeout)
System call for fast user space mutual exclusion.
Definition futex.c:6
@ FUTEX_WAKE
Wake up one or more threads waiting on the futex.
Definition proc.h:200
@ FUTEX_WAIT
Wait until the timeout expires or the futex value changes.
Definition proc.h:193
#define NULL
Pointer error value.
Definition NULL.h:23
#define ERR
Integer error value.
Definition ERR.h:17
#define CONTAINER_OF(ptr, type, member)
Container of macro.
#define CONTAINER_OF_SAFE(ptr, type, member)
Safe container of macro.
__UINT64_TYPE__ clock_t
A nanosecond time.
Definition clock_t.h:13
static futex_t * futex_ctx_get(futex_ctx_t *ctx, void *addr)
Definition futex.c:39
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
_PUBLIC void * malloc(size_t size)
Definition malloc.c:5
_PUBLIC void free(void *ptr)
Definition free.c:11
Per-process futex context.
Definition futex.h:34
lock_t lock
Definition futex.h:36
map_t futexes
Definition futex.h:35
Futex structure.
Definition futex.h:24
Map entry structure.
Definition map.h:68
Map key stucture.
Definition map.h:56
uint64_t capacity
Definition map.h:91
map_entry_t ** entries
Definition map.h:90
Process structure.
Definition process.h:205
futex_ctx_t futexCtx
Definition process.h:214
Thread of execution structure.
Definition thread.h:56
process_t * process
The parent process that the thread executes within.
Definition thread.h:57
The primitive that threads block on.
Definition wait.h:182