[orbis-kernel] Implement umtx_wait/umtx_wake

This commit is contained in:
Ivan Chikish 2023-07-10 20:46:23 +03:00
parent 9a3054a5d1
commit 205b7d91cf
2 changed files with 29 additions and 8 deletions

View file

@ -64,7 +64,7 @@ ErrorCode umtx_lock_umtx(Thread *thread, ptr<umtx> umtx, ulong id,
std::uint64_t ut);
ErrorCode umtx_unlock_umtx(Thread *thread, ptr<umtx> umtx, ulong id);
ErrorCode umtx_wait(Thread *thread, ptr<void> addr, ulong id, std::uint64_t ut);
ErrorCode umtx_wake(Thread *thread, ptr<void> uaddr, sint n_wake);
ErrorCode umtx_wake(Thread *thread, ptr<void> addr, sint n_wake);
ErrorCode umtx_trylock_umutex(Thread *thread, ptr<umutex> m);
ErrorCode umtx_lock_umutex(Thread *thread, ptr<umutex> m, std::uint64_t ut);
ErrorCode umtx_unlock_umutex(Thread *thread, ptr<umutex> m);

View file

@ -30,6 +30,8 @@ void UmtxChain::erase(std::pair<const UmtxKey, UmtxCond> *obj) {
void UmtxChain::notify_one(const UmtxKey &key) {
auto it = sleep_queue.find(key);
if (it == sleep_queue.end())
return;
it->second.thr = nullptr;
it->second.cv.notify_one(mtx);
this->erase(&*it);
@ -50,14 +52,32 @@ orbis::ErrorCode orbis::umtx_unlock_umtx(Thread *thread, ptr<umtx> umtx,
orbis::ErrorCode orbis::umtx_wait(Thread *thread, ptr<void> addr, ulong id,
std::uint64_t ut) {
ORBIS_LOG_TODO(__FUNCTION__, addr, id, ut);
return ErrorCode::NOSYS;
ORBIS_LOG_NOTICE(__FUNCTION__, addr, id, ut);
auto [chain, key, lock] = g_context.getUmtxChain0(thread->tproc->pid, addr);
auto node = chain.enqueue(key, thread);
ErrorCode result = {};
// TODO: this is inaccurate with timeout as FreeBsd 9.1 only checks id once
if (reinterpret_cast<ptr<std::atomic<ulong>>>(addr)->load() == id) {
node->second.cv.wait(chain.mtx, ut);
if (node->second.thr == thread)
result = ErrorCode::TIMEDOUT;
}
if (node->second.thr == thread)
chain.erase(node);
return result;
}
orbis::ErrorCode orbis::umtx_wake(Thread *thread, ptr<void> uaddr,
sint n_wake) {
ORBIS_LOG_TODO(__FUNCTION__, uaddr, n_wake);
return ErrorCode::NOSYS;
orbis::ErrorCode orbis::umtx_wake(Thread *thread, ptr<void> addr, sint n_wake) {
ORBIS_LOG_NOTICE(__FUNCTION__, addr, n_wake);
auto [chain, key, lock] = g_context.getUmtxChain0(thread->tproc->pid, addr);
std::size_t count = chain.sleep_queue.count(key);
// TODO: check this
while (count--) {
chain.notify_one(key);
if (n_wake-- <= 1)
break;
}
return {};
}
namespace orbis {
@ -152,7 +172,8 @@ static ErrorCode do_unlock_normal(Thread *thread, ptr<umutex> m, uint flags) {
std::size_t count = chain.sleep_queue.count(key);
bool ok = m->owner.compare_exchange_strong(
owner, count <= 1 ? kUmutexUnowned : kUmutexContested);
chain.notify_one(key);
if (count)
chain.notify_one(key);
if (!ok)
return ErrorCode::INVAL;
return {};