MOS Source Code
Loading...
Searching...
No Matches
futex.c
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#include "mos/platform/platform_defs.h"
4
7#include <mos/locks/futex.h>
10#include <mos/syslog/printk.h>
11#include <mos/tasks/schedule.h>
12#include <mos/tasks/wait.h>
13#include <mos/types.h>
14#include <mos_stdlib.h>
15
17
24
27
29{
30 const ptr_t vaddr = (ptr_t) futex;
31 if (vaddr >= MOS_KERNEL_START_VADDR)
32 return vaddr;
33 return mm_get_phys_addr(current_process->mm, vaddr);
34}
35
36bool futex_wait(futex_word_t *futex, futex_word_t expected)
37{
38 const futex_word_t current_value = __atomic_load_n(futex, __ATOMIC_SEQ_CST);
39
40 if (current_value != expected)
41 {
42 //
43 // The purpose of the comparison with the expected value is to prevent lost wake-ups.
44 //
45 // if another thread changed the futex word value after the calling thread decided to block based on the prior value
46 // and, if that thread executed a futex_wake (or similar wake-up) after the value change before this FUTEX_WAIT operation
47 // then, with this check, the calling thread will observe the value change and will not start to sleep.
48 //
49 // | thread A | thread B |
50 // |--------------------|--------------------|
51 // | Check futex value | |
52 // | decide to block | |
53 // | | Change futex value |
54 // | | Execute futex_wake |
55 // | system call | |
56 // |--------------------|--------------------|
57 // | this check fails | | <--- if this check was not here, thread A would block, losing a wake-up
58 // |--------------------|--------------------|
59 // | unblocked | |
60 // |--------------------|--------------------|
61 //
62 return false;
63 }
64
65 // firstly find the futex in the list
66 // if it's not there, create a new one add the current thread to the waiters list
67 // then reschedule
68 const futex_key_t key = futex_get_key(futex);
69
71
74 {
75 if (f->key == key)
76 {
77 fu = f;
78 break;
79 }
80 }
81
82 if (!fu)
83 {
84 fu = kmalloc(sizeof(futex_private_t));
85 fu->key = key;
88 }
90
91 pr_dinfo2(futex, "tid %pt waiting on lock key=" PTR_FMT, (void *) current_thread, key);
92
93 bool ok = reschedule_for_waitlist(&fu->waiters);
94 MOS_ASSERT(ok);
95
96 pr_dinfo2(futex, "tid %pt woke up", (void *) current_thread);
97 return true;
98}
99
100bool futex_wake(futex_word_t *futex, size_t num_to_wake)
101{
102 if (unlikely(num_to_wake == 0))
103 mos_panic("insane number of threads to wake up (?): %zd", num_to_wake);
104
105 const futex_key_t key = futex_get_key(futex);
106 futex_private_t *fu = NULL;
107
110 {
111 if (f->key == key)
112 {
113 fu = f;
114 break;
115 }
116 }
118
119 if (!fu)
120 {
121 // no threads are waiting on this futex, or it's the first time it's being used by only one thread
122 return true;
123 }
124
125 pr_dinfo2(futex, "waking up %zd threads on lock key=" PTR_FMT, num_to_wake, key);
126 const size_t real_wakeups = waitlist_wake(&fu->waiters, num_to_wake);
127 pr_dinfo2(futex, "actually woke up %zd threads", real_wakeups);
128
129 return true;
130}
#define MOS_ASSERT(cond)
Definition assert.h:14
ptr_t futex_key_t
Definition futex.c:16
static spinlock_t futex_list_lock
Definition futex.c:26
static futex_key_t futex_get_key(const futex_word_t *futex)
Definition futex.c:28
static list_head futex_list_head
Definition futex.c:25
#define LIST_HEAD_INIT(container)
Definition list.h:38
MOSAPI void list_node_append(list_node_t *head, list_node_t *item)
Definition list.c:68
#define list_foreach(t, v, h)
Iterate over a list.
Definition list.h:83
#define list_node(element)
Get the ‘list_node’ of a list element. This is exactly the reverse of ‘list_entry’ above.
Definition list.h:68
list_node_t list_head
A linked list head.
Definition list.h:23
ptr_t mm_get_phys_addr(mm_context_t *ctx, ptr_t vaddr)
Definition paging.c:179
#define unlikely(x)
Definition mos_global.h:40
#define futex_wake(futex, val)
Definition mutex.c:10
#define futex_wait(futex, val)
Definition mutex.c:9
#define mos_panic(fmt,...)
Definition panic.h:55
#define NULL
Definition pb_syshdr.h:46
#define current_thread
Definition platform.h:30
#define current_process
Definition platform.h:31
#define pr_dinfo2(feat, fmt,...)
Definition printk.h:27
#define MOS_KERNEL_START_VADDR
__nodiscard bool reschedule_for_waitlist(waitlist_t *waitlist)
Definition schedule.c:174
#define spinlock_acquire(lock)
Definition spinlock.h:61
#define SPINLOCK_INIT
Definition spinlock.h:28
#define spinlock_release(lock)
Definition spinlock.h:62
waitlist_t waiters
Definition futex.c:22
futex_key_t key
Definition futex.c:21
s32 futex_word_t
Definition types.h:99
#define PTR_FMT
Definition types.h:33
unsigned long ptr_t
Definition types.h:25
size_t waitlist_wake(waitlist_t *list, size_t max_wakeups)
Definition wait.c:45
__BEGIN_DECLS void waitlist_init(waitlist_t *list)
Definition wait.c:23