Kernel: Optimize futexes
Eeach futex object now has its own mutex to prevent unnecessary locking of the process/global futex lock. This basically removes sys_futex from profiles when running software with llvmpipe
This commit is contained in:
parent
c30fc9d60f
commit
a83fa6f4c6
|
|
@ -348,6 +348,7 @@ namespace Kernel
|
||||||
|
|
||||||
struct futex_t
|
struct futex_t
|
||||||
{
|
{
|
||||||
|
Mutex mutex;
|
||||||
ThreadBlocker blocker;
|
ThreadBlocker blocker;
|
||||||
uint32_t waiters { 0 };
|
uint32_t waiters { 0 };
|
||||||
uint32_t to_wakeup { 0 };
|
uint32_t to_wakeup { 0 };
|
||||||
|
|
|
||||||
|
|
@ -3142,11 +3142,32 @@ namespace Kernel
|
||||||
return SystemTimer::get().ns_since_boot() + (abs_ns - real_ns);
|
return SystemTimer::get().ns_since_boot() + (abs_ns - real_ns);
|
||||||
}());
|
}());
|
||||||
|
|
||||||
|
if (op == FUTEX_WAIT && BAN::atomic_load(*addr) != val)
|
||||||
|
return BAN::Error::from_errno(EAGAIN);
|
||||||
|
|
||||||
|
futex_t* futex;
|
||||||
|
|
||||||
|
{
|
||||||
auto& futex_lock = is_private ? m_futex_lock : s_futex_lock;
|
auto& futex_lock = is_private ? m_futex_lock : s_futex_lock;
|
||||||
auto& futexes = is_private ? m_futexes : s_futexes;
|
auto& futexes = is_private ? m_futexes : s_futexes;
|
||||||
|
|
||||||
LockGuard _(futex_lock);
|
LockGuard _(futex_lock);
|
||||||
|
|
||||||
|
auto it = futexes.find(paddr);
|
||||||
|
if (it != futexes.end())
|
||||||
|
futex = it->value.ptr();
|
||||||
|
else switch (op)
|
||||||
|
{
|
||||||
|
case FUTEX_WAIT:
|
||||||
|
futex = TRY(futexes.emplace(paddr, TRY(BAN::UniqPtr<futex_t>::create())))->value.ptr();
|
||||||
|
break;
|
||||||
|
case FUTEX_WAKE:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LockGuard _(futex->mutex);
|
||||||
|
|
||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
case FUTEX_WAIT:
|
case FUTEX_WAIT:
|
||||||
|
|
@ -3154,20 +3175,17 @@ namespace Kernel
|
||||||
if (BAN::atomic_load(*addr) != val)
|
if (BAN::atomic_load(*addr) != val)
|
||||||
return BAN::Error::from_errno(EAGAIN);
|
return BAN::Error::from_errno(EAGAIN);
|
||||||
|
|
||||||
auto it = futexes.find(paddr);
|
|
||||||
if (it == futexes.end())
|
|
||||||
it = TRY(futexes.emplace(paddr, TRY(BAN::UniqPtr<futex_t>::create())));
|
|
||||||
futex_t* const futex = it->value.ptr();
|
|
||||||
|
|
||||||
futex->waiters++;
|
futex->waiters++;
|
||||||
BAN::ScopeGuard _([futex] {
|
|
||||||
// TODO: Lazily deallocate unused futex objects at some point (?)
|
// TODO: Deallocate unused futex objects at some point (?)
|
||||||
futex->waiters--;
|
// We don't want to do it on every operation as allocation
|
||||||
});
|
// and deletion slows this down a lot and the same addresses
|
||||||
|
// will be probably used again
|
||||||
|
BAN::ScopeGuard cleanup([futex] { futex->waiters--; });
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
TRY(Thread::current().block_or_eintr_or_waketime_ns(futex->blocker, wake_time_ns, true, &futex_lock));
|
TRY(Thread::current().block_or_eintr_or_waketime_ns(futex->blocker, wake_time_ns, true, &futex->mutex));
|
||||||
if (BAN::atomic_load(*addr) == val || futex->to_wakeup == 0)
|
if (BAN::atomic_load(*addr) == val || futex->to_wakeup == 0)
|
||||||
continue;
|
continue;
|
||||||
futex->to_wakeup--;
|
futex->to_wakeup--;
|
||||||
|
|
@ -3176,18 +3194,16 @@ namespace Kernel
|
||||||
}
|
}
|
||||||
case FUTEX_WAKE:
|
case FUTEX_WAKE:
|
||||||
{
|
{
|
||||||
auto it = futexes.find(paddr);
|
|
||||||
if (it == futexes.end())
|
|
||||||
return 0;
|
|
||||||
futex_t* const futex = it->value.ptr();
|
|
||||||
|
|
||||||
if (BAN::Math::will_addition_overflow(futex->to_wakeup, val))
|
if (BAN::Math::will_addition_overflow(futex->to_wakeup, val))
|
||||||
futex->to_wakeup = BAN::numeric_limits<uint32_t>::max();
|
futex->to_wakeup = BAN::numeric_limits<uint32_t>::max();
|
||||||
else
|
else
|
||||||
futex->to_wakeup += val;
|
futex->to_wakeup += val;
|
||||||
|
|
||||||
futex->to_wakeup = BAN::Math::min(futex->to_wakeup, futex->waiters);
|
futex->to_wakeup = BAN::Math::min(futex->to_wakeup, futex->waiters);
|
||||||
|
|
||||||
|
if (futex->to_wakeup > 0)
|
||||||
futex->blocker.unblock();
|
futex->blocker.unblock();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue