forked from Bananymous/banan-os
Add support for processor local futexes. These work the exact same way as global ones, but only lock a process specific lock and use a process specific hash map. Also reduce the time futex lock is held. There was no need to hold the global lock while validating addresses in the process' address space.
65 lines
1.3 KiB
C++
65 lines
1.3 KiB
C++
#include <BAN/Atomic.h>
|
|
|
|
#include <errno.h>
|
|
#include <semaphore.h>
|
|
#include <sys/futex.h>
|
|
|
|
int sem_destroy(sem_t* sem)
|
|
{
|
|
(void)sem;
|
|
return 0;
|
|
}
|
|
|
|
int sem_init(sem_t* sem, int pshared, unsigned value)
|
|
{
|
|
*sem = {
|
|
.shared = pshared,
|
|
.value = value,
|
|
};
|
|
return 0;
|
|
}
|
|
|
|
int sem_getvalue(sem_t* __restrict sem, int* __restrict sval)
|
|
{
|
|
*sval = BAN::atomic_load(sem->value);
|
|
return 0;
|
|
}
|
|
|
|
int sem_post(sem_t* sem)
|
|
{
|
|
const auto old = BAN::atomic_fetch_add(sem->value, 1);
|
|
const int op = FUTEX_WAKE | (sem->shared ? 0 : FUTEX_PRIVATE);
|
|
if (old == 0)
|
|
futex(op, &sem->value, 1, nullptr);
|
|
return 0;
|
|
}
|
|
|
|
int sem_trywait(sem_t* sem)
|
|
{
|
|
uint32_t expected = BAN::atomic_load(sem->value);
|
|
while (expected)
|
|
if (BAN::atomic_compare_exchange(sem->value, expected, expected - 1))
|
|
return 0;
|
|
errno = EAGAIN;
|
|
return -1;
|
|
}
|
|
|
|
int sem_timedwait(sem_t* __restrict sem, const struct timespec* __restrict abstime)
|
|
{
|
|
for (;;)
|
|
{
|
|
uint32_t expected = BAN::atomic_load(sem->value);
|
|
if (expected > 0 && BAN::atomic_compare_exchange(sem->value, expected, expected - 1))
|
|
return 0;
|
|
|
|
const int op = FUTEX_WAIT | (sem->shared ? 0 : FUTEX_PRIVATE) | FUTEX_REALTIME;
|
|
if (futex(op, &sem->value, expected, abstime) == -1 && (errno == EINTR || errno == ETIMEDOUT))
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int sem_wait(sem_t* sem)
|
|
{
|
|
return sem_timedwait(sem, nullptr);
|
|
}
|