diff --git a/orbis-kernel/include/orbis/KernelContext.hpp b/orbis-kernel/include/orbis/KernelContext.hpp index 93c436661..46d1e3ab0 100644 --- a/orbis-kernel/include/orbis/KernelContext.hpp +++ b/orbis-kernel/include/orbis/KernelContext.hpp @@ -38,8 +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); + uint notify_one(const UmtxKey &key); + uint notify_all(const UmtxKey &key); }; class alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__) KernelContext final { diff --git a/orbis-kernel/src/umtx.cpp b/orbis-kernel/src/umtx.cpp index 2c746f7cc..d56871527 100644 --- a/orbis-kernel/src/umtx.cpp +++ b/orbis-kernel/src/umtx.cpp @@ -28,13 +28,21 @@ void UmtxChain::erase(std::pair *obj) { } } -void UmtxChain::notify_one(const UmtxKey &key) { +uint UmtxChain::notify_one(const UmtxKey &key) { auto it = sleep_queue.find(key); if (it == sleep_queue.end()) - return; + return 0; it->second.thr = nullptr; it->second.cv.notify_one(mtx); this->erase(&*it); + return 1; +} + +uint UmtxChain::notify_all(const UmtxKey &key) { + uint n = 0; + while (notify_one(key)) + n++; + return n; } } // namespace orbis @@ -302,12 +310,19 @@ orbis::ErrorCode orbis::umtx_cv_wait(Thread *thread, ptr cv, } orbis::ErrorCode orbis::umtx_cv_signal(Thread *thread, ptr cv) { - ORBIS_LOG_TODO(__FUNCTION__, cv); - return ErrorCode::NOSYS; + ORBIS_LOG_NOTICE(__FUNCTION__, cv); + auto [chain, key, lock] = g_context.getUmtxChain0(thread->tproc->pid, cv); + std::size_t count = chain.sleep_queue.count(key); + if (chain.notify_one(key) >= count) + cv->has_waiters.store(0, std::memory_order::relaxed); + return {}; } orbis::ErrorCode orbis::umtx_cv_broadcast(Thread *thread, ptr cv) { - ORBIS_LOG_TODO(__FUNCTION__, cv); + ORBIS_LOG_NOTICE(__FUNCTION__, cv); + auto [chain, key, lock] = g_context.getUmtxChain0(thread->tproc->pid, cv); + chain.notify_all(key); + cv->has_waiters.store(0, std::memory_order::relaxed); return ErrorCode::NOSYS; }