diff --git a/orbis-kernel/include/orbis/KernelContext.hpp b/orbis-kernel/include/orbis/KernelContext.hpp index 23ad6f28c..93c436661 100644 --- a/orbis-kernel/include/orbis/KernelContext.hpp +++ b/orbis-kernel/include/orbis/KernelContext.hpp @@ -38,6 +38,8 @@ struct UmtxChain { std::pair *enqueue(UmtxKey &key, Thread *thr); void erase(std::pair *obj); + void notify_one(const UmtxKey &key); + void notify_all(const UmtxKey &key); }; class alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__) KernelContext final { diff --git a/orbis-kernel/include/orbis/umtx.hpp b/orbis-kernel/include/orbis/umtx.hpp index 0f6f1eb66..d8c986276 100644 --- a/orbis-kernel/include/orbis/umtx.hpp +++ b/orbis-kernel/include/orbis/umtx.hpp @@ -86,8 +86,7 @@ ErrorCode umtx_wait_uint_private(Thread *thread, ptr addr, ulong id, std::uint64_t ut); ErrorCode umtx_wake_private(Thread *thread, ptr uaddr, sint n_wake); ErrorCode umtx_wait_umutex(Thread *thread, ptr m, std::uint64_t ut); -ErrorCode umtx_wake_umutex(Thread *thread, ptr obj, std::int64_t val, - ptr uaddr1, ptr uaddr2); +ErrorCode umtx_wake_umutex(Thread *thread, ptr m); ErrorCode umtx_sem_wait(Thread *thread, ptr obj, std::int64_t val, ptr uaddr1, ptr uaddr2); ErrorCode umtx_sem_wake(Thread *thread, ptr obj, std::int64_t val, diff --git a/orbis-kernel/src/sys/sys_umtx.cpp b/orbis-kernel/src/sys/sys_umtx.cpp index 0ea318118..bd01dd235 100644 --- a/orbis-kernel/src/sys/sys_umtx.cpp +++ b/orbis-kernel/src/sys/sys_umtx.cpp @@ -15,13 +15,13 @@ static orbis::ErrorCode ureadTimespec(orbis::timespec &ts, } orbis::SysResult orbis::sys__umtx_lock(Thread *thread, ptr umtx) { - ORBIS_LOG_TODO(__FUNCTION__, umtx); + ORBIS_LOG_TRACE(__FUNCTION__, umtx); if (reinterpret_cast(umtx) - 0x10000 > 0xff'fffe'ffff) return ErrorCode::FAULT; return umtx_lock_umtx(thread, umtx, thread->tid, -1); } orbis::SysResult orbis::sys__umtx_unlock(Thread *thread, ptr umtx) { - ORBIS_LOG_TODO(__FUNCTION__, umtx); + ORBIS_LOG_TRACE(__FUNCTION__, umtx); if (reinterpret_cast(umtx) - 0x10000 > 0xff'fffe'ffff) return ErrorCode::FAULT; return umtx_unlock_umtx(thread, umtx, thread->tid); @@ -29,7 +29,7 @@ orbis::SysResult orbis::sys__umtx_unlock(Thread *thread, ptr umtx) { orbis::SysResult orbis::sys__umtx_op(Thread *thread, ptr obj, sint op, ulong val, ptr uaddr1, ptr uaddr2) { - ORBIS_LOG_TODO(__FUNCTION__, obj, op, val, uaddr1, uaddr2); + ORBIS_LOG_TRACE(__FUNCTION__, obj, op, val, uaddr1, uaddr2); if (reinterpret_cast(obj) - 0x10000 > 0xff'fffe'ffff) return ErrorCode::FAULT; auto with_timeout = [&](auto op) -> orbis::ErrorCode { @@ -127,7 +127,7 @@ orbis::SysResult orbis::sys__umtx_op(Thread *thread, ptr obj, sint op, }); } case 18: - return umtx_wake_umutex(thread, obj, val, uaddr1, uaddr2); + return umtx_wake_umutex(thread, (ptr)obj); case 19: return umtx_sem_wait(thread, obj, val, uaddr1, uaddr2); case 20: diff --git a/orbis-kernel/src/umtx.cpp b/orbis-kernel/src/umtx.cpp index fffbd0e1c..4a35300fd 100644 --- a/orbis-kernel/src/umtx.cpp +++ b/orbis-kernel/src/umtx.cpp @@ -27,6 +27,13 @@ void UmtxChain::erase(std::pair *obj) { } } } + +void UmtxChain::notify_one(const UmtxKey &key) { + auto it = sleep_queue.find(key); + it->second.thr = nullptr; + it->second.cv.notify_one(mtx); + this->erase(&*it); +} } // namespace orbis orbis::ErrorCode orbis::umtx_lock_umtx(Thread *thread, ptr umtx, ulong id, @@ -145,10 +152,7 @@ static ErrorCode do_unlock_normal(Thread *thread, ptr m, uint flags) { std::size_t count = chain.sleep_queue.count(key); bool ok = m->owner.compare_exchange_strong( owner, count <= 1 ? kUmutexUnowned : kUmutexContested); - auto it = chain.sleep_queue.find(key); - it->second.thr = nullptr; - it->second.cv.notify_one(chain.mtx); - chain.erase(&*it); + chain.notify_one(key); if (!ok) return ErrorCode::INVAL; return {}; @@ -285,11 +289,23 @@ orbis::ErrorCode orbis::umtx_wait_umutex(Thread *thread, ptr m, return ErrorCode::INVAL; } -orbis::ErrorCode orbis::umtx_wake_umutex(Thread *thread, ptr obj, - std::int64_t val, ptr uaddr1, - ptr uaddr2) { - ORBIS_LOG_TODO(__FUNCTION__, obj, val, uaddr1, uaddr2); - return ErrorCode::NOSYS; +orbis::ErrorCode orbis::umtx_wake_umutex(Thread *thread, ptr m) { + ORBIS_LOG_TRACE(__FUNCTION__, m); + int owner = m->owner.load(std::memory_order::acquire); + if ((owner & ~kUmutexContested) != 0) + return {}; + + [[maybe_unused]] uint flags = uread(&m->flags); + + auto [chain, key, lock] = g_context.getUmtxChain1(thread->tproc->pid, m); + std::size_t count = chain.sleep_queue.count(key); + if (count <= 1) { + owner = kUmutexContested; + m->owner.compare_exchange_strong(owner, kUmutexUnowned); + } + if (count != 0 && (owner & ~kUmutexContested) == 0) + chain.notify_one(key); + return {}; } orbis::ErrorCode orbis::umtx_sem_wait(Thread *thread, ptr obj,