2023-07-08 01:50:45 +02:00
|
|
|
#include "umtx.hpp"
|
2023-07-10 12:58:53 +02:00
|
|
|
#include "orbis/KernelContext.hpp"
|
|
|
|
|
#include "orbis/thread.hpp"
|
|
|
|
|
#include "orbis/utils/AtomicOp.hpp"
|
|
|
|
|
#include "orbis/utils/Logs.hpp"
|
2023-07-09 12:52:38 +02:00
|
|
|
#include "time.hpp"
|
2023-07-08 01:50:45 +02:00
|
|
|
|
2023-07-10 12:58:53 +02:00
|
|
|
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
|
|
|
|
|
|
2023-07-09 12:52:38 +02:00
|
|
|
orbis::ErrorCode orbis::umtx_lock_umtx(Thread *thread, ptr<umtx> umtx, ulong id,
|
2023-07-10 12:58:53 +02:00
|
|
|
std::uint64_t ut) {
|
|
|
|
|
ORBIS_LOG_TODO(__FUNCTION__, umtx, id, ut);
|
2023-07-08 01:50:45 +02:00
|
|
|
return ErrorCode::NOSYS;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-09 12:52:38 +02:00
|
|
|
orbis::ErrorCode orbis::umtx_unlock_umtx(Thread *thread, ptr<umtx> umtx,
|
|
|
|
|
ulong id) {
|
2023-07-10 12:58:53 +02:00
|
|
|
ORBIS_LOG_TODO(__FUNCTION__, umtx, id);
|
2023-07-08 01:50:45 +02:00
|
|
|
return ErrorCode::NOSYS;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-09 12:52:38 +02:00
|
|
|
orbis::ErrorCode orbis::umtx_wait(Thread *thread, ptr<void> addr, ulong id,
|
2023-07-10 12:58:53 +02:00
|
|
|
std::uint64_t ut) {
|
|
|
|
|
ORBIS_LOG_TODO(__FUNCTION__, addr, id, ut);
|
2023-07-08 01:50:45 +02:00
|
|
|
return ErrorCode::NOSYS;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-09 12:52:38 +02:00
|
|
|
orbis::ErrorCode orbis::umtx_wake(Thread *thread, ptr<void> uaddr,
|
|
|
|
|
sint n_wake) {
|
2023-07-10 12:58:53 +02:00
|
|
|
ORBIS_LOG_TODO(__FUNCTION__, uaddr, n_wake);
|
2023-07-08 01:50:45 +02:00
|
|
|
return ErrorCode::NOSYS;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-10 12:58:53 +02:00
|
|
|
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);
|
2023-07-08 01:50:45 +02:00
|
|
|
return ErrorCode::NOSYS;
|
|
|
|
|
}
|
2023-07-10 12:58:53 +02:00
|
|
|
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);
|
2023-07-08 01:50:45 +02:00
|
|
|
|
2023-07-10 12:58:53 +02:00
|
|
|
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);
|
2023-07-08 01:50:45 +02:00
|
|
|
return ErrorCode::NOSYS;
|
|
|
|
|
}
|
2023-07-10 12:58:53 +02:00
|
|
|
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,
|
|
|
|
|
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;
|
|
|
|
|
}
|
2023-07-08 01:50:45 +02:00
|
|
|
|
2023-07-09 12:52:38 +02:00
|
|
|
orbis::ErrorCode orbis::umtx_unlock_umutex(Thread *thread, ptr<umutex> m) {
|
2023-07-10 12:58:53 +02:00
|
|
|
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;
|
2023-07-08 01:50:45 +02:00
|
|
|
}
|
|
|
|
|
|
2023-07-09 12:52:38 +02:00
|
|
|
orbis::ErrorCode orbis::umtx_set_ceiling(Thread *thread, ptr<umutex> m,
|
|
|
|
|
std::uint32_t ceiling,
|
|
|
|
|
ptr<uint32_t> oldCeiling) {
|
2023-07-10 12:58:53 +02:00
|
|
|
ORBIS_LOG_TODO(__FUNCTION__, m, ceiling, oldCeiling);
|
2023-07-08 01:50:45 +02:00
|
|
|
return ErrorCode::NOSYS;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-09 12:52:38 +02:00
|
|
|
orbis::ErrorCode orbis::umtx_cv_wait(Thread *thread, ptr<ucond> cv,
|
2023-07-10 12:58:53 +02:00
|
|
|
ptr<umutex> m, std::uint64_t ut,
|
2023-07-09 12:52:38 +02:00
|
|
|
ulong wflags) {
|
2023-07-10 12:58:53 +02:00
|
|
|
ORBIS_LOG_TODO(__FUNCTION__, cv, m, ut, wflags);
|
2023-07-08 01:50:45 +02:00
|
|
|
return ErrorCode::NOSYS;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-09 12:52:38 +02:00
|
|
|
orbis::ErrorCode orbis::umtx_cv_signal(Thread *thread, ptr<ucond> cv) {
|
2023-07-10 12:58:53 +02:00
|
|
|
ORBIS_LOG_TODO(__FUNCTION__, cv);
|
2023-07-08 01:50:45 +02:00
|
|
|
return ErrorCode::NOSYS;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-09 12:52:38 +02:00
|
|
|
orbis::ErrorCode orbis::umtx_cv_broadcast(Thread *thread, ptr<ucond> cv) {
|
2023-07-10 12:58:53 +02:00
|
|
|
ORBIS_LOG_TODO(__FUNCTION__, cv);
|
2023-07-08 01:50:45 +02:00
|
|
|
return ErrorCode::NOSYS;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-09 12:52:38 +02:00
|
|
|
orbis::ErrorCode orbis::umtx_wait_uint(Thread *thread, ptr<void> addr, ulong id,
|
2023-07-10 12:58:53 +02:00
|
|
|
std::uint64_t ut) {
|
|
|
|
|
ORBIS_LOG_TODO(__FUNCTION__, addr, id, ut);
|
2023-07-08 01:50:45 +02:00
|
|
|
return ErrorCode::NOSYS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
orbis::ErrorCode orbis::umtx_rw_rdlock(Thread *thread, ptr<void> obj,
|
|
|
|
|
std::int64_t val, ptr<void> uaddr1,
|
|
|
|
|
ptr<void> uaddr2) {
|
2023-07-10 12:58:53 +02:00
|
|
|
ORBIS_LOG_TODO(__FUNCTION__, obj, val, uaddr1, uaddr2);
|
2023-07-08 01:50:45 +02:00
|
|
|
return ErrorCode::NOSYS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
orbis::ErrorCode orbis::umtx_rw_wrlock(Thread *thread, ptr<void> obj,
|
|
|
|
|
std::int64_t val, ptr<void> uaddr1,
|
|
|
|
|
ptr<void> uaddr2) {
|
2023-07-10 12:58:53 +02:00
|
|
|
ORBIS_LOG_TODO(__FUNCTION__, obj, val, uaddr1, uaddr2);
|
2023-07-08 01:50:45 +02:00
|
|
|
return ErrorCode::NOSYS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
orbis::ErrorCode orbis::umtx_rw_unlock(Thread *thread, ptr<void> obj,
|
|
|
|
|
std::int64_t val, ptr<void> uaddr1,
|
|
|
|
|
ptr<void> uaddr2) {
|
2023-07-10 12:58:53 +02:00
|
|
|
ORBIS_LOG_TODO(__FUNCTION__, obj, val, uaddr1, uaddr2);
|
2023-07-08 01:50:45 +02:00
|
|
|
return ErrorCode::NOSYS;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-09 12:52:38 +02:00
|
|
|
orbis::ErrorCode orbis::umtx_wait_uint_private(Thread *thread, ptr<void> addr,
|
2023-07-10 12:58:53 +02:00
|
|
|
ulong id, std::uint64_t ut) {
|
|
|
|
|
ORBIS_LOG_TODO(__FUNCTION__, addr, id, ut);
|
2023-07-08 01:50:45 +02:00
|
|
|
return ErrorCode::NOSYS;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-09 12:52:38 +02:00
|
|
|
orbis::ErrorCode orbis::umtx_wake_private(Thread *thread, ptr<void> uaddr,
|
|
|
|
|
sint n_wake) {
|
2023-07-10 12:58:53 +02:00
|
|
|
ORBIS_LOG_TODO(__FUNCTION__, uaddr, n_wake);
|
2023-07-08 01:50:45 +02:00
|
|
|
return ErrorCode::NOSYS;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-09 12:52:38 +02:00
|
|
|
orbis::ErrorCode orbis::umtx_wait_umutex(Thread *thread, ptr<umutex> m,
|
2023-07-10 12:58:53 +02:00
|
|
|
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;
|
2023-07-08 01:50:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
orbis::ErrorCode orbis::umtx_wake_umutex(Thread *thread, ptr<void> obj,
|
|
|
|
|
std::int64_t val, ptr<void> uaddr1,
|
|
|
|
|
ptr<void> uaddr2) {
|
2023-07-10 12:58:53 +02:00
|
|
|
ORBIS_LOG_TODO(__FUNCTION__, obj, val, uaddr1, uaddr2);
|
2023-07-08 01:50:45 +02:00
|
|
|
return ErrorCode::NOSYS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
orbis::ErrorCode orbis::umtx_sem_wait(Thread *thread, ptr<void> obj,
|
|
|
|
|
std::int64_t val, ptr<void> uaddr1,
|
|
|
|
|
ptr<void> uaddr2) {
|
2023-07-10 12:58:53 +02:00
|
|
|
ORBIS_LOG_TODO(__FUNCTION__, obj, val, uaddr1, uaddr2);
|
2023-07-08 01:50:45 +02:00
|
|
|
return ErrorCode::NOSYS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
orbis::ErrorCode orbis::umtx_sem_wake(Thread *thread, ptr<void> obj,
|
|
|
|
|
std::int64_t val, ptr<void> uaddr1,
|
|
|
|
|
ptr<void> uaddr2) {
|
2023-07-10 12:58:53 +02:00
|
|
|
ORBIS_LOG_TODO(__FUNCTION__, obj, val, uaddr1, uaddr2);
|
2023-07-08 01:50:45 +02:00
|
|
|
return ErrorCode::NOSYS;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-09 12:52:38 +02:00
|
|
|
orbis::ErrorCode orbis::umtx_nwake_private(Thread *thread, ptr<void> uaddrs,
|
|
|
|
|
std::int64_t count) {
|
2023-07-10 12:58:53 +02:00
|
|
|
ORBIS_LOG_TODO(__FUNCTION__, uaddrs, count);
|
2023-07-08 01:50:45 +02:00
|
|
|
return ErrorCode::NOSYS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
orbis::ErrorCode orbis::umtx_wake2_umutex(Thread *thread, ptr<void> obj,
|
|
|
|
|
std::int64_t val, ptr<void> uaddr1,
|
|
|
|
|
ptr<void> uaddr2) {
|
2023-07-10 12:58:53 +02:00
|
|
|
ORBIS_LOG_TODO(__FUNCTION__, obj, val, uaddr1, uaddr2);
|
2023-07-08 01:50:45 +02:00
|
|
|
return ErrorCode::NOSYS;
|
|
|
|
|
}
|