mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-01-30 20:34:45 +01:00
[orbis-kernel] Initial osem semaphore implementation
This commit is contained in:
parent
00690fd685
commit
439444d72b
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
#include "evf.hpp"
|
||||
#include "osem.hpp"
|
||||
#include "utils/LinkedNode.hpp"
|
||||
#include "utils/SharedCV.hpp"
|
||||
#include "utils/SharedMutex.hpp"
|
||||
|
|
@ -81,6 +82,28 @@ public:
|
|||
return {};
|
||||
}
|
||||
|
||||
std::pair<Semaphore *, bool> createSemaphore(utils::kstring name,
|
||||
std::uint32_t attrs,
|
||||
std::int32_t initCount,
|
||||
std::int32_t maxCount) {
|
||||
std::lock_guard lock(m_sem_mtx);
|
||||
auto [it, inserted] = m_semaphores.try_emplace(std::move(name), nullptr);
|
||||
if (inserted) {
|
||||
it->second = knew<Semaphore>(attrs, initCount, maxCount);
|
||||
}
|
||||
|
||||
return {it->second.get(), inserted};
|
||||
}
|
||||
|
||||
Ref<Semaphore> findSemaphore(std::string_view name) {
|
||||
std::lock_guard lock(m_sem_mtx);
|
||||
if (auto it = m_semaphores.find(name); it != m_semaphores.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
enum {
|
||||
c_golden_ratio_prime = 2654404609u,
|
||||
c_umtx_chains = 512,
|
||||
|
|
@ -122,6 +145,9 @@ private:
|
|||
|
||||
shared_mutex m_evf_mtx;
|
||||
utils::kmap<utils::kstring, Ref<EventFlag>> m_event_flags;
|
||||
|
||||
shared_mutex m_sem_mtx;
|
||||
utils::kmap<utils::kstring, Ref<Semaphore>> m_semaphores;
|
||||
};
|
||||
|
||||
extern KernelContext &g_context;
|
||||
|
|
|
|||
45
orbis-kernel/include/orbis/osem.hpp
Normal file
45
orbis-kernel/include/orbis/osem.hpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#pragma once
|
||||
|
||||
#include "KernelAllocator.hpp"
|
||||
#include "thread/Thread.hpp"
|
||||
#include "utils/SharedCV.hpp"
|
||||
#include "utils/SharedMutex.hpp"
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
|
||||
namespace orbis {
|
||||
enum {
|
||||
kSemaAttrThFifo = 1,
|
||||
kSemaAttrThPrio = 2,
|
||||
kSemaAttrShared = 256,
|
||||
};
|
||||
|
||||
struct Semaphore final {
|
||||
char name[32];
|
||||
|
||||
bool isDeleted = false;
|
||||
std::uint8_t attrs;
|
||||
std::atomic<unsigned> references{0};
|
||||
std::atomic<sint> value;
|
||||
const sint maxValue;
|
||||
utils::shared_mutex mtx;
|
||||
utils::shared_cv cond;
|
||||
|
||||
Semaphore(uint attrs, sint value, sint max)
|
||||
: attrs(attrs), value(value), maxValue(max) {}
|
||||
|
||||
void destroy() {
|
||||
std::lock_guard lock(mtx);
|
||||
isDeleted = true;
|
||||
cond.notify_all(mtx);
|
||||
}
|
||||
|
||||
void incRef() { references.fetch_add(1, std::memory_order::relaxed); }
|
||||
|
||||
void decRef() {
|
||||
if (references.fetch_sub(1, std::memory_order::relaxed) == 1) {
|
||||
kdelete(this);
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace orbis
|
||||
|
|
@ -635,14 +635,16 @@ SysResult sys_evf_cancel(Thread *thread, sint id, uint64_t value,
|
|||
ptr<sint> pNumWaitThreads);
|
||||
SysResult sys_query_memory_protection(Thread *thread /* TODO */);
|
||||
SysResult sys_batch_map(Thread *thread /* TODO */);
|
||||
SysResult sys_osem_create(Thread *thread /* TODO */);
|
||||
SysResult sys_osem_delete(Thread *thread /* TODO */);
|
||||
SysResult sys_osem_open(Thread *thread /* TODO */);
|
||||
SysResult sys_osem_close(Thread *thread /* TODO */);
|
||||
SysResult sys_osem_wait(Thread *thread /* TODO */);
|
||||
SysResult sys_osem_trywait(Thread *thread /* TODO */);
|
||||
SysResult sys_osem_post(Thread *thread /* TODO */);
|
||||
SysResult sys_osem_cancel(Thread *thread /* TODO */);
|
||||
SysResult sys_osem_create(Thread *thread, ptr<const char[32]> name, uint attrs,
|
||||
sint initCount, sint maxCount);
|
||||
SysResult sys_osem_delete(Thread *thread, sint id);
|
||||
SysResult sys_osem_open(Thread *thread, ptr<const char[32]> name);
|
||||
SysResult sys_osem_close(Thread *thread, sint id);
|
||||
SysResult sys_osem_wait(Thread *thread, sint id, sint need, ptr<uint> pTimeout);
|
||||
SysResult sys_osem_trywait(Thread *thread, sint id, sint need);
|
||||
SysResult sys_osem_post(Thread *thread, sint id, sint count);
|
||||
SysResult sys_osem_cancel(Thread *thread, sint id, sint set,
|
||||
ptr<uint> pNumWaitThreads);
|
||||
SysResult sys_namedobj_create(Thread *thread, ptr<const char[32]> name,
|
||||
ptr<void> object, uint16_t type);
|
||||
SysResult sys_namedobj_delete(Thread *thread, uint id, uint16_t type);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include "orbis-config.hpp"
|
||||
|
||||
#include "../evf.hpp"
|
||||
#include "../osem.hpp"
|
||||
#include "../thread/Thread.hpp"
|
||||
#include "../thread/types.hpp"
|
||||
#include "ProcessState.hpp"
|
||||
|
|
@ -57,6 +58,7 @@ struct Process final {
|
|||
std::uint64_t lastTlsOffset = 0;
|
||||
|
||||
utils::RcIdMap<EventFlag, sint, 4097, 1> evfMap;
|
||||
utils::RcIdMap<Semaphore, sint, 4097, 1> semMap;
|
||||
utils::RcIdMap<Module, ModuleHandle> modulesMap;
|
||||
utils::OwningIdMap<Thread, lwpid_t> threadsMap;
|
||||
utils::RcIdMap<utils::RcBase, sint> fileDescriptors;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "module/ModuleInfo.hpp"
|
||||
#include "module/ModuleInfoEx.hpp"
|
||||
#include "orbis/time.hpp"
|
||||
#include "osem.hpp"
|
||||
#include "sys/sysproto.hpp"
|
||||
#include "utils/Logs.hpp"
|
||||
#include <chrono>
|
||||
|
|
@ -283,28 +284,139 @@ orbis::SysResult orbis::sys_query_memory_protection(Thread *thread /* TODO */) {
|
|||
orbis::SysResult orbis::sys_batch_map(Thread *thread /* TODO */) {
|
||||
return ErrorCode::NOSYS;
|
||||
}
|
||||
orbis::SysResult orbis::sys_osem_create(Thread *thread /* TODO */) {
|
||||
orbis::SysResult orbis::sys_osem_create(Thread *thread,
|
||||
ptr<const char[32]> name, uint attrs,
|
||||
sint initCount, sint maxCount) {
|
||||
ORBIS_LOG_WARNING(__FUNCTION__, name, attrs, initCount, maxCount);
|
||||
if (name == nullptr) {
|
||||
return ErrorCode::INVAL;
|
||||
}
|
||||
|
||||
if (attrs & ~(kSemaAttrThPrio | kSemaAttrThFifo | kSemaAttrShared)) {
|
||||
return ErrorCode::INVAL;
|
||||
}
|
||||
|
||||
switch (attrs & (kSemaAttrThPrio | kSemaAttrThFifo)) {
|
||||
case kSemaAttrThPrio | kSemaAttrThFifo:
|
||||
return ErrorCode::INVAL;
|
||||
case 0:
|
||||
attrs |= kSemaAttrThFifo;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (maxCount <= 0 || initCount < 0 || maxCount < initCount)
|
||||
return ErrorCode::INVAL;
|
||||
|
||||
char _name[32];
|
||||
if (auto result = ureadString(_name, sizeof(_name), (const char *)name);
|
||||
result != ErrorCode{}) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Semaphore *sem;
|
||||
if (attrs & kSemaAttrShared) {
|
||||
auto [insertedSem, ok] = thread->tproc->context->createSemaphore(
|
||||
_name, attrs, initCount, maxCount);
|
||||
|
||||
if (!ok) {
|
||||
return ErrorCode::EXIST; // FIXME: verify
|
||||
}
|
||||
|
||||
sem = insertedSem;
|
||||
} else {
|
||||
sem = knew<Semaphore>(attrs, initCount, maxCount);
|
||||
}
|
||||
|
||||
thread->retval[0] = thread->tproc->semMap.insert(sem);
|
||||
return {};
|
||||
}
|
||||
orbis::SysResult orbis::sys_osem_delete(Thread *thread /* TODO */) {
|
||||
return ErrorCode::NOSYS;
|
||||
orbis::SysResult orbis::sys_osem_delete(Thread *thread, sint id) {
|
||||
ORBIS_LOG_WARNING(__FUNCTION__, id);
|
||||
Ref<Semaphore> sem = thread->tproc->semMap.get(id);
|
||||
if (sem == nullptr) {
|
||||
return ErrorCode::SRCH;
|
||||
}
|
||||
|
||||
thread->tproc->semMap.destroy(id);
|
||||
return {};
|
||||
}
|
||||
orbis::SysResult orbis::sys_osem_open(Thread *thread /* TODO */) {
|
||||
return ErrorCode::NOSYS;
|
||||
orbis::SysResult orbis::sys_osem_open(Thread *thread,
|
||||
ptr<const char[32]> name) {
|
||||
ORBIS_LOG_WARNING(__FUNCTION__, name);
|
||||
char _name[32];
|
||||
if (auto result = ureadString(_name, sizeof(_name), (const char *)name);
|
||||
result != ErrorCode{}) {
|
||||
return result;
|
||||
}
|
||||
|
||||
auto sem = thread->tproc->context->findSemaphore(_name);
|
||||
if (sem == nullptr) {
|
||||
return ErrorCode::SRCH;
|
||||
}
|
||||
|
||||
thread->retval[0] = thread->tproc->semMap.insert(sem);
|
||||
return {};
|
||||
}
|
||||
orbis::SysResult orbis::sys_osem_close(Thread *thread /* TODO */) {
|
||||
return ErrorCode::NOSYS;
|
||||
orbis::SysResult orbis::sys_osem_close(Thread *thread, sint id) {
|
||||
ORBIS_LOG_WARNING(__FUNCTION__, id);
|
||||
if (!thread->tproc->semMap.close(id)) {
|
||||
return ErrorCode::SRCH;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
orbis::SysResult orbis::sys_osem_wait(Thread *thread /* TODO */) {
|
||||
return ErrorCode::NOSYS;
|
||||
orbis::SysResult orbis::sys_osem_wait(Thread *thread, sint id, sint need,
|
||||
ptr<uint> pTimeout) {
|
||||
ORBIS_LOG_NOTICE(__FUNCTION__, thread, id, need, pTimeout);
|
||||
Ref<Semaphore> sem = thread->tproc->semMap.get(id);
|
||||
if (pTimeout)
|
||||
ORBIS_LOG_FATAL("sys_osem_wait timeout is not implemented!");
|
||||
if (need < 1 || need > sem->maxValue)
|
||||
return ErrorCode::INVAL;
|
||||
|
||||
std::lock_guard lock(sem->mtx);
|
||||
while (true) {
|
||||
if (sem->isDeleted)
|
||||
return ErrorCode::ACCES;
|
||||
if (sem->value >= need) {
|
||||
sem->value -= need;
|
||||
break;
|
||||
}
|
||||
sem->cond.wait(sem->mtx);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
orbis::SysResult orbis::sys_osem_trywait(Thread *thread /* TODO */) {
|
||||
return ErrorCode::NOSYS;
|
||||
orbis::SysResult orbis::sys_osem_trywait(Thread *thread, sint id, sint need) {
|
||||
ORBIS_LOG_NOTICE(__FUNCTION__, thread, id, need);
|
||||
Ref<Semaphore> sem = thread->tproc->semMap.get(id);
|
||||
if (need < 1 || need > sem->maxValue)
|
||||
return ErrorCode::INVAL;
|
||||
|
||||
std::lock_guard lock(sem->mtx);
|
||||
if (sem->isDeleted || sem->value < need)
|
||||
return ErrorCode::BUSY;
|
||||
sem->value -= need;
|
||||
return {};
|
||||
}
|
||||
orbis::SysResult orbis::sys_osem_post(Thread *thread /* TODO */) {
|
||||
return ErrorCode::NOSYS;
|
||||
orbis::SysResult orbis::sys_osem_post(Thread *thread, sint id, sint count) {
|
||||
ORBIS_LOG_NOTICE(__FUNCTION__, thread, id, count);
|
||||
Ref<Semaphore> sem = thread->tproc->semMap.get(id);
|
||||
if (count < 1 || count > sem->maxValue - sem->value)
|
||||
return ErrorCode::INVAL;
|
||||
|
||||
std::lock_guard lock(sem->mtx);
|
||||
if (sem->isDeleted)
|
||||
return {};
|
||||
sem->value += count;
|
||||
sem->cond.notify_all(sem->mtx);
|
||||
return {};
|
||||
}
|
||||
orbis::SysResult orbis::sys_osem_cancel(Thread *thread /* TODO */) {
|
||||
orbis::SysResult orbis::sys_osem_cancel(Thread *thread, sint id, sint set,
|
||||
ptr<uint> pNumWaitThreads) {
|
||||
ORBIS_LOG_TODO(__FUNCTION__, thread, id, set, pNumWaitThreads);
|
||||
return ErrorCode::NOSYS;
|
||||
}
|
||||
orbis::SysResult orbis::sys_namedobj_create(Thread *thread,
|
||||
|
|
|
|||
Loading…
Reference in a new issue