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