diff --git a/orbis-kernel/include/orbis/umtx.hpp b/orbis-kernel/include/orbis/umtx.hpp index 436238154..6ca0e1a1e 100644 --- a/orbis-kernel/include/orbis/umtx.hpp +++ b/orbis-kernel/include/orbis/umtx.hpp @@ -88,10 +88,8 @@ ErrorCode umtx_rw_unlock(Thread *thread, ptr obj, std::int64_t val, 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 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, - ptr uaddr1, ptr uaddr2); +ErrorCode umtx_sem_wait(Thread *thread, ptr sem, std::uint64_t ut); +ErrorCode umtx_sem_wake(Thread *thread, ptr sem); ErrorCode umtx_nwake_private(Thread *thread, ptr uaddrs, std::int64_t count); ErrorCode umtx_wake2_umutex(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 776b08320..df503dc2e 100644 --- a/orbis-kernel/src/sys/sys_umtx.cpp +++ b/orbis-kernel/src/sys/sys_umtx.cpp @@ -66,7 +66,9 @@ orbis::SysResult orbis::sys__umtx_op(Thread *thread, ptr obj, sint op, while (true) { if (auto r = op(usec - udiff); r != ErrorCode::TIMEDOUT) return r; - udiff = (std::chrono::steady_clock::now() - start).count() / 1000; + udiff = std::chrono::duration_cast( + std::chrono::steady_clock::now() - start) + .count(); if (udiff >= usec) return ErrorCode::TIMEDOUT; } @@ -142,9 +144,13 @@ orbis::SysResult orbis::sys__umtx_op(Thread *thread, ptr obj, sint op, case 18: return umtx_wake_umutex(thread, (ptr)obj); case 19: - return umtx_sem_wait(thread, obj, val, uaddr1, uaddr2); + return with_timeout( + [&](std::uint64_t ut) { + return umtx_sem_wait(thread, (ptr)obj, ut); + }, + false); case 20: - return umtx_sem_wake(thread, obj, val, uaddr1, uaddr2); + return umtx_sem_wake(thread, (ptr)obj); case 21: return umtx_nwake_private(thread, (ptr)obj, val); case 22: diff --git a/orbis-kernel/src/umtx.cpp b/orbis-kernel/src/umtx.cpp index a0968822f..18d09bd1c 100644 --- a/orbis-kernel/src/umtx.cpp +++ b/orbis-kernel/src/umtx.cpp @@ -83,7 +83,9 @@ orbis::ErrorCode orbis::umtx_wait(Thread *thread, ptr addr, ulong id, node->second.cv.wait(chain.mtx, ut - udiff); if (node->second.thr != thread) break; - udiff = (std::chrono::steady_clock::now() - start).count() / 1000; + udiff = std::chrono::duration_cast( + std::chrono::steady_clock::now() - start) + .count(); if (udiff >= ut) { result = ErrorCode::TIMEDOUT; break; @@ -315,7 +317,9 @@ orbis::ErrorCode orbis::umtx_cv_wait(Thread *thread, ptr cv, node->second.cv.wait(chain.mtx, ut - udiff); if (node->second.thr != thread) break; - udiff = (std::chrono::steady_clock::now() - start).count() / 1000; + udiff = std::chrono::duration_cast( + std::chrono::steady_clock::now() - start) + .count(); if (udiff >= ut) { result = ErrorCode::TIMEDOUT; break; @@ -415,18 +419,59 @@ orbis::ErrorCode orbis::umtx_wake_umutex(Thread *thread, ptr m) { return {}; } -orbis::ErrorCode orbis::umtx_sem_wait(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_sem_wait(Thread *thread, ptr sem, + std::uint64_t ut) { + ORBIS_LOG_WARNING(__FUNCTION__, sem, ut); + auto [chain, key, lock] = g_context.getUmtxChain0(thread->tproc->pid, sem); + auto node = chain.enqueue(key, thread); + + std::uint32_t has_waiters = sem->has_waiters; + if (!has_waiters) + sem->has_waiters.compare_exchange_strong(has_waiters, 1); + + ErrorCode result = {}; + if (!sem->count) { + if (ut + 1 == 0) { + while (true) { + node->second.cv.wait(chain.mtx, ut); + if (node->second.thr != thread) + break; + } + } else { + auto start = std::chrono::steady_clock::now(); + std::uint64_t udiff = 0; + while (true) { + node->second.cv.wait(chain.mtx, ut - udiff); + if (node->second.thr != thread) + break; + udiff = std::chrono::duration_cast( + std::chrono::steady_clock::now() - start) + .count(); + if (udiff >= ut) { + result = ErrorCode::TIMEDOUT; + break; + } + } + } + } + + if (node->second.thr != thread) { + result = {}; + } else { + chain.erase(node); + } + return result; } -orbis::ErrorCode orbis::umtx_sem_wake(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_sem_wake(Thread *thread, ptr sem) { + ORBIS_LOG_WARNING(__FUNCTION__, sem); + auto [chain, key, lock] = g_context.getUmtxChain0(thread->tproc->pid, sem); + std::size_t count = chain.sleep_queue.count(key); + if (auto up = chain.notify_one(key); up >= count) + thread->retval[0] = sem->has_waiters; + else + thread->retval[0] = 0; + return {}; } orbis::ErrorCode orbis::umtx_nwake_private(Thread *thread, ptr uaddrs,