Kernel+LibPthread+LibC: Add a naive futex and use it for pthread_cond_t

This patch implements a simple version of the futex (fast userspace
mutex) API in the kernel and uses it to make the pthread_cond_t API's
block instead of busily sched_yield().

An arbitrary userspace address is passed to the kernel as a "token"
that identifies the futex and you can then FUTEX_WAIT and FUTEX_WAKE
that specific userspace address.

FUTEX_WAIT corresponds to pthread_cond_wait() and FUTEX_WAKE is used
for pthread_cond_signal() and pthread_cond_broadcast().

I'm pretty sure I'm missing something in this implementation, but it's
hopefully okay for a start. :^)
This commit is contained in:
Andreas Kling 2019-12-22 21:29:47 +01:00
parent 4b8b100b83
commit 4a8683ea68
Notes: sideshowbarker 2024-07-19 10:40:17 +09:00
9 changed files with 99 additions and 55 deletions

View file

@ -3807,3 +3807,47 @@ Thread& Process::any_thread()
ASSERT(found_thread);
return *found_thread;
}
WaitQueue& Process::futex_queue(i32* userspace_address)
{
auto& queue = m_futex_queues.ensure((u32)userspace_address);
if (!queue)
queue = make<WaitQueue>();
return *queue;
}
int Process::sys$futex(const Syscall::SC_futex_params* params)
{
if (!validate_read_typed(params))
return -EFAULT;
auto& [userspace_address, futex_op, value, timeout] = *params;
if (!validate_read_typed(userspace_address))
return -EFAULT;
if (timeout && !validate_read_typed(timeout))
return -EFAULT;
switch (futex_op) {
case FUTEX_WAIT:
if (*userspace_address != value)
return -EAGAIN;
// FIXME: This is supposed to be interruptible by a signal, but right now WaitQueue cannot be interrupted.
// FIXME: Support timeout!
current->wait_on(futex_queue(userspace_address));
break;
case FUTEX_WAKE:
if (value == 0)
return 0;
if (value == 1) {
futex_queue(userspace_address).wake_one();
} else {
// FIXME: Wake exactly (value) waiters.
futex_queue(userspace_address).wake_all();
}
break;
}
return 0;
}