[orbis-kernel] Implement _umtx_op for umutex (no PI)

This commit is contained in:
Ivan Chikish 2023-07-10 13:58:53 +03:00
parent d273e649bd
commit bfffd20946
4 changed files with 328 additions and 94 deletions

View file

@ -1,16 +1,44 @@
#pragma once
#include "evf.hpp"
#include "utils/LinkedNode.hpp"
#include "utils/SharedCV.hpp"
#include "utils/SharedMutex.hpp"
#include "KernelAllocator.hpp"
#include "orbis/thread/types.hpp"
#include <algorithm>
#include <cstdint>
#include <mutex>
#include <pthread.h>
#include <utility>
namespace orbis {
struct Process;
struct Thread;
struct UmtxKey {
// TODO: may contain a reference to a shared memory
void *addr;
pid_t pid;
auto operator<=>(const UmtxKey &) const = default;
};
struct UmtxCond {
Thread *thr;
utils::shared_cv cv;
UmtxCond(Thread *thr) : thr(thr) {}
};
struct UmtxChain {
utils::shared_mutex mtx;
utils::kmultimap<UmtxKey, UmtxCond> sleep_queue;
utils::kmultimap<UmtxKey, UmtxCond> spare_queue;
std::pair<const UmtxKey, UmtxCond> *enqueue(UmtxKey &key, Thread *thr);
void erase(std::pair<const UmtxKey, UmtxCond> *obj);
};
class alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__) KernelContext final {
public:
@ -47,6 +75,31 @@ public:
return {};
}
enum {
c_golden_ratio_prime = 2654404609u,
c_umtx_chains = 512,
c_umtx_shifts = 23,
};
// Use getUmtxChain0 or getUmtxChain1
std::tuple<UmtxChain &, UmtxKey, std::unique_lock<shared_mutex>>
getUmtxChainIndexed(int i, pid_t pid, void *ptr) {
auto n = reinterpret_cast<std::uintptr_t>(ptr) + pid;
n = ((n * c_golden_ratio_prime) >> c_umtx_shifts) % c_umtx_chains;
std::unique_lock lock(m_umtx_chains[i][n].mtx);
return {m_umtx_chains[i][n], UmtxKey{ptr, pid}, std::move(lock)};
}
// Internal Umtx: Wait/Cv/Sem
auto getUmtxChain0(pid_t pid, void *ptr) {
return getUmtxChainIndexed(0, pid, ptr);
}
// Internal Umtx: Mutex/Umtx/Rwlock
auto getUmtxChain1(pid_t pid, void *ptr) {
return getUmtxChainIndexed(1, pid, ptr);
}
private:
shared_mutex m_evf_mtx;
mutable pthread_mutex_t m_heap_mtx;
@ -55,6 +108,8 @@ private:
utils::kmultimap<std::size_t, void *> m_free_heap;
utils::kmultimap<std::size_t, void *> m_used_node;
UmtxChain m_umtx_chains[2][c_umtx_chains]{};
mutable shared_mutex m_proc_mtx;
utils::LinkedNode<Process> *m_processes = nullptr;
utils::kmap<utils::kstring, Ref<EventFlag>> m_event_flags;

View file

@ -61,22 +61,21 @@ struct usem {
struct Thread;
ErrorCode umtx_lock_umtx(Thread *thread, ptr<umtx> umtx, ulong id,
timespec *ts);
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,
timespec *timeout);
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_trylock_umutex(Thread *thread, ptr<umutex> m);
ErrorCode umtx_lock_umutex(Thread *thread, ptr<umutex> m, timespec *timeout);
ErrorCode umtx_lock_umutex(Thread *thread, ptr<umutex> m, std::uint64_t ut);
ErrorCode umtx_unlock_umutex(Thread *thread, ptr<umutex> m);
ErrorCode umtx_set_ceiling(Thread *thread, ptr<umutex> m, std::uint32_t ceiling,
ptr<uint32_t> oldCeiling);
ErrorCode umtx_cv_wait(Thread *thread, ptr<ucond> cv, ptr<umutex> m,
timespec *ts, ulong wflags);
std::uint64_t ut, ulong wflags);
ErrorCode umtx_cv_signal(Thread *thread, ptr<ucond> cv);
ErrorCode umtx_cv_broadcast(Thread *thread, ptr<ucond> cv);
ErrorCode umtx_wait_uint(Thread *thread, ptr<void> addr, ulong id,
timespec *timeout);
std::uint64_t ut);
ErrorCode umtx_rw_rdlock(Thread *thread, ptr<void> obj, std::int64_t val,
ptr<void> uaddr1, ptr<void> uaddr2);
ErrorCode umtx_rw_wrlock(Thread *thread, ptr<void> obj, std::int64_t val,
@ -84,9 +83,9 @@ ErrorCode umtx_rw_wrlock(Thread *thread, ptr<void> obj, std::int64_t val,
ErrorCode umtx_rw_unlock(Thread *thread, ptr<void> obj, std::int64_t val,
ptr<void> uaddr1, ptr<void> uaddr2);
ErrorCode umtx_wait_uint_private(Thread *thread, ptr<void> addr, ulong id,
timespec *timeout);
std::uint64_t ut);
ErrorCode umtx_wake_private(Thread *thread, ptr<void> uaddr, sint n_wake);
ErrorCode umtx_wait_umutex(Thread *thread, ptr<umutex> m, timespec *timeout);
ErrorCode umtx_wait_umutex(Thread *thread, ptr<umutex> m, std::uint64_t ut);
ErrorCode umtx_wake_umutex(Thread *thread, ptr<void> obj, std::int64_t val,
ptr<void> uaddr1, ptr<void> uaddr2);
ErrorCode umtx_sem_wait(Thread *thread, ptr<void> obj, std::int64_t val,

View file

@ -1,6 +1,8 @@
#include "orbis/utils/Logs.hpp"
#include "sys/sysproto.hpp"
#include "time.hpp"
#include "umtx.hpp"
#include <chrono>
static orbis::ErrorCode ureadTimespec(orbis::timespec &ts,
orbis::ptr<orbis::timespec> addr) {
@ -13,16 +15,24 @@ static orbis::ErrorCode ureadTimespec(orbis::timespec &ts,
}
orbis::SysResult orbis::sys__umtx_lock(Thread *thread, ptr<umtx> umtx) {
return umtx_lock_umtx(thread, umtx, thread->tid, nullptr);
ORBIS_LOG_TODO(__FUNCTION__, umtx);
if (reinterpret_cast<std::uintptr_t>(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> umtx) {
ORBIS_LOG_TODO(__FUNCTION__, umtx);
if (reinterpret_cast<std::uintptr_t>(umtx) - 0x10000 > 0xff'fffe'ffff)
return ErrorCode::FAULT;
return umtx_unlock_umtx(thread, umtx, thread->tid);
}
orbis::SysResult orbis::sys__umtx_op(Thread *thread, ptr<void> obj, sint op,
ulong val, ptr<void> uaddr1,
ptr<void> uaddr2) {
switch (op) {
case 0: {
ORBIS_LOG_TODO(__FUNCTION__, obj, op, val, uaddr1, uaddr2);
if (reinterpret_cast<std::uintptr_t>(obj) - 0x10000 > 0xff'fffe'ffff)
return ErrorCode::FAULT;
auto with_timeout = [&](auto op) -> orbis::ErrorCode {
timespec *ts = nullptr;
timespec timeout;
if (uaddr2 != nullptr) {
@ -33,41 +43,49 @@ orbis::SysResult orbis::sys__umtx_op(Thread *thread, ptr<void> obj, sint op,
ts = &timeout;
}
std::uint64_t usec = 0;
auto start = std::chrono::steady_clock::now();
return umtx_lock_umtx(thread, (ptr<umtx>)obj, val, ts);
if (!ts) {
usec = -1;
while (true) {
if (auto r = op(usec); r != ErrorCode::TIMEDOUT)
return r;
}
} else {
usec += (timeout.nsec + 999) / 1000;
usec += timeout.sec * 1000'000;
std::uint64_t udiff = 0;
while (true) {
if (auto r = op(usec - udiff); r != ErrorCode::TIMEDOUT)
return r;
udiff = (std::chrono::steady_clock::now() - start).count() / 1000;
if (udiff >= usec)
return ErrorCode::TIMEDOUT;
}
}
};
switch (op) {
case 0: {
return with_timeout([&](std::uint64_t ut) {
return umtx_lock_umtx(thread, (ptr<umtx>)obj, val, ut);
});
}
case 1:
return umtx_unlock_umtx(thread, (ptr<umtx>)obj, val);
case 2: {
timespec *ts = nullptr;
timespec timeout;
if (uaddr2 != nullptr) {
auto result = ureadTimespec(timeout, (ptr<timespec>)uaddr2);
if (result != ErrorCode{}) {
return result;
}
ts = &timeout;
}
return umtx_wait(thread, obj, val, ts);
return with_timeout(
[&](std::uint64_t ut) { return umtx_wait(thread, obj, val, ut); });
}
case 3:
return umtx_wake(thread, obj, val);
case 4:
return umtx_trylock_umutex(thread, (ptr<umutex>)obj);
case 5: {
timespec *ts = nullptr;
timespec timeout;
if (uaddr2 != nullptr) {
auto result = ureadTimespec(timeout, (ptr<timespec>)uaddr2);
if (result != ErrorCode{}) {
return result;
}
ts = &timeout;
}
return umtx_lock_umutex(thread, (ptr<umutex>)obj, ts);
return with_timeout([&](std::uint64_t ut) {
return umtx_lock_umutex(thread, (ptr<umutex>)obj, ut);
});
}
case 6:
return umtx_unlock_umutex(thread, (ptr<umutex>)obj);
@ -76,18 +94,10 @@ orbis::SysResult orbis::sys__umtx_op(Thread *thread, ptr<void> obj, sint op,
(ptr<uint32_t>)uaddr1);
case 8: {
timespec *ts = nullptr;
timespec timeout;
if (uaddr2 != nullptr) {
auto result = ureadTimespec(timeout, (ptr<timespec>)uaddr2);
if (result != ErrorCode{}) {
return result;
}
ts = &timeout;
}
return umtx_cv_wait(thread, (ptr<ucond>)obj, (ptr<umutex>)uaddr1, ts, val);
return with_timeout([&](std::uint64_t ut) {
return umtx_cv_wait(thread, (ptr<ucond>)obj, (ptr<umutex>)uaddr1, ut,
val);
});
}
case 9:
@ -95,18 +105,8 @@ orbis::SysResult orbis::sys__umtx_op(Thread *thread, ptr<void> obj, sint op,
case 10:
return umtx_cv_broadcast(thread, (ptr<ucond>)obj);
case 11: {
timespec *ts = nullptr;
timespec timeout;
if (uaddr2 != nullptr) {
auto result = ureadTimespec(timeout, (ptr<timespec>)uaddr2);
if (result != ErrorCode{}) {
return result;
}
ts = &timeout;
}
return umtx_wait_uint(thread, obj, val, ts);
return with_timeout(
[&](std::uint64_t ut) { return umtx_wait_uint(thread, obj, val, ut); });
}
case 12:
return umtx_rw_rdlock(thread, obj, val, uaddr1, uaddr2);
@ -115,34 +115,16 @@ orbis::SysResult orbis::sys__umtx_op(Thread *thread, ptr<void> obj, sint op,
case 14:
return umtx_rw_unlock(thread, obj, val, uaddr1, uaddr2);
case 15: {
timespec *ts = nullptr;
timespec timeout;
if (uaddr2 != nullptr) {
auto result = ureadTimespec(timeout, (ptr<timespec>)uaddr2);
if (result != ErrorCode{}) {
return result;
}
ts = &timeout;
}
return umtx_wait_uint_private(thread, obj, val, ts);
return with_timeout([&](std::uint64_t ut) {
return umtx_wait_uint_private(thread, obj, val, ut);
});
}
case 16:
return umtx_wake_private(thread, obj, val);
case 17: {
timespec *ts = nullptr;
timespec timeout;
if (uaddr2 != nullptr) {
auto result = ureadTimespec(timeout, (ptr<timespec>)uaddr2);
if (result != ErrorCode{}) {
return result;
}
ts = &timeout;
}
return umtx_wait_umutex(thread, (ptr<umutex>)obj, ts);
return with_timeout([&](std::uint64_t ut) {
return umtx_wait_umutex(thread, (ptr<umutex>)obj, ut);
});
}
case 18:
return umtx_wake_umutex(thread, obj, val, uaddr1, uaddr2);

View file

@ -1,122 +1,320 @@
#include "umtx.hpp"
#include "orbis/KernelContext.hpp"
#include "orbis/thread.hpp"
#include "orbis/utils/AtomicOp.hpp"
#include "orbis/utils/Logs.hpp"
#include "time.hpp"
namespace orbis {
std::pair<const UmtxKey, UmtxCond> *UmtxChain::enqueue(UmtxKey &key,
Thread *thr) {
if (!spare_queue.empty()) {
auto node = spare_queue.extract(spare_queue.begin());
node.key() = key;
node.mapped().thr = thr;
return &*sleep_queue.insert(std::move(node));
}
return &*sleep_queue.emplace(key, thr);
}
void UmtxChain::erase(std::pair<const UmtxKey, UmtxCond> *obj) {
for (auto [it, e] = sleep_queue.equal_range(obj->first); it != e; it++) {
if (&*it == obj) {
auto node = sleep_queue.extract(it);
node.key() = {};
spare_queue.insert(spare_queue.begin(), std::move(node));
return;
}
}
}
} // namespace orbis
orbis::ErrorCode orbis::umtx_lock_umtx(Thread *thread, ptr<umtx> umtx, ulong id,
timespec *ts) {
std::uint64_t ut) {
ORBIS_LOG_TODO(__FUNCTION__, umtx, id, ut);
return ErrorCode::NOSYS;
}
orbis::ErrorCode orbis::umtx_unlock_umtx(Thread *thread, ptr<umtx> umtx,
ulong id) {
ORBIS_LOG_TODO(__FUNCTION__, umtx, id);
return ErrorCode::NOSYS;
}
orbis::ErrorCode orbis::umtx_wait(Thread *thread, ptr<void> addr, ulong id,
timespec *timeout) {
std::uint64_t ut) {
ORBIS_LOG_TODO(__FUNCTION__, addr, id, ut);
return ErrorCode::NOSYS;
}
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_trylock_umutex(Thread *thread, ptr<umutex> m) {
namespace orbis {
enum class umutex_lock_mode {
lock,
try_,
wait,
};
template <>
void log_class_string<umutex_lock_mode>::format(std::string &out,
const void *arg) {
switch (get_object(arg)) {
case umutex_lock_mode::lock:
out += "lock";
break;
case umutex_lock_mode::try_:
out += "try";
break;
case umutex_lock_mode::wait:
out += "wait";
break;
}
}
static ErrorCode do_lock_normal(Thread *thread, ptr<umutex> m, uint flags,
std::uint64_t ut, umutex_lock_mode mode) {
ORBIS_LOG_NOTICE(__FUNCTION__, m, flags, ut, mode);
ErrorCode error = {};
while (true) {
int owner = m->owner.load(std::memory_order_acquire);
if (mode == umutex_lock_mode::wait) {
if (owner == kUmutexUnowned || owner == kUmutexContested)
return {};
} else {
owner = kUmutexUnowned;
if (m->owner.compare_exchange_strong(owner, thread->tid))
return {};
if (owner == kUmutexContested) {
if (m->owner.compare_exchange_strong(owner,
thread->tid | kUmutexContested))
return {};
continue;
}
}
if ((flags & kUmutexErrorCheck) != 0 &&
(owner & ~kUmutexContested) == thread->tid)
return ErrorCode::DEADLK;
if (mode == umutex_lock_mode::try_)
return ErrorCode::BUSY;
if (error != ErrorCode{})
return error;
auto [chain, key, lock] = g_context.getUmtxChain1(thread->tproc->pid, m);
auto node = chain.enqueue(key, thread);
bool ok = m->owner.compare_exchange_strong(owner, owner | kUmutexContested);
if (ok && node->second.thr == thread) {
node->second.cv.wait(chain.mtx, ut);
if (node->second.thr)
error = ErrorCode::TIMEDOUT;
}
if (node->second.thr == thread)
chain.erase(node);
}
return {};
}
static ErrorCode do_lock_pi(Thread *thread, ptr<umutex> m, uint flags,
std::uint64_t ut, umutex_lock_mode mode) {
ORBIS_LOG_TODO(__FUNCTION__, m, flags, ut, mode);
return ErrorCode::NOSYS;
}
static ErrorCode do_lock_pp(Thread *thread, ptr<umutex> m, uint flags,
std::uint64_t ut, umutex_lock_mode mode) {
ORBIS_LOG_TODO(__FUNCTION__, m, flags, ut, mode);
return ErrorCode::NOSYS;
}
static ErrorCode do_unlock_normal(Thread *thread, ptr<umutex> m, uint flags) {
ORBIS_LOG_NOTICE(__FUNCTION__, m, flags);
int owner = m->owner.load(std::memory_order_acquire);
if ((owner & ~kUmutexContested) != thread->tid)
return ErrorCode::PERM;
if ((owner & kUmtxContested) == 0) {
if (m->owner.compare_exchange_strong(owner, kUmutexUnowned))
return {};
}
auto [chain, key, lock] = g_context.getUmtxChain1(thread->tproc->pid, m);
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);
if (!ok)
return ErrorCode::INVAL;
return {};
}
static ErrorCode do_unlock_pi(Thread *thread, ptr<umutex> m, uint flags) {
ORBIS_LOG_TODO(__FUNCTION__, m, flags);
return ErrorCode::NOSYS;
}
static ErrorCode do_unlock_pp(Thread *thread, ptr<umutex> m, uint flags) {
ORBIS_LOG_TODO(__FUNCTION__, m, flags);
return ErrorCode::NOSYS;
}
} // namespace orbis
orbis::ErrorCode orbis::umtx_trylock_umutex(Thread *thread, ptr<umutex> m) {
ORBIS_LOG_TRACE(__FUNCTION__, m);
uint flags = uread(&m->flags);
switch (flags & (kUmutexPrioInherit | kUmutexPrioProtect)) {
case 0:
return do_lock_normal(thread, m, flags, 0, umutex_lock_mode::try_);
case kUmutexPrioInherit:
return do_lock_pi(thread, m, flags, 0, umutex_lock_mode::try_);
case kUmutexPrioProtect:
return do_lock_pp(thread, m, flags, 0, umutex_lock_mode::try_);
}
return ErrorCode::INVAL;
}
orbis::ErrorCode orbis::umtx_lock_umutex(Thread *thread, ptr<umutex> m,
timespec *timeout) {
return ErrorCode::NOSYS;
std::uint64_t ut) {
ORBIS_LOG_TRACE(__FUNCTION__, m, ut);
uint flags = uread(&m->flags);
switch (flags & (kUmutexPrioInherit | kUmutexPrioProtect)) {
case 0:
return do_lock_normal(thread, m, flags, ut, umutex_lock_mode::lock);
case kUmutexPrioInherit:
return do_lock_pi(thread, m, flags, ut, umutex_lock_mode::lock);
case kUmutexPrioProtect:
return do_lock_pp(thread, m, flags, ut, umutex_lock_mode::lock);
}
return ErrorCode::INVAL;
}
orbis::ErrorCode orbis::umtx_unlock_umutex(Thread *thread, ptr<umutex> m) {
return ErrorCode::NOSYS;
ORBIS_LOG_TRACE(__FUNCTION__, m);
uint flags = uread(&m->flags);
switch (flags & (kUmutexPrioInherit | kUmutexPrioProtect)) {
case 0:
return do_unlock_normal(thread, m, flags);
case kUmutexPrioInherit:
return do_unlock_pi(thread, m, flags);
case kUmutexPrioProtect:
return do_unlock_pp(thread, m, flags);
}
return ErrorCode::INVAL;
}
orbis::ErrorCode orbis::umtx_set_ceiling(Thread *thread, ptr<umutex> m,
std::uint32_t ceiling,
ptr<uint32_t> oldCeiling) {
ORBIS_LOG_TODO(__FUNCTION__, m, ceiling, oldCeiling);
return ErrorCode::NOSYS;
}
orbis::ErrorCode orbis::umtx_cv_wait(Thread *thread, ptr<ucond> cv,
ptr<umutex> m, timespec *ts,
ptr<umutex> m, std::uint64_t ut,
ulong wflags) {
ORBIS_LOG_TODO(__FUNCTION__, cv, m, ut, wflags);
return ErrorCode::NOSYS;
}
orbis::ErrorCode orbis::umtx_cv_signal(Thread *thread, ptr<ucond> cv) {
ORBIS_LOG_TODO(__FUNCTION__, cv);
return ErrorCode::NOSYS;
}
orbis::ErrorCode orbis::umtx_cv_broadcast(Thread *thread, ptr<ucond> cv) {
ORBIS_LOG_TODO(__FUNCTION__, cv);
return ErrorCode::NOSYS;
}
orbis::ErrorCode orbis::umtx_wait_uint(Thread *thread, ptr<void> addr, ulong id,
timespec *timeout) {
std::uint64_t ut) {
ORBIS_LOG_TODO(__FUNCTION__, addr, id, ut);
return ErrorCode::NOSYS;
}
orbis::ErrorCode orbis::umtx_rw_rdlock(Thread *thread, ptr<void> obj,
std::int64_t val, ptr<void> uaddr1,
ptr<void> uaddr2) {
ORBIS_LOG_TODO(__FUNCTION__, obj, val, uaddr1, uaddr2);
return ErrorCode::NOSYS;
}
orbis::ErrorCode orbis::umtx_rw_wrlock(Thread *thread, ptr<void> obj,
std::int64_t val, ptr<void> uaddr1,
ptr<void> uaddr2) {
ORBIS_LOG_TODO(__FUNCTION__, obj, val, uaddr1, uaddr2);
return ErrorCode::NOSYS;
}
orbis::ErrorCode orbis::umtx_rw_unlock(Thread *thread, ptr<void> obj,
std::int64_t val, ptr<void> uaddr1,
ptr<void> uaddr2) {
ORBIS_LOG_TODO(__FUNCTION__, obj, val, uaddr1, uaddr2);
return ErrorCode::NOSYS;
}
orbis::ErrorCode orbis::umtx_wait_uint_private(Thread *thread, ptr<void> addr,
ulong id, timespec *timeout) {
ulong id, std::uint64_t ut) {
ORBIS_LOG_TODO(__FUNCTION__, addr, id, ut);
return ErrorCode::NOSYS;
}
orbis::ErrorCode orbis::umtx_wake_private(Thread *thread, ptr<void> uaddr,
sint n_wake) {
ORBIS_LOG_TODO(__FUNCTION__, uaddr, n_wake);
return ErrorCode::NOSYS;
}
orbis::ErrorCode orbis::umtx_wait_umutex(Thread *thread, ptr<umutex> m,
timespec *timeout) {
return ErrorCode::NOSYS;
std::uint64_t ut) {
ORBIS_LOG_TRACE(__FUNCTION__, m, ut);
uint flags = uread(&m->flags);
switch (flags & (kUmutexPrioInherit | kUmutexPrioProtect)) {
case 0:
return do_lock_normal(thread, m, flags, ut, umutex_lock_mode::wait);
case kUmutexPrioInherit:
return do_lock_pi(thread, m, flags, ut, umutex_lock_mode::wait);
case kUmutexPrioProtect:
return do_lock_pp(thread, m, flags, ut, umutex_lock_mode::wait);
}
return ErrorCode::INVAL;
}
orbis::ErrorCode orbis::umtx_wake_umutex(Thread *thread, ptr<void> obj,
std::int64_t val, ptr<void> uaddr1,
ptr<void> uaddr2) {
ORBIS_LOG_TODO(__FUNCTION__, obj, val, uaddr1, uaddr2);
return ErrorCode::NOSYS;
}
orbis::ErrorCode orbis::umtx_sem_wait(Thread *thread, ptr<void> obj,
std::int64_t val, ptr<void> uaddr1,
ptr<void> uaddr2) {
ORBIS_LOG_TODO(__FUNCTION__, obj, val, uaddr1, uaddr2);
return ErrorCode::NOSYS;
}
orbis::ErrorCode orbis::umtx_sem_wake(Thread *thread, ptr<void> obj,
std::int64_t val, ptr<void> uaddr1,
ptr<void> uaddr2) {
ORBIS_LOG_TODO(__FUNCTION__, obj, val, uaddr1, uaddr2);
return ErrorCode::NOSYS;
}
orbis::ErrorCode orbis::umtx_nwake_private(Thread *thread, ptr<void> uaddrs,
std::int64_t count) {
ORBIS_LOG_TODO(__FUNCTION__, uaddrs, count);
return ErrorCode::NOSYS;
}
orbis::ErrorCode orbis::umtx_wake2_umutex(Thread *thread, ptr<void> obj,
std::int64_t val, ptr<void> uaddr1,
ptr<void> uaddr2) {
ORBIS_LOG_TODO(__FUNCTION__, obj, val, uaddr1, uaddr2);
return ErrorCode::NOSYS;
}