mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 23:17:45 +00:00
Kernel: Some futex improvements
This adds support for FUTEX_WAKE_OP, FUTEX_WAIT_BITSET, FUTEX_WAKE_BITSET, FUTEX_REQUEUE, and FUTEX_CMP_REQUEUE, as well well as global and private futex and absolute/relative timeouts against the appropriate clock. This also changes the implementation so that kernel resources are only used when a thread is blocked on a futex. Global futexes are implemented as offsets in VMObjects, so that different processes can share a futex against the same VMObject despite potentially being mapped at different virtual addresses.
This commit is contained in:
parent
7581b64705
commit
1d621ab172
23 changed files with 928 additions and 63 deletions
|
@ -60,10 +60,38 @@ int profiling_disable(pid_t pid)
|
|||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
|
||||
int futex(int32_t* userspace_address, int futex_op, int32_t value, const struct timespec* timeout)
|
||||
int futex(uint32_t* userspace_address, int futex_op, uint32_t value, const struct timespec* timeout, uint32_t* userspace_address2, uint32_t value3)
|
||||
{
|
||||
Syscall::SC_futex_params params { userspace_address, futex_op, value, timeout };
|
||||
int rc = syscall(SC_futex, ¶ms);
|
||||
int rc;
|
||||
switch (futex_op & FUTEX_CMD_MASK) {
|
||||
//case FUTEX_CMP_REQUEUE:
|
||||
// FUTEX_CMP_REQUEUE_PI:
|
||||
case FUTEX_WAKE_OP: {
|
||||
// These interpret timeout as a u32 value for val2
|
||||
Syscall::SC_futex_params params {
|
||||
.userspace_address = userspace_address,
|
||||
.futex_op = futex_op,
|
||||
.val = value,
|
||||
.val2 = (uint32_t)timeout,
|
||||
.userspace_address2 = userspace_address2,
|
||||
.val3 = value3
|
||||
};
|
||||
rc = syscall(SC_futex, ¶ms);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
Syscall::SC_futex_params params {
|
||||
.userspace_address = userspace_address,
|
||||
.futex_op = futex_op,
|
||||
.val = value,
|
||||
.timeout = timeout,
|
||||
.userspace_address2 = userspace_address2,
|
||||
.val3 = value3
|
||||
};
|
||||
rc = syscall(SC_futex, ¶ms);
|
||||
break;
|
||||
}
|
||||
}
|
||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
|
||||
|
|
|
@ -45,10 +45,48 @@ int profiling_disable(pid_t);
|
|||
#define THREAD_PRIORITY_HIGH 50
|
||||
#define THREAD_PRIORITY_MAX 99
|
||||
|
||||
#define _FUTEX_OP_SHIFT_OP 28
|
||||
#define _FUTEX_OP_MASK_OP 0xf
|
||||
#define _FUTEX_OP_SHIFT_CMP 24
|
||||
#define _FUTEX_OP_MASK_CMP 0xf
|
||||
#define _FUTEX_OP_SHIFT_OP_ARG 12
|
||||
#define _FUTEX_OP_MASK_OP_ARG 0xfff
|
||||
#define _FUTEX_OP_SHIFT_CMP_ARG 0
|
||||
#define _FUTEX_OP_MASK_CMP_ARG 0xfff
|
||||
|
||||
#define FUTEX_OP(op, op_arg, cmp, cmp_arg) \
|
||||
((((op)&_FUTEX_OP_MASK_OP) << _FUTEX_OP_SHIFT_OP) | (((cmp)&_FUTEX_OP_MASK_CMP) << _FUTEX_OP_SHIFT_CMP) | (((op_arg)&_FUTEX_OP_MASK_OP_ARG) << _FUTEX_OP_SHIFT_OP_ARG) | (((cmp_arg)&_FUTEX_OP_MASK_CMP_ARG) << _FUTEX_OP_SHIFT_CMP_ARG))
|
||||
|
||||
#define FUTEX_OP_SET 0
|
||||
#define FUTEX_OP_ADD 1
|
||||
#define FUTEX_OP_OR 2
|
||||
#define FUTEX_OP_ANDN 3
|
||||
#define FUTEX_OP_XOR 4
|
||||
#define FUTEX_OP_ARG_SHIFT 8
|
||||
|
||||
#define FUTEX_OP_CMP_EQ 0
|
||||
#define FUTEX_OP_CMP_NE 1
|
||||
#define FUTEX_OP_CMP_LT 2
|
||||
#define FUTEX_OP_CMP_LE 3
|
||||
#define FUTEX_OP_CMP_GT 4
|
||||
#define FUTEX_OP_CMP_GE 5
|
||||
|
||||
#define FUTEX_WAIT 1
|
||||
#define FUTEX_WAKE 2
|
||||
|
||||
int futex(int32_t* userspace_address, int futex_op, int32_t value, const struct timespec* timeout);
|
||||
#define FUTEX_REQUEUE 3
|
||||
#define FUTEX_CMP_REQUEUE 4
|
||||
#define FUTEX_WAKE_OP 5
|
||||
#define FUTEX_WAIT_BITSET 9
|
||||
#define FUTEX_WAKE_BITSET 10
|
||||
|
||||
#define FUTEX_PRIVATE_FLAG (1 << 7)
|
||||
#define FUTEX_CLOCK_REALTIME (1 << 8)
|
||||
#define FUTEX_CMD_MASK ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME)
|
||||
|
||||
#define FUTEX_BITSET_MATCH_ANY 0xffffffff
|
||||
|
||||
int futex(uint32_t* userspace_address, int futex_op, uint32_t value, const struct timespec* timeout, uint32_t* userspace_address2, uint32_t value3);
|
||||
|
||||
#define PURGE_ALL_VOLATILE 0x1
|
||||
#define PURGE_ALL_CLEAN_INODE 0x2
|
||||
|
|
50
Userland/Libraries/LibC/serenity.h.rej
Normal file
50
Userland/Libraries/LibC/serenity.h.rej
Normal file
|
@ -0,0 +1,50 @@
|
|||
diff a/Userland/Libraries/LibC/serenity.h b/Userland/Libraries/LibC/serenity.h (rejected hunks)
|
||||
@@ -55,10 +55,47 @@ int profiling_disable(pid_t);
|
||||
int set_thread_boost(pid_t tid, int amount);
|
||||
int set_process_boost(pid_t, int amount);
|
||||
|
||||
+#define _FUTEX_OP_SHIFT_OP 28
|
||||
+#define _FUTEX_OP_MASK_OP 0xf
|
||||
+#define _FUTEX_OP_SHIFT_CMP 24
|
||||
+#define _FUTEX_OP_MASK_CMP 0xf
|
||||
+#define _FUTEX_OP_SHIFT_OP_ARG 12
|
||||
+#define _FUTEX_OP_MASK_OP_ARG 0xfff
|
||||
+#define _FUTEX_OP_SHIFT_CMP_ARG 0
|
||||
+#define _FUTEX_OP_MASK_CMP_ARG 0xfff
|
||||
+
|
||||
+#define FUTEX_OP(op, op_arg, cmp, cmp_arg) \
|
||||
+ ((((op)&_FUTEX_OP_MASK_OP) << _FUTEX_OP_SHIFT_OP) | (((cmp)&_FUTEX_OP_MASK_CMP) << _FUTEX_OP_SHIFT_CMP) | (((op_arg)&_FUTEX_OP_MASK_OP_ARG) << _FUTEX_OP_SHIFT_OP_ARG) | (((cmp_arg)&_FUTEX_OP_MASK_CMP_ARG) << _FUTEX_OP_SHIFT_CMP_ARG))
|
||||
+
|
||||
+#define FUTEX_OP_SET 0
|
||||
+#define FUTEX_OP_ADD 1
|
||||
+#define FUTEX_OP_OR 2
|
||||
+#define FUTEX_OP_ANDN 3
|
||||
+#define FUTEX_OP_XOR 4
|
||||
+#define FUTEX_OP_ARG_SHIFT 8
|
||||
+
|
||||
+#define FUTEX_OP_CMP_EQ 0
|
||||
+#define FUTEX_OP_CMP_NE 1
|
||||
+#define FUTEX_OP_CMP_LT 2
|
||||
+#define FUTEX_OP_CMP_LE 3
|
||||
+#define FUTEX_OP_CMP_GT 4
|
||||
+#define FUTEX_OP_CMP_GE 5
|
||||
+
|
||||
#define FUTEX_WAIT 1
|
||||
#define FUTEX_WAKE 2
|
||||
+#define FUTEX_REQUEUE 3
|
||||
+#define FUTEX_CMP_REQUEUE 4
|
||||
+#define FUTEX_WAKE_OP 5
|
||||
+#define FUTEX_WAIT_BITSET 9
|
||||
+#define FUTEX_WAKE_BITSET 10
|
||||
+
|
||||
+#define FUTEX_PRIVATE_FLAG (1 << 7)
|
||||
+#define FUTEX_CLOCK_REALTIME (1 << 8)
|
||||
+#define FUTEX_CMD_MASK ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME)
|
||||
+
|
||||
+#define FUTEX_BITSET_MATCH_ANY 0xffffffff
|
||||
|
||||
-int futex(int32_t* userspace_address, int futex_op, int32_t value, const struct timespec* timeout);
|
||||
+int futex(uint32_t* userspace_address, int futex_op, uint32_t value, const struct timespec* timeout, uint32_t* userspace_address2, uint32_t value3);
|
||||
|
||||
#define PURGE_ALL_VOLATILE 0x1
|
||||
#define PURGE_ALL_CLEAN_INODE 0x2
|
|
@ -78,7 +78,7 @@ struct utimbuf {
|
|||
|
||||
typedef int pthread_t;
|
||||
typedef int pthread_key_t;
|
||||
typedef int32_t pthread_once_t;
|
||||
typedef uint32_t pthread_once_t;
|
||||
|
||||
typedef struct __pthread_mutex_t {
|
||||
uint32_t lock;
|
||||
|
@ -93,7 +93,7 @@ typedef struct __pthread_mutexattr_t {
|
|||
} pthread_mutexattr_t;
|
||||
|
||||
typedef struct __pthread_cond_t {
|
||||
int32_t value;
|
||||
uint32_t value;
|
||||
uint32_t previous;
|
||||
int clockid; // clockid_t
|
||||
} pthread_cond_t;
|
||||
|
|
|
@ -495,12 +495,25 @@ int pthread_cond_destroy(pthread_cond_t*)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int futex_wait(uint32_t& futex_addr, uint32_t value, const struct timespec* abstime)
|
||||
{
|
||||
int saved_errno = errno;
|
||||
// NOTE: FUTEX_WAIT takes a relative timeout, so use FUTEX_WAIT_BITSET instead!
|
||||
int rc = futex(&futex_addr, FUTEX_WAIT_BITSET, value, abstime, nullptr, FUTEX_BITSET_MATCH_ANY);
|
||||
if (rc < 0 && errno == EAGAIN) {
|
||||
// If we didn't wait, that's not an error
|
||||
errno = saved_errno;
|
||||
rc = 0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex, const struct timespec* abstime)
|
||||
{
|
||||
i32 value = cond->value;
|
||||
u32 value = cond->value;
|
||||
cond->previous = value;
|
||||
pthread_mutex_unlock(mutex);
|
||||
int rc = futex(&cond->value, FUTEX_WAIT, value, abstime);
|
||||
int rc = futex_wait(cond->value, value, abstime);
|
||||
pthread_mutex_lock(mutex);
|
||||
return rc;
|
||||
}
|
||||
|
@ -538,7 +551,7 @@ int pthread_cond_signal(pthread_cond_t* cond)
|
|||
{
|
||||
u32 value = cond->previous + 1;
|
||||
cond->value = value;
|
||||
int rc = futex(&cond->value, FUTEX_WAKE, 1, nullptr);
|
||||
int rc = futex(&cond->value, FUTEX_WAKE, 1, nullptr, nullptr, 0);
|
||||
ASSERT(rc == 0);
|
||||
return 0;
|
||||
}
|
||||
|
@ -547,7 +560,7 @@ int pthread_cond_broadcast(pthread_cond_t* cond)
|
|||
{
|
||||
u32 value = cond->previous + 1;
|
||||
cond->value = value;
|
||||
int rc = futex(&cond->value, FUTEX_WAKE, INT32_MAX, nullptr);
|
||||
int rc = futex(&cond->value, FUTEX_WAKE, INT32_MAX, nullptr, nullptr, 0);
|
||||
ASSERT(rc == 0);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ int pthread_once(pthread_once_t* self, void (*callback)(void))
|
|||
// anyone.
|
||||
break;
|
||||
case State::PERFORMING_WITH_WAITERS:
|
||||
futex(self, FUTEX_WAKE, INT_MAX, nullptr);
|
||||
futex(self, FUTEX_WAKE, INT_MAX, nullptr, nullptr, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -95,7 +95,7 @@ int pthread_once(pthread_once_t* self, void (*callback)(void))
|
|||
[[fallthrough]];
|
||||
case State::PERFORMING_WITH_WAITERS:
|
||||
// Let's wait for it.
|
||||
futex(self, FUTEX_WAIT, state2, nullptr);
|
||||
futex(self, FUTEX_WAIT, state2, nullptr, nullptr, 0);
|
||||
// We have been woken up, but that might have been due to a signal
|
||||
// or something, so we have to reevaluate. We need acquire ordering
|
||||
// here for the same reason as above. Hopefully we'll just see
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue