diff --git a/kernel/include/kernel/KernelObject.hpp b/kernel/include/kernel/KernelObject.hpp index d36814ec4..7947b0c2f 100644 --- a/kernel/include/kernel/KernelObject.hpp +++ b/kernel/include/kernel/KernelObject.hpp @@ -2,6 +2,7 @@ #include "rx/Rc.hpp" #include "rx/Serializer.hpp" +#include "rx/SharedMutex.hpp" #include "rx/TypeId.hpp" #include #include @@ -44,6 +45,28 @@ struct KernelObject : KernelObjectBase, StateT { } }; +template +struct LockableKernelObject : KernelObjectBase, StateT { + mutable rx::shared_mutex mtx; + + template + LockableKernelObject(Args &&...args) + : KernelObjectBase(rx::TypeId::get()), + StateT(std::forward(args)...) {} + + virtual void serialize(rx::Serializer &s) const { + std::lock_guard lock(*this); + s.serialize(static_cast(*this)); + } + + virtual void deserialize(rx::Deserializer &s) { + s.deserialize(static_cast(*this)); + } + + void lock() const { mtx.lock(); } + void unlock() const { mtx.unlock(); } +}; + namespace detail { struct StaticObjectCtl { std::size_t offset = -1ull; diff --git a/kernel/orbis/CMakeLists.txt b/kernel/orbis/CMakeLists.txt index a4c92210a..5f029144e 100644 --- a/kernel/orbis/CMakeLists.txt +++ b/kernel/orbis/CMakeLists.txt @@ -65,6 +65,9 @@ add_library(obj.orbis-kernel OBJECT src/sys/sys_vm_mmap.cpp src/sys/sys_vm_unix.cpp + src/thread/Process.cpp + src/thread/Thread.cpp + src/utils/Logs.cpp ) diff --git a/kernel/orbis/include/orbis/KernelContext.hpp b/kernel/orbis/include/orbis/KernelContext.hpp index ee4338992..23314d545 100644 --- a/kernel/orbis/include/orbis/KernelContext.hpp +++ b/kernel/orbis/include/orbis/KernelContext.hpp @@ -8,9 +8,7 @@ #include "orbis/note.hpp" #include "osem.hpp" #include "rx/IdMap.hpp" -#include "rx/LinkedNode.hpp" #include "rx/SharedMutex.hpp" -#include "thread/types.hpp" #include #include @@ -37,18 +35,6 @@ public: KernelContext(); ~KernelContext(); - Process *createProcess(pid_t pid); - void deleteProcess(Process *proc); - Process *findProcessById(pid_t pid) const; - Process *findProcessByHostId(std::uint64_t pid) const; - - rx::LinkedNode *getProcessList() { return m_processes; } - - long allocatePid() { - std::lock_guard lock(m_thread_id_mtx); - return m_thread_id_map.emplace(0).first; - } - long getTscFreq(); std::pair createEventFlag(kstring name, std::int32_t flags, @@ -123,17 +109,15 @@ public: return {}; } - std::tuple &, std::unique_lock> + std::tuple> &, std::unique_lock> getKernelEnv() { std::unique_lock lock(m_kenv_mtx); return {m_kenv, std::move(lock)}; } void setKernelEnv(std::string_view key, std::string_view value) { - auto &kenvValue = m_kenv[kstring(key)]; - auto len = std::min(sizeof(kenvValue) - 1, value.size()); - std::memcpy(kenvValue, value.data(), len); - kenvValue[len] = '0'; + std::unique_lock lock(m_kenv_mtx); + m_kenv[kstring(key)] = value; } rx::Ref deviceEventEmitter; @@ -177,11 +161,6 @@ public: private: std::atomic m_tsc_freq{0}; - rx::shared_mutex m_thread_id_mtx; - rx::OwningIdMap m_thread_id_map; - mutable rx::shared_mutex m_proc_mtx; - rx::LinkedNode *m_processes = nullptr; - rx::shared_mutex m_evf_mtx; kmap> m_event_flags; @@ -192,7 +171,7 @@ private: kmap> mIpmiServers; rx::shared_mutex m_kenv_mtx; - kmap m_kenv; // max size: 127 + '\0' + kmap> m_kenv; // max size: 127 + '\0' }; extern GlobalObjectRef g_context; diff --git a/kernel/orbis/include/orbis/KernelObject.hpp b/kernel/orbis/include/orbis/KernelObject.hpp index ba9cfbdce..151f654ea 100644 --- a/kernel/orbis/include/orbis/KernelObject.hpp +++ b/kernel/orbis/include/orbis/KernelObject.hpp @@ -15,6 +15,7 @@ public: explicit GlobalObjectRef(std::uint32_t offset) : mOffset(offset) {} T *get() { return reinterpret_cast(g_globalStorage + mOffset); } T *operator->() { return get(); } + T &operator*() { return *get(); } }; template diff --git a/kernel/orbis/include/orbis/thread/Process.hpp b/kernel/orbis/include/orbis/thread/Process.hpp index af30c9df2..245ddb7ae 100644 --- a/kernel/orbis/include/orbis/thread/Process.hpp +++ b/kernel/orbis/include/orbis/thread/Process.hpp @@ -59,6 +59,8 @@ struct Process final { kernel::StaticKernelObjectStorage; + ~Process(); + KernelContext *context = nullptr; std::byte *storage = nullptr; @@ -97,7 +99,7 @@ struct Process final { rx::RcIdMap evfMap; rx::RcIdMap semMap; rx::RcIdMap modulesMap; - rx::OwningIdMap threadsMap; + rx::RcIdMap threadsMap; rx::RcIdMap fileDescriptors; // Named objects for debugging @@ -115,18 +117,8 @@ struct Process final { void incRef() {} void decRef() {} - void allocate() { - if (auto size = Storage::GetSize()) { - storage = (std::byte *)kalloc(size, Storage::GetAlignment()); - } - } - - void deallocate() { - if (auto size = Storage::GetSize()) { - kfree(storage, size); - storage = nullptr; - } - } + void serialize(rx::Serializer &) const; + void deserialize(rx::Deserializer &); template T *get( @@ -135,4 +127,10 @@ struct Process final { return ref.get(storage); } }; + +pid_t allocatePid(); +Process *createProcess(Process *parentProcess = nullptr, pid_t pid = -1); +void deleteProcess(Process *proc); +Process *findProcessById(pid_t pid); +Process *findProcessByHostId(std::uint64_t pid); } // namespace orbis diff --git a/kernel/orbis/include/orbis/thread/Thread.hpp b/kernel/orbis/include/orbis/thread/Thread.hpp index 7f0d74071..e4ce01855 100644 --- a/kernel/orbis/include/orbis/thread/Thread.hpp +++ b/kernel/orbis/include/orbis/thread/Thread.hpp @@ -4,6 +4,7 @@ #include "cpuset.hpp" #include "orbis-config.hpp" #include "rx/Serializer.hpp" +#include "rx/StaticString.hpp" #include "types.hpp" #include "../KernelAllocator.hpp" @@ -23,6 +24,8 @@ struct Thread final { kernel::StaticKernelObjectStorage; + ~Thread(); + rx::shared_mutex mtx; Process *tproc = nullptr; std::byte *storage = nullptr; @@ -33,7 +36,7 @@ struct Thread final { ptr stackEnd; uint64_t fsBase{}; uint64_t gsBase{}; - char name[32]{}; + rx::StaticString<32> name; cpuset affinity{~0u}; SigSet sigMask = {0x7fff'ffff, ~0u, ~0u, ~0u}; @@ -82,19 +85,6 @@ struct Thread final { void notifyUnblockedSignal(int signo); void setSigMask(SigSet newSigMask); - void allocate() { - if (auto size = Storage::GetSize()) { - storage = (std::byte *)kalloc(size, Storage::GetAlignment()); - } - } - - void deallocate() { - if (auto size = Storage::GetSize()) { - kfree(storage, size); - storage = nullptr; - } - } - template T *get(kernel::StaticObjectRef ref) { @@ -106,6 +96,8 @@ struct Thread final { void decRef() {} }; +Thread *createThread(Process *process, std::string_view name); + extern thread_local Thread *g_currentThread; struct scoped_unblock { diff --git a/kernel/orbis/src/KernelContext.cpp b/kernel/orbis/src/KernelContext.cpp index 8e3ddd98b..78d47e814 100644 --- a/kernel/orbis/src/KernelContext.cpp +++ b/kernel/orbis/src/KernelContext.cpp @@ -24,71 +24,6 @@ KernelContext::KernelContext() { } KernelContext::~KernelContext() {} -Process *KernelContext::createProcess(pid_t pid) { - auto newProcess = knew>(); - newProcess->object.context = this; - newProcess->object.pid = pid; - newProcess->object.state = ProcessState::NEW; - - { - std::lock_guard lock(m_proc_mtx); - if (m_processes != nullptr) { - m_processes->insertPrev(*newProcess); - } - - m_processes = newProcess; - } - - return &newProcess->object; -} - -void KernelContext::deleteProcess(Process *proc) { - auto procNode = reinterpret_cast *>(proc); - - { - std::lock_guard lock(m_proc_mtx); - auto next = procNode->erase(); - - if (procNode == m_processes) { - m_processes = next; - } - } - - kdelete(procNode); -} - -Process *KernelContext::findProcessById(pid_t pid) const { - for (std::size_t i = 0; i < 20; ++i) { - { - std::lock_guard lock(m_proc_mtx); - for (auto proc = m_processes; proc != nullptr; proc = proc->next) { - if (proc->object.pid == pid) { - return &proc->object; - } - } - } - std::this_thread::sleep_for(std::chrono::microseconds(50)); - } - - return nullptr; -} - -Process *KernelContext::findProcessByHostId(std::uint64_t pid) const { - for (std::size_t i = 0; i < 20; ++i) { - { - std::lock_guard lock(m_proc_mtx); - for (auto proc = m_processes; proc != nullptr; proc = proc->next) { - if (proc->object.hostPid == pid) { - return &proc->object; - } - } - } - std::this_thread::sleep_for(std::chrono::microseconds(50)); - } - - return nullptr; -} - long KernelContext::getTscFreq() { auto cal_tsc = []() -> long { const long timer_freq = 1'000'000'000; diff --git a/kernel/orbis/src/pipe.cpp b/kernel/orbis/src/pipe.cpp index 6513b39a3..9509982fa 100644 --- a/kernel/orbis/src/pipe.cpp +++ b/kernel/orbis/src/pipe.cpp @@ -12,8 +12,8 @@ static orbis::ErrorCode pipe_read(orbis::File *file, orbis::Uio *uio, while (true) { if (pipe->data.empty()) { // pipe->cv.wait(file->mtx); - // ORBIS_LOG_ERROR(__FUNCTION__, "wakeup", thread->name, thread->tid, - // file); continue; + // ORBIS_LOG_ERROR(__FUNCTION__, "wakeup", thread->name.c_str(), + // thread->tid, file); continue; return orbis::ErrorCode::WOULDBLOCK; } @@ -32,8 +32,8 @@ static orbis::ErrorCode pipe_read(orbis::File *file, orbis::Uio *uio, uio->offset += size; std::memcpy(vec.base, pipe->data.data(), size); - ORBIS_LOG_ERROR(__FUNCTION__, thread->name, thread->tid, file, size, - pipe->data.size(), uio->offset, file->nextOff); + ORBIS_LOG_ERROR(__FUNCTION__, thread->name.c_str(), thread->tid, file, + size, pipe->data.size(), uio->offset, file->nextOff); if (pipe->data.size() == size) { pipe->data.clear(); @@ -55,7 +55,7 @@ static orbis::ErrorCode pipe_read(orbis::File *file, orbis::Uio *uio, static orbis::ErrorCode pipe_write(orbis::File *file, orbis::Uio *uio, orbis::Thread *thread) { auto pipe = static_cast(file)->other; - ORBIS_LOG_ERROR(__FUNCTION__, thread->name, thread->tid, file); + ORBIS_LOG_ERROR(__FUNCTION__, thread->name.c_str(), thread->tid, file); std::size_t cnt = 0; for (auto vec : std::span(uio->iov, uio->iovcnt)) { @@ -70,8 +70,8 @@ static orbis::ErrorCode pipe_write(orbis::File *file, orbis::Uio *uio, uio->resid -= cnt; uio->offset += cnt; - ORBIS_LOG_ERROR(__FUNCTION__, thread->name, thread->tid, file, uio->resid, - uio->offset, file->nextOff, cnt); + ORBIS_LOG_ERROR(__FUNCTION__, thread->name.c_str(), thread->tid, file, + uio->resid, uio->offset, file->nextOff, cnt); thread->where(); return {}; } diff --git a/kernel/orbis/src/sys/sys_cpuset.cpp b/kernel/orbis/src/sys/sys_cpuset.cpp index 12163a6ba..ed0168ba3 100644 --- a/kernel/orbis/src/sys/sys_cpuset.cpp +++ b/kernel/orbis/src/sys/sys_cpuset.cpp @@ -78,7 +78,7 @@ orbis::SysResult orbis::sys_cpuset_getaffinity(Thread *thread, cpulevel_t level, case CpuLevel::Which: switch (CpuWhich(which)) { case CpuWhich::Tid: { - Thread *whichThread = nullptr; + rx::Ref whichThread = nullptr; if (id == ~id_t(0) || thread->tid == id) { whichThread = thread; } else { @@ -97,7 +97,7 @@ orbis::SysResult orbis::sys_cpuset_getaffinity(Thread *thread, cpulevel_t level, if (id == ~id_t(0) || id == thread->tproc->pid) { whichProcess = thread->tproc; } else { - whichProcess = g_context->findProcessById(id); + whichProcess = findProcessById(id); if (whichProcess == nullptr) { return ErrorCode::SRCH; @@ -132,7 +132,7 @@ orbis::SysResult orbis::sys_cpuset_setaffinity(Thread *thread, cpulevel_t level, case CpuLevel::Which: switch (CpuWhich(which)) { case CpuWhich::Tid: { - Thread *whichThread = nullptr; + rx::Ref whichThread = nullptr; if (id == ~id_t(0) || thread->tid == id) { whichThread = thread; } else { @@ -163,7 +163,7 @@ orbis::SysResult orbis::sys_cpuset_setaffinity(Thread *thread, cpulevel_t level, } else { ORBIS_LOG_ERROR(__FUNCTION__, "process not found", level, which, id, cpusetsize); - whichProcess = g_context->findProcessById(id); + whichProcess = findProcessById(id); if (whichProcess == nullptr) { return ErrorCode::SRCH; diff --git a/kernel/orbis/src/sys/sys_environment.cpp b/kernel/orbis/src/sys/sys_environment.cpp index 50f247f76..e0ebbda37 100644 --- a/kernel/orbis/src/sys/sys_environment.cpp +++ b/kernel/orbis/src/sys/sys_environment.cpp @@ -18,7 +18,7 @@ orbis::SysResult orbis::sys_kenv(Thread *thread, sint what, size_t entry = 0; // Entry: size of both full buffers, the '=' and the '\0' at the end if (value == nullptr || len == 0) { - entry = key.size() + 1 + strnlen(env_value, 128) + 1; + entry = key.size() + 1 + env_value.size() + 1; } else { char buf[128 * 2 + 2]; @@ -28,9 +28,8 @@ orbis::SysResult orbis::sys_kenv(Thread *thread, sint what, *_buf++ = '='; - const size_t value_size = strnlen(env_value, 128); - std::strncpy(_buf, env_value, value_size); - _buf += value_size; + std::strncpy(_buf, env_value.data(), env_value.size()); + _buf += env_value.size(); *_buf++ = '\0'; @@ -58,16 +57,16 @@ orbis::SysResult orbis::sys_kenv(Thread *thread, sint what, if (it == kenv.end()) { return ErrorCode::NOENT; } - const char *buf = it->second; - ORBIS_RET_ON_ERROR(uwriteRaw(value, buf, std::min(len, 128))); + ORBIS_RET_ON_ERROR(uwriteRaw(value, it->second.data(), it->second.size())); break; } case kenv_set: { if (len < 1) { return ErrorCode::INVAL; } - char *_value_buf = kenv[kstring(_name)]; - ORBIS_RET_ON_ERROR(ureadString(_value_buf, 128, value)); + auto &_value_buf = kenv[kstring(_name)]; + ORBIS_RET_ON_ERROR( + ureadString(_value_buf.data(), _value_buf.max_size() + 1, value)); break; } case kenv_unset: { diff --git a/kernel/orbis/src/sys/sys_event.cpp b/kernel/orbis/src/sys/sys_event.cpp index 950c89765..01828e146 100644 --- a/kernel/orbis/src/sys/sys_event.cpp +++ b/kernel/orbis/src/sys/sys_event.cpp @@ -89,7 +89,7 @@ static SysResult keventChange(KQueue *kq, KEvent &change, Thread *thread) { nodeIt = kq->notes.begin(); if (change.filter == kEvFiltProc) { - auto process = g_context->findProcessById(change.ident); + auto process = findProcessById(change.ident); if (process == nullptr) { return ErrorCode::SRCH; } diff --git a/kernel/orbis/src/sys/sys_exit.cpp b/kernel/orbis/src/sys/sys_exit.cpp index a6bfd27c4..f8f7cdb66 100644 --- a/kernel/orbis/src/sys/sys_exit.cpp +++ b/kernel/orbis/src/sys/sys_exit.cpp @@ -25,7 +25,7 @@ orbis::SysResult orbis::sys_wait4(Thread *thread, sint pid, ptr status, int hostPid = pid; if (pid > 0) { - auto process = g_context->findProcessById(pid); + auto process = findProcessById(pid); if (process == nullptr) { return ErrorCode::SRCH; } @@ -42,7 +42,7 @@ orbis::SysResult orbis::sys_wait4(Thread *thread, sint pid, ptr status, ORBIS_LOG_ERROR(__FUNCTION__, pid, status, options, rusage, result, stat); - auto process = g_context->findProcessByHostId(result); + auto process = findProcessByHostId(result); if (process == nullptr) { ORBIS_LOG_ERROR("host process not found", result); continue; diff --git a/kernel/orbis/src/sys/sys_resource.cpp b/kernel/orbis/src/sys/sys_resource.cpp index 22327f42c..dcef27342 100644 --- a/kernel/orbis/src/sys/sys_resource.cpp +++ b/kernel/orbis/src/sys/sys_resource.cpp @@ -24,7 +24,7 @@ orbis::SysResult orbis::sys_rtprio_thread(Thread *thread, sint function, ORBIS_LOG_ERROR(__FUNCTION__, function, lwpid, rtp->prio, rtp->type); thread->where(); - Thread *targetThread; + rx::Ref targetThread; if (lwpid == thread->tid || lwpid == -1) { targetThread = thread; } else { diff --git a/kernel/orbis/src/sys/sys_sce.cpp b/kernel/orbis/src/sys/sys_sce.cpp index a5cba82cc..ba22f9aef 100644 --- a/kernel/orbis/src/sys/sys_sce.cpp +++ b/kernel/orbis/src/sys/sys_sce.cpp @@ -940,7 +940,7 @@ orbis::SysResult orbis::sys_dmem_container(Thread *thread, uint id) { orbis::SysResult orbis::sys_get_authinfo(Thread *thread, pid_t pid, ptr info) { - auto process = pid > 0 ? g_context->findProcessById(pid) : thread->tproc; + auto process = pid > 0 ? findProcessById(pid) : thread->tproc; if (process == nullptr) { return ErrorCode::SRCH; } @@ -1188,21 +1188,20 @@ orbis::SysResult orbis::sys_randomized_path(Thread *thread, sint type, } orbis::SysResult orbis::sys_rdup(Thread *thread, sint pid, sint fd) { ORBIS_LOG_TODO(__FUNCTION__, pid, fd); - for (auto it = g_context->getProcessList(); it != nullptr; it = it->next) { - auto &p = it->object; - if (p.pid != pid) { - continue; - } + auto process = pid == -1 || pid == thread->tproc->pid ? thread->tproc + : findProcessById(pid); - auto file = p.fileDescriptors.get(fd); - if (file == nullptr) { - return ErrorCode::BADF; - } - - thread->retval[0] = thread->tproc->fileDescriptors.insert(std::move(file)); - return {}; + if (!process) { + return ErrorCode::SRCH; } - return ErrorCode::SRCH; + + auto file = process->fileDescriptors.get(fd); + if (file == nullptr) { + return ErrorCode::BADF; + } + + thread->retval[0] = thread->tproc->fileDescriptors.insert(std::move(file)); + return {}; } orbis::SysResult orbis::sys_dl_get_metadata(Thread *thread /* TODO */) { return ErrorCode::NOSYS; @@ -1297,7 +1296,7 @@ orbis::SysResult orbis::sys_budget_get_ptype(Thread *thread, sint pid) { if (pid < 0 || pid == thread->tproc->pid) { process = thread->tproc; } else { - process = g_context->findProcessById(pid); + process = findProcessById(pid); if (!process) { return ErrorCode::SRCH; @@ -1337,14 +1336,14 @@ orbis::SysResult orbis::sys_get_resident_fmem_count(Thread *thread, pid_t pid) { } orbis::SysResult orbis::sys_thr_get_name(Thread *thread, lwpid_t lwpid, char *buf, size_t buflen) { - Thread *searchThread; + rx::Ref searchThread; if (thread->tid == lwpid || lwpid == -1) { searchThread = thread; } else { searchThread = thread->tproc->threadsMap.get(lwpid - thread->tproc->pid); if (searchThread == nullptr) { - if (auto process = g_context->findProcessById(lwpid)) { + if (auto process = findProcessById(lwpid)) { searchThread = process->threadsMap.get(lwpid - process->pid); } } @@ -1354,11 +1353,11 @@ orbis::SysResult orbis::sys_thr_get_name(Thread *thread, lwpid_t lwpid, } } - auto namelen = std::strlen(searchThread->name); + auto namelen = searchThread->name.length(); auto writeLen = std::min(namelen + 1, buflen); if (writeLen > 0) { - ORBIS_RET_ON_ERROR(uwriteRaw(buf, searchThread->name, writeLen - 1)); + ORBIS_RET_ON_ERROR(uwriteRaw(buf, searchThread->name.data(), writeLen - 1)); buf[writeLen] = 0; } diff --git a/kernel/orbis/src/sys/sys_sig.cpp b/kernel/orbis/src/sys/sys_sig.cpp index 13fcd2a0d..82147a175 100644 --- a/kernel/orbis/src/sys/sys_sig.cpp +++ b/kernel/orbis/src/sys/sys_sig.cpp @@ -114,7 +114,7 @@ orbis::SysResult orbis::sys_kill(Thread *thread, sint pid, sint signum) { int hostPid = pid; if (pid > 0) { - auto process = g_context->findProcessById(pid); + auto process = findProcessById(pid); if (process == nullptr) { return ErrorCode::SRCH; } diff --git a/kernel/orbis/src/sys/sys_sysctl.cpp b/kernel/orbis/src/sys/sys_sysctl.cpp index 1f09f0103..5015f136c 100644 --- a/kernel/orbis/src/sys/sys_sysctl.cpp +++ b/kernel/orbis/src/sys/sys_sysctl.cpp @@ -225,7 +225,7 @@ SysResult kern_sysctl(Thread *thread, ptr name, uint namelen, ORBIS_LOG_ERROR("KERN_PROC_PROC 2"); if (namelen >= 4) { - auto process = g_context->findProcessById(name[3]); + auto process = findProcessById(name[3]); if (process == nullptr || process->exitStatus.has_value()) { return ErrorCode::SRCH; } @@ -259,7 +259,7 @@ SysResult kern_sysctl(Thread *thread, ptr name, uint namelen, if (name[0] == kern && name[1] == proc && name[2] == 36) { Process *process = thread->tproc; if (process->pid != name[3]) { - process = g_context->findProcessById(name[3]); + process = findProcessById(name[3]); if (process == nullptr) { ORBIS_LOG_ERROR("get sdk version by pid: process not found", name[3], thread->tproc->pid); @@ -290,7 +290,7 @@ SysResult kern_sysctl(Thread *thread, ptr name, uint namelen, // 1 - 14 - 35 - pid Process *process = thread->tproc; if (process->pid != name[3] && name[3] != -1) { - process = g_context->findProcessById(name[3]); + process = findProcessById(name[3]); if (process == nullptr) { ORBIS_LOG_ERROR("appinfo process not found", name[3], thread->tproc->pid); @@ -461,7 +461,7 @@ SysResult kern_sysctl(Thread *thread, ptr name, uint namelen, if (name[0] == kern && name[1] == proc && name[2] == 68) { Process *process = thread->tproc; if (process->pid != name[3]) { - process = g_context->findProcessById(name[3]); + process = findProcessById(name[3]); if (process == nullptr) { ORBIS_LOG_ERROR("get ps5 sdk version by pid: process not found", name[3], thread->tproc->pid); diff --git a/kernel/orbis/src/thread/Process.cpp b/kernel/orbis/src/thread/Process.cpp new file mode 100644 index 000000000..5d6cbc605 --- /dev/null +++ b/kernel/orbis/src/thread/Process.cpp @@ -0,0 +1,179 @@ +#include "thread/Process.hpp" +#include "KernelAllocator.hpp" +#include "KernelContext.hpp" +#include "KernelObject.hpp" +#include "kernel/KernelObject.hpp" +#include "rx/LinkedNode.hpp" +#include "rx/Serializer.hpp" +#include "rx/align.hpp" +#include "thread/Thread.hpp" +#include + +struct ProcessIdList { + rx::OwningIdMap pidMap; + + void serialize(rx::Serializer &s) const { + pidMap.walk([&s](std::uint8_t id, orbis::pid_t value) { + s.serialize(id); + s.serialize(value); + }); + + s.serialize(-1); + } + + void deserialize(rx::Deserializer &s) { + while (true) { + auto id = s.deserialize(); + if (id == static_cast(-1)) { + break; + } + + auto value = s.deserialize(); + + if (s.failure()) { + break; + } + + if (!pidMap.emplace_at(id, value)) { + s.setFailure(); + return; + } + } + } +}; + +static auto g_processIdList = + orbis::createGlobalObject>(); + +orbis::pid_t orbis::allocatePid() { + std::lock_guard lock(*g_processIdList); + return g_processIdList->pidMap.emplace(0).first * 10000 + 1; +} + +struct ProcessList { + rx::LinkedNode *list = nullptr; + + void serialize(rx::Serializer &s) const { + for (auto proc = list; proc != nullptr; proc = proc->next) { + s.serialize(proc->object.pid); + s.serialize(proc->object); + } + + s.serialize(-1); + } + + void deserialize(rx::Deserializer &s) { + while (true) { + auto pid = s.deserialize(); + if (pid == static_cast(-1) || s.failure()) { + break; + } + + auto process = orbis::createProcess(nullptr, pid); + s.deserialize(*process); + + if (s.failure()) { + break; + } + } + } +}; + +static auto g_processList = + orbis::createGlobalObject>(); + +void orbis::deleteProcess(orbis::Process *proc) { + auto procNode = reinterpret_cast *>(proc); + + { + std::lock_guard lock(*g_processList); + auto next = procNode->erase(); + + if (procNode == g_processList->list) { + g_processList->list = next; + } + } + + kdelete(procNode); +} + +orbis::Process *orbis::findProcessById(pid_t pid) { + for (std::size_t i = 0; i < 20; ++i) { + { + std::lock_guard lock(*g_processList); + for (auto proc = g_processList->list; proc != nullptr; + proc = proc->next) { + if (proc->object.pid == pid) { + return &proc->object; + } + } + } + std::this_thread::sleep_for(std::chrono::microseconds(50)); + } + + return nullptr; +} + +orbis::Process *orbis::findProcessByHostId(std::uint64_t pid) { + for (std::size_t i = 0; i < 20; ++i) { + { + std::lock_guard lock(*g_processList); + for (auto proc = g_processList->list; proc != nullptr; + proc = proc->next) { + if (proc->object.hostPid == pid) { + return &proc->object; + } + } + } + + std::this_thread::sleep_for(std::chrono::microseconds(50)); + } + + return nullptr; +} + +void orbis::Process::serialize(rx::Serializer &s) const { + Process::Storage::SerializeAll(storage, s); +} +void orbis::Process::deserialize(rx::Deserializer &s) { + Process::Storage::DeserializeAll(storage, s); +} + +orbis::Process::~Process() { + Process::Storage::DestructAll(storage); + + auto size = sizeof(Process); + size = rx::alignUp(size, Process::Storage::GetAlignment()); + size += Process::Storage::GetSize(); + + kfree(this, size); +} + +orbis::Process *orbis::createProcess(Process *parentProcess, pid_t pid) { + if (pid == static_cast(-1)) { + pid = allocatePid(); + } + + auto size = sizeof(rx::LinkedNode); + size = rx::alignUp(size, Process::Storage::GetAlignment()); + auto storageOffset = size; + size += Process::Storage::GetSize(); + + auto memory = (std::byte *)kalloc( + size, std::max(alignof(rx::LinkedNode), + Process::Storage::GetAlignment())); + + auto result = new (memory) rx::LinkedNode(); + result->object.context = g_context.get(); + result->object.storage = memory + storageOffset; + result->object.parentProcess = parentProcess; + result->object.pid = pid; + Process::Storage::ConstructAll(result->object.storage); + + std::lock_guard lock(*g_processList); + if (auto list = g_processList->list) { + list->insertPrev(*result); + } + g_processList->list = result; + return &result->object; +} diff --git a/kernel/orbis/src/thread/Thread.cpp b/kernel/orbis/src/thread/Thread.cpp new file mode 100644 index 000000000..579a2cd47 --- /dev/null +++ b/kernel/orbis/src/thread/Thread.cpp @@ -0,0 +1,38 @@ +#include "thread/Thread.hpp" +#include "thread/Process.hpp" + +orbis::Thread::~Thread() { + Thread::Storage::DestructAll(storage); + + auto size = sizeof(Thread); + size = rx::alignUp(size, Thread::Storage::GetAlignment()); + size += Thread::Storage::GetSize(); + + kfree(this, size); +} + +orbis::Thread *orbis::createThread(Process *process, std::string_view name) { + auto size = sizeof(Thread); + size = rx::alignUp(size, Thread::Storage::GetAlignment()); + auto storageOffset = size; + size += Thread::Storage::GetSize(); + + auto memory = (std::byte *)kalloc( + size, + std::max(alignof(Thread), Thread::Storage::GetAlignment())); + + auto result = new (memory) Thread(); + result->storage = memory + storageOffset; + result->tproc = process; + result->name = name; + + Thread::Storage::ConstructAll(result->storage); + + std::lock_guard lock(process->mtx); + auto baseId = process->threadsMap.insert(result); + result->tproc = process; + result->tid = process->pid + baseId; + result->state = orbis::ThreadState::RUNNING; + + return result; +} diff --git a/rpcsx/ipmi.cpp b/rpcsx/ipmi.cpp index 44bb64af9..79887e3bf 100644 --- a/rpcsx/ipmi.cpp +++ b/rpcsx/ipmi.cpp @@ -4,6 +4,7 @@ #include "io-device.hpp" #include "orbis/KernelContext.hpp" #include "orbis/osem.hpp" +#include "orbis/thread/Process.hpp" #include "orbis/utils/Logs.hpp" #include "rx/format.hpp" #include "rx/hexdump.hpp" @@ -357,7 +358,7 @@ ipmi::IpmiServer &ipmi::createIpmiServer(orbis::Process *process, if ((packet.info.type & ~0x8010) == 0x41) { auto msgHeader = std::bit_cast( packet.message.data()); - auto process = orbis::g_context->findProcessById(msgHeader->pid); + auto process = orbis::findProcessById(msgHeader->pid); if (process == nullptr) { continue; } @@ -378,7 +379,7 @@ ipmi::IpmiServer &ipmi::createIpmiServer(orbis::Process *process, if ((packet.info.type & ~0x10) == 0x43) { auto msgHeader = (orbis::IpmiAsyncMessageHeader *)packet.message.data(); - auto process = orbis::g_context->findProcessById(msgHeader->pid); + auto process = orbis::findProcessById(msgHeader->pid); if (process == nullptr) { continue; } diff --git a/rpcsx/main.cpp b/rpcsx/main.cpp index 1af8a7249..5152ae61d 100644 --- a/rpcsx/main.cpp +++ b/rpcsx/main.cpp @@ -534,20 +534,6 @@ static void guestInitFd(orbis::Thread *mainThread) { mainThread->tproc->fileDescriptors.insert(stderrFile); } -static orbis::Process *createGuestProcess() { - auto pid = orbis::g_context->allocatePid() * 10000 + 1; - return orbis::g_context->createProcess(pid); -} - -static orbis::Thread *createGuestThread() { - auto process = createGuestProcess(); - auto [baseId, thread] = process->threadsMap.emplace(); - thread->tproc = process; - thread->tid = process->pid + baseId; - thread->state = orbis::ThreadState::RUNNING; - return thread; -} - struct ExecEnv { std::uint64_t entryPoint; std::uint64_t interpBase; @@ -789,7 +775,7 @@ static orbis::SysResult launchDaemon(orbis::Thread *thread, std::string path, std::vector argv, std::vector envv, orbis::AppInfoEx appInfo) { - auto childPid = orbis::g_context->allocatePid() * 10000 + 1; + auto childPid = orbis::allocatePid(); auto flag = orbis::knew>(); *flag = false; @@ -805,7 +791,7 @@ static orbis::SysResult launchDaemon(orbis::Thread *thread, std::string path, return {}; } - auto process = orbis::g_context->createProcess(childPid); + auto process = orbis::createProcess(thread->tproc, childPid); auto logFd = ::open(("log-" + std::to_string(childPid) + ".txt").c_str(), O_CREAT | O_TRUNC | O_WRONLY, 0666); @@ -817,7 +803,6 @@ static orbis::SysResult launchDaemon(orbis::Thread *thread, std::string path, process->onSysEnter = thread->tproc->onSysEnter; process->onSysExit = thread->tproc->onSysExit; process->ops = thread->tproc->ops; - process->parentProcess = thread->tproc; process->appInfo = appInfo; process->authInfo = { @@ -845,10 +830,9 @@ static orbis::SysResult launchDaemon(orbis::Thread *thread, std::string path, *flag = true; - auto [baseId, newThread] = process->threadsMap.emplace(); - newThread->tproc = process; - newThread->tid = process->pid + baseId; - newThread->state = orbis::ThreadState::RUNNING; + auto newThread = orbis::createThread(process, path); + newThread->hostTid = ::gettid(); + newThread->nativeHandle = pthread_self(); newThread->context = thread->context; newThread->fsBase = thread->fsBase; @@ -1060,8 +1044,8 @@ int main(int argc, const char *argv[]) { rx::thread::initialize(); // vm::printHostStats(); - orbis::g_context->allocatePid(); - auto initProcess = orbis::g_context->createProcess(asRoot ? 1 : 10); + orbis::allocatePid(); + auto initProcess = orbis::createProcess(nullptr, asRoot ? 1 : 10); // pthread_setname_np(pthread_self(), "10.MAINTHREAD"); int status = 0; @@ -1216,10 +1200,9 @@ int main(int argc, const char *argv[]) { initProcess->isInSandbox = true; } - auto [baseId, mainThread] = initProcess->threadsMap.emplace(); - mainThread->tproc = initProcess; - mainThread->tid = initProcess->pid + baseId; - mainThread->state = orbis::ThreadState::RUNNING; + auto mainThread = orbis::createThread(initProcess, ""); + mainThread->hostTid = ::gettid(); + mainThread->nativeHandle = pthread_self(); orbis::g_currentThread = mainThread; if (!isSystem && !vfs::exists(guestArgv[0], mainThread) && @@ -1345,7 +1328,8 @@ int main(int argc, const char *argv[]) { // version if (orbis::g_context->fwType != orbis::FwType::Ps5 && orbis::g_context->fwSdkVersion >= 0x5050000) { - auto fakeIpmiThread = createGuestThread(); + auto fakeIpmiThread = + orbis::createThread(initProcess, "SceSysAudioSystemIpc"); ipmi::audioIpmiClient = ipmi::createIpmiClient(fakeIpmiThread, "SceSysAudioSystemIpc"); // HACK: here is a bug in audiod because we send this very early and diff --git a/rpcsx/ops.cpp b/rpcsx/ops.cpp index 48caa7d7f..29b29c965 100644 --- a/rpcsx/ops.cpp +++ b/rpcsx/ops.cpp @@ -537,13 +537,14 @@ SysResult thr_new(orbis::Thread *thread, orbis::ptr param, return result; } - auto proc = thread->tproc; - std::lock_guard lock(proc->mtx); - auto [baseId, childThread] = proc->threadsMap.emplace(); - std::lock_guard lockThr(childThread->mtx); - childThread->tproc = proc; - childThread->tid = proc->pid + baseId; - childThread->state = orbis::ThreadState::RUNQ; + char _name[32]{}; + if (_param.name != 0) { + ORBIS_RET_ON_ERROR(ureadString(_name, sizeof(_name), _param.name)); + } + + auto childThread = orbis::createThread(thread->tproc, _name); + + std::lock_guard lock(childThread->mtx); childThread->stackStart = _param.stack_base; childThread->stackEnd = _param.stack_base + _param.stack_size; childThread->fsBase = reinterpret_cast(_param.tls_base); @@ -560,11 +561,6 @@ SysResult thr_new(orbis::Thread *thread, orbis::ptr param, childThread->stackStart, _param.rtp, _param.name, _param.spare[0], _param.spare[1]); - if (_param.name != 0) { - ORBIS_RET_ON_ERROR( - ureadString(childThread->name, sizeof(childThread->name), _param.name)); - } - if (_param.rtp != 0) { rtprio _rtp; ORBIS_RET_ON_ERROR(uread(_rtp, _param.rtp)); @@ -760,7 +756,7 @@ SysResult processNeeded(Thread *thread) { } SysResult fork(Thread *thread, slong flags) { - auto childPid = g_context->allocatePid() * 10000 + 1; + auto childPid = orbis::allocatePid(); ORBIS_LOG_TODO(__FUNCTION__, flags, childPid, thread->tid); thread->where(); auto flag = knew>(); @@ -783,13 +779,12 @@ SysResult fork(Thread *thread, slong flags) { return {}; } - auto process = g_context->createProcess(childPid); + auto process = orbis::createProcess(thread->tproc, childPid); process->hostPid = ::getpid(); process->sysent = thread->tproc->sysent; process->onSysEnter = thread->tproc->onSysEnter; process->onSysExit = thread->tproc->onSysExit; process->ops = thread->tproc->ops; - process->parentProcess = thread->tproc; process->authInfo = thread->tproc->authInfo; process->sdkVersion = thread->tproc->sdkVersion; process->type = thread->tproc->type; @@ -813,11 +808,8 @@ SysResult fork(Thread *thread, slong flags) { *flag = true; - auto [baseId, newThread] = process->threadsMap.emplace(); - newThread->tproc = process; + auto newThread = orbis::createThread(process, thread->name); newThread->hostTid = ::gettid(); - newThread->tid = process->pid + baseId; - newThread->state = orbis::ThreadState::RUNNING; newThread->context = thread->context; newThread->fsBase = thread->fsBase; diff --git a/rx/include/rx/IdMap.hpp b/rx/include/rx/IdMap.hpp index 3797efda4..57357549a 100644 --- a/rx/include/rx/IdMap.hpp +++ b/rx/include/rx/IdMap.hpp @@ -3,6 +3,7 @@ #include "BitSet.hpp" #include "Rc.hpp" #include "SharedMutex.hpp" +#include "FunctionRef.hpp" #include #include @@ -324,10 +325,24 @@ struct OwningIdMap { std::construct_at(get(index), std::forward(args)...)}; } + template + T *emplace_new_at(std::size_t index, ArgsT &&...args) { + if (mask.test(index)) { + return {}; + } + + mask.set(index); + return std::construct_at(get(index), std::forward(args)...); + } + T *get(std::size_t index) { return reinterpret_cast(objects + sizeof(T) * index); } + const T *get(std::size_t index) const { + return reinterpret_cast(objects + sizeof(T) * index); + } + void destroy(std::size_t index) { std::destroy_at(get(index)); mask.clear(index); @@ -337,6 +352,25 @@ struct OwningIdMap { IdMapChunk chunks[ChunkCount]{}; BitSet fullChunks; + template + requires(std::is_constructible_v) + T *emplace_at(IdT id, ArgsT &&...args) { + auto page = static_cast(id) / ChunkSize; + if (page >= ChunkCount) { + return {}; + } + + auto newElem = + chunks[page].emplace_new_at(static_cast(id) % ChunkSize, + std::forward(args)...); + + if (chunks[page].mask.full()) { + fullChunks.set(page); + } + + return newElem; + } + template requires(std::is_constructible_v) std::pair emplace(ArgsT &&...args) { @@ -390,13 +424,13 @@ struct OwningIdMap { return true; } - void walk(auto cb) { + void walk(FunctionRef cb) const { for (std::size_t chunk = 0; chunk < ChunkCount; ++chunk) { std::size_t index = chunks[chunk].mask.countr_zero(); while (index < ChunkSize) { auto id = static_cast(index + chunk * ChunkSize + MinId); - cb(id, chunks[chunk].get(id)); + cb(id, *chunks[chunk].get(id)); index = chunks[chunk].mask.countr_zero(index + 1); }