Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit e1f643c

Browse files
committed
Kernel/libc: Allow for futex file descriptors
This way, we can use poll() with futexes. Using poll() with a futex doesn't actually wait on it, but rather unblocks when it is ready to be waited on - so this is inherently racy and should be used with caution.
1 parent 82f7b0d commit e1f643c

File tree

8 files changed

+55
-52
lines changed

8 files changed

+55
-52
lines changed

kernel/api/futex.h

+2-3
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@
44
#pragma once
55
#include "types.h"
66

7-
#define FUTEX_INIT 1
8-
#define FUTEX_DESTROY 2
9-
#define FUTEX_WAIT 3
7+
#define FUTEX_WAIT 1
8+
#define FUTEX_REGFD 2
109

1110
__DECL_BEGIN
1211

kernel/syscall/futex.cpp

+15-24
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
/* Copyright © 2016-2024 Byteduck */
33

44
#include "../tasking/Process.h"
5-
#include "../kernel/api/futex.h"
6-
#include "../kernel/memory/SafePointer.h"
5+
#include "../api/futex.h"
6+
#include "../memory/SafePointer.h"
7+
#include "../filesystem/FileDescriptor.h"
8+
#include "../tasking/Futex.h"
79

810
int Process::sys_futex(UserspacePointer<futex_t> futex, int op) {
911
auto addr = (uintptr_t) futex.raw();
@@ -17,29 +19,18 @@ int Process::sys_futex(UserspacePointer<futex_t> futex, int op) {
1719
return -EPERM;
1820

1921
switch (op) {
20-
case FUTEX_INIT: {
21-
LOCK(m_futex_lock);
22-
if (m_futexes.contains(addr))
23-
return -EEXIST;
24-
m_futexes[addr] = kstd::Arc(new Futex(reg->object(), addr - reg->start()));
25-
return SUCCESS;
26-
}
27-
case FUTEX_DESTROY: {
28-
LOCK(m_futex_lock);
29-
if (!m_futexes.contains(addr))
30-
return -ENOENT;
31-
m_futexes.erase(addr);
32-
}
33-
case FUTEX_WAIT: {
34-
auto k_futex = m_futex_lock.synced<kstd::Arc<Futex>>([this, addr]() {
35-
auto node = m_futexes.find_node(addr);
36-
if (!node)
37-
return kstd::Arc<Futex>();
38-
return node->data.second;
22+
case FUTEX_REGFD:
23+
return m_fd_lock.synced<int>([this, addr, reg] {
24+
auto futex = kstd::Arc(new Futex(reg->object(), addr - reg->start()));
25+
auto fd = kstd::Arc(new FileDescriptor(futex, this));
26+
_file_descriptors.push_back(fd);
27+
fd->set_id((int) _file_descriptors.size() - 1);
28+
return (int)_file_descriptors.size() - 1;
3929
});
40-
if (!k_futex)
41-
return -ENOENT;
42-
TaskManager::current_thread()->block(*k_futex);
30+
case FUTEX_WAIT: {
31+
printf("Wait...\n");
32+
Futex k_futex {reg->object(), addr - reg->start()};
33+
TaskManager::current_thread()->block(k_futex);
4334
return SUCCESS;
4435
}
4536
default:

kernel/tasking/Futex.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,8 @@ Futex::Futex(kstd::Arc<VMObject> object, size_t offset_in_object):
1414

1515
bool Futex::is_ready() {
1616
return m_var->load(MemoryOrder::Relaxed) > 0;
17-
}
17+
}
18+
19+
bool Futex::can_read(const FileDescriptor& fd) {
20+
return is_ready();
21+
}

kernel/tasking/Futex.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,18 @@
55

66
#include "Blocker.h"
77
#include "../memory/VMRegion.h"
8+
#include "../filesystem/File.h"
89

9-
class Futex: public Blocker {
10+
class Futex: public Blocker, public File {
1011
public:
1112
Futex(kstd::Arc<VMObject> object, size_t offset_in_object);
1213

14+
// Blocker
1315
bool is_ready() override;
1416

17+
// File
18+
bool can_read(const FileDescriptor& fd) override;
19+
1520
private:
1621
kstd::Arc<VMObject> m_object;
1722
kstd::Arc<VMRegion> m_k_region;

kernel/tasking/Process.h

-3
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
#include "../api/mmap.h"
3131
#include "Tracer.h"
3232
#include "../kstd/KLog.h"
33-
#include "Futex.h"
3433

3534
class FileDescriptor;
3635
class Blocker;
@@ -245,8 +244,6 @@ class Process {
245244
Mutex m_fd_lock { "Process::FileDescriptor" };
246245
kstd::vector<kstd::Arc<FileDescriptor>> _file_descriptors;
247246
kstd::Arc<LinkedInode> _cwd;
248-
Mutex m_futex_lock { "Process::Futexes" };
249-
kstd::map<uintptr_t, kstd::Arc<Futex>> m_futexes;
250247

251248
//Signals
252249
Signal::SigAction signal_actions[32] = {{Signal::SigAction()}};

libraries/libc/dlfcn.h

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ __DECL_BEGIN
1212
#define RTLD_LAZY 2
1313
#define RTLD_NOW 4
1414
#define RTLD_LOCAL 8
15+
#define RTLD_GLOBAL 16
1516

1617
void* dlopen(const char*, int);
1718
int dlclose(void*);

libraries/libc/sys/futex.c

+16-9
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,8 @@
44
#include "futex.h"
55
#include "syscall.h"
66

7-
int futex_init(futex_t* futex, int val) {
8-
*futex = val;
9-
return syscall3(SYS_FUTEX, (int) futex, FUTEX_INIT);
10-
}
11-
12-
int futex_destroy(futex_t* futex) {
13-
return syscall3(SYS_FUTEX, (int) futex, FUTEX_DESTROY);
7+
int futex_open(futex_t* futex) {
8+
return syscall3(SYS_FUTEX, (int) futex, FUTEX_REGFD);
149
}
1510

1611
void futex_wait(futex_t* futex) {
@@ -20,13 +15,25 @@ void futex_wait(futex_t* futex) {
2015
if (__atomic_compare_exchange_n(futex, &exp, exp - 1, 0, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE))
2116
break;
2217
} else {
23-
if (syscall3_noerr(SYS_FUTEX, (int) futex, FUTEX_WAIT))
24-
return;
18+
syscall3_noerr(SYS_FUTEX, (int) futex, FUTEX_WAIT);
2519
exp = __atomic_load_n(futex, __ATOMIC_RELAXED);
2620
}
2721
}
2822
}
2923

24+
int futex_trywait(futex_t* futex) {
25+
int exp = __atomic_load_n(futex, __ATOMIC_RELAXED);
26+
while (1) {
27+
if (exp > 0) {
28+
if (__atomic_compare_exchange_n(futex, &exp, exp - 1, 0, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE))
29+
break;
30+
} else {
31+
return 0;
32+
}
33+
}
34+
return 1;
35+
}
36+
3037
void futex_signal(futex_t* futex) {
3138
__atomic_fetch_add(futex, 1, __ATOMIC_ACQUIRE);
3239
}

libraries/libc/sys/futex.h

+10-11
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,25 @@
77
__DECL_BEGIN
88

99
/**
10-
* Initializes a futex.
10+
* Registers a futex to a file descriptor, so that it can be waited on using poll().
1111
* @param futex Pointer to the futex_t to initialize.
12-
* @param val The value to initialize the futex with.
13-
* @return 0 on success, -1 on error (errno set).
12+
* @return file descriptor on success, -1 on error (errno set).
1413
*/
15-
int futex_init(futex_t* futex, int val);
16-
17-
/**
18-
* Destroys a futex.
19-
* @param futex Pointer to the futex to destroy.
20-
* @return 0 on success, -1 on error (errno set).
21-
*/
22-
int futex_destroy(futex_t* futex);
14+
int futex_open(futex_t* futex);
2315

2416
/**
2517
* Waits for a futex to be greater than zero and then subtracts one from its stored value.
2618
* @param futex Pointer to the futex to wait on.
2719
*/
2820
void futex_wait(futex_t* futex);
2921

22+
/**
23+
* Tries to wait for a futex to be greater than zero and subtracts one from its stored value if successful.
24+
* @param futex Pointer to the futex to try waiting on.
25+
* @return 1 if the futex was waited on, 0 if not.
26+
*/
27+
int futex_trywait(futex_t* futex);
28+
3029
/**
3130
* Adds one to the futex's stored value.
3231
* @param futex Poitner to the futex to signal.

0 commit comments

Comments
 (0)