diff --git a/Core/HLE/sceKernel.h b/Core/HLE/sceKernel.h index 1d12a9dee2..0898c6cbca 100644 --- a/Core/HLE/sceKernel.h +++ b/Core/HLE/sceKernel.h @@ -225,6 +225,20 @@ public: } } + // Like Iterate(), but every live object regardless of type - only the base KernelObject + // interface (GetUID/GetTypeName/GetName/GetQuickInfo/...) is available on each. Used for a + // coarse "what's alive right now" overview across every kernel object kind at once, e.g. the + // WebSocket debugger's hle.object.list. + template + void IterateAll(F func) { + for (int i = 0; i < maxCount; i++) { + if (!occupied[i]) + continue; + if (!func(i + handleOffset, pool[i])) + break; + } + } + int ListIDType(int type, SceUID_le *uids, int count) const { int total = 0; for (int i = 0; i < maxCount; i++) { diff --git a/Core/HLE/sceKernelEventFlag.cpp b/Core/HLE/sceKernelEventFlag.cpp index a3a6dee106..be9fa2540e 100644 --- a/Core/HLE/sceKernelEventFlag.cpp +++ b/Core/HLE/sceKernelEventFlag.cpp @@ -32,61 +32,18 @@ void __KernelEventFlagTimeout(u64 userdata, int cycleslate); -struct NativeEventFlag { - u32_le size; - char name[KERNELOBJECT_MAX_NAME_LENGTH + 1]; - u32_le attr; - u32_le initPattern; - u32_le currentPattern; - s32_le numWaitThreads; -}; +// NativeEventFlag/EventFlagTh/EventFlag itself now live in sceKernelEventFlag.h - see the +// comment on the class there for why. +void EventFlag::DoState(PointerWrap &p) { + auto s = p.Section("EventFlag", 1); + if (!s) + return; -struct EventFlagTh { - SceUID threadID; - u32 bits; - u32 wait; - u32 outAddr; - u64 pausedTimeout; - - bool operator ==(const SceUID &otherThreadID) const { - return threadID == otherThreadID; - } -}; - -class EventFlag : public KernelObject { -public: - const char *GetName() override { return nef.name; } - const char *GetTypeName() override { return GetStaticTypeName(); } - static const char *GetStaticTypeName() { return "EventFlag"; } - void GetQuickInfo(char *ptr, int size) override { - snprintf(ptr, size, "init=%08x cur=%08x numwait=%i", - nef.initPattern, - nef.currentPattern, - nef.numWaitThreads); - } - - static u32 GetMissingErrorCode() { - return SCE_KERNEL_ERROR_UNKNOWN_EVFID; - } - static int GetStaticIDType() { return SCE_KERNEL_TMID_EventFlag; } - int GetIDType() const override { return SCE_KERNEL_TMID_EventFlag; } - - void DoState(PointerWrap &p) override { - auto s = p.Section("EventFlag", 1); - if (!s) - return; - - Do(p, nef); - EventFlagTh eft = { 0 }; - Do(p, waitingThreads, eft); - Do(p, pausedWaits); - } - - NativeEventFlag nef; - std::vector waitingThreads; - // Key is the callback id it was for, or if no callback, the thread id. - std::map pausedWaits; -}; + Do(p, nef); + EventFlagTh eft = { 0 }; + Do(p, waitingThreads, eft); + Do(p, pausedWaits); +} /** Event flag creation attributes */ diff --git a/Core/HLE/sceKernelEventFlag.h b/Core/HLE/sceKernelEventFlag.h index 776f8dc0c5..b6d8446cce 100644 --- a/Core/HLE/sceKernelEventFlag.h +++ b/Core/HLE/sceKernelEventFlag.h @@ -17,6 +17,67 @@ #pragma once +#include +#include +#include + +#include "Core/HLE/sceKernel.h" +#include "Core/HLE/ErrorCodes.h" + +class PointerWrap; + +struct NativeEventFlag { + u32_le size; + char name[KERNELOBJECT_MAX_NAME_LENGTH + 1]; + u32_le attr; + u32_le initPattern; + u32_le currentPattern; + s32_le numWaitThreads; +}; + +struct EventFlagTh { + SceUID threadID; + u32 bits; + u32 wait; + u32 outAddr; + u64 pausedTimeout; + + bool operator ==(const SceUID &otherThreadID) const { + return threadID == otherThreadID; + } +}; + +// Exposed here (rather than kept private to sceKernelEventFlag.cpp) so the WebSocket debugger +// can read a live object's state directly via kernelObjects.Get()/Iterate() +// - see HLEKernelObjectSubscriber.cpp. That's a read-only use: nothing outside this file should +// call DoState() or otherwise mutate an EventFlag - it's public here for this file's own use as +// before, not an invitation to write to it from elsewhere. +class EventFlag : public KernelObject { +public: + const char *GetName() override { return nef.name; } + const char *GetTypeName() override { return GetStaticTypeName(); } + static const char *GetStaticTypeName() { return "EventFlag"; } + void GetQuickInfo(char *ptr, int size) override { + snprintf(ptr, size, "init=%08x cur=%08x numwait=%i", + nef.initPattern, + nef.currentPattern, + nef.numWaitThreads); + } + + static u32 GetMissingErrorCode() { + return SCE_KERNEL_ERROR_UNKNOWN_EVFID; + } + static int GetStaticIDType() { return SCE_KERNEL_TMID_EventFlag; } + int GetIDType() const override { return SCE_KERNEL_TMID_EventFlag; } + + void DoState(PointerWrap &p) override; + + NativeEventFlag nef; + std::vector waitingThreads; + // Key is the callback id it was for, or if no callback, the thread id. + std::map pausedWaits; +}; + int sceKernelCreateEventFlag(const char *name, u32 flag_attr, u32 flag_initPattern, u32 optPtr); u32 sceKernelClearEventFlag(SceUID id, u32 bits); u32 sceKernelDeleteEventFlag(SceUID uid); diff --git a/Core/HLE/sceKernelMsgPipe.cpp b/Core/HLE/sceKernelMsgPipe.cpp index e2d7e1cf50..3662e22efa 100644 --- a/Core/HLE/sceKernelMsgPipe.cpp +++ b/Core/HLE/sceKernelMsgPipe.cpp @@ -48,261 +48,216 @@ static const u32 MSGPIPE_WAIT_VALUE_RECV = 1; // State: the timer for MsgPipe timeouts. static int waitTimer = -1; -struct NativeMsgPipe -{ - SceSize_le size; - char name[32]; - SceUInt_le attr; - s32_le bufSize; - s32_le freeSize; - s32_le numSendWaitThreads; - s32_le numReceiveWaitThreads; -}; - -struct MsgPipeWaitingThread -{ - SceUID threadID; - u32 bufAddr; - u32 bufSize; - // Free space at the end for receive, valid/free to read bytes from end for send. - u32 freeSize; - s32 waitMode; - PSPPointer transferredBytes; - u64 pausedTimeout; - - bool IsStillWaiting(SceUID waitID) const - { - return HLEKernel::VerifyWait(threadID, WAITTYPE_MSGPIPE, waitID); - } - - void WriteCurrentTimeout(SceUID waitID) const - { - u32 error; - if (IsStillWaiting(waitID)) - { - u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); - if (timeoutPtr != 0 && waitTimer != -1) - { - // Remove any event for this thread. - s64 cyclesLeft = CoreTiming::UnscheduleEvent(waitTimer, threadID); - Memory::WriteOrException_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); - } - } - } - - void Complete(SceUID waitID, int result) const - { - if (IsStillWaiting(waitID)) - { - WriteCurrentTimeout(waitID); - __KernelResumeThreadFromWait(threadID, result); - } - } - - void Cancel(SceUID waitID, int result) const - { - Complete(waitID, result); - } - - void ReadBuffer(u32 destPtr, u32 len) - { - Memory::Memcpy(destPtr, bufAddr + bufSize - freeSize, len, "MsgPipeReadBuffer"); - freeSize -= len; - if (transferredBytes.IsValid()) - *transferredBytes += len; - } - - void WriteBuffer(u32 srcPtr, u32 len) - { - Memory::Memcpy(bufAddr + (bufSize - freeSize), srcPtr, len, "MsgPipeWriteBuffer"); - freeSize -= len; - if (transferredBytes.IsValid()) - *transferredBytes += len; - } - - bool operator ==(const SceUID &otherThreadID) const - { - return threadID == otherThreadID; - } -}; +// NativeMsgPipe/MsgPipeWaitingThread/MsgPipe itself now live in sceKernelMsgPipe.h - see the +// comment on the class there for why. static bool __KernelMsgPipeThreadSortPriority(const MsgPipeWaitingThread &thread1, const MsgPipeWaitingThread &thread2) { return __KernelThreadSortPriority(thread1.threadID, thread2.threadID); } -struct MsgPipe : public KernelObject +bool MsgPipeWaitingThread::IsStillWaiting(SceUID waitID) const { - const char *GetName() override { return nmp.name; } - const char *GetTypeName() override { return GetStaticTypeName(); } - static const char *GetStaticTypeName() { return "MsgPipe"; } - static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_MPPID; } - static int GetStaticIDType() { return SCE_KERNEL_TMID_Mpipe; } - int GetIDType() const override { return SCE_KERNEL_TMID_Mpipe; } + return HLEKernel::VerifyWait(threadID, WAITTYPE_MSGPIPE, waitID); +} - MsgPipe() : buffer(0) {} - ~MsgPipe() { - if (buffer != 0) { - BlockAllocator *alloc = BlockAllocatorFromAddr(buffer); - _assert_msg_(alloc != nullptr, "Should always have a valid allocator/address"); - if (alloc) - alloc->Free(buffer); - } - } - - u32 GetUsedSize() +void MsgPipeWaitingThread::WriteCurrentTimeout(SceUID waitID) const +{ + u32 error; + if (IsStillWaiting(waitID)) { - return (u32)(nmp.bufSize - nmp.freeSize); - } - - void AddWaitingThread(std::vector &list, SceUID id, u32 addr, u32 size, int waitMode, u32 transferredBytesAddr) - { - MsgPipeWaitingThread thread = { id, addr, size, size, waitMode, { transferredBytesAddr } }; - // Start out with 0 transferred bytes while waiting. - // TODO: for receive, it might be a different (partial) number. - if (thread.transferredBytes.IsValid()) - *thread.transferredBytes = 0; - - list.push_back(thread); - } - - void AddSendWaitingThread(SceUID id, u32 addr, u32 size, int waitMode, u32 transferredBytesAddr) - { - AddWaitingThread(sendWaitingThreads, id, addr, size, waitMode, transferredBytesAddr); - } - - void AddReceiveWaitingThread(SceUID id, u32 addr, u32 size, int waitMode, u32 transferredBytesAddr) - { - AddWaitingThread(receiveWaitingThreads, id, addr, size, waitMode, transferredBytesAddr); - } - - bool CheckSendThreads() - { - SortSendThreads(); - - bool wokeThreads = false; - bool filledSpace = false; - while (!sendWaitingThreads.empty() && nmp.freeSize > 0) + u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); + if (timeoutPtr != 0 && waitTimer != -1) { - MsgPipeWaitingThread *thread = &sendWaitingThreads.front(); - u32 bytesToSend = std::min(thread->freeSize, (u32) nmp.freeSize); - - thread->ReadBuffer(buffer + GetUsedSize(), bytesToSend); - nmp.freeSize -= bytesToSend; - filledSpace = true; - - if (thread->waitMode == SCE_KERNEL_MPW_ASAP || thread->freeSize == 0) - { - thread->Complete(GetUID(), 0); - sendWaitingThreads.erase(sendWaitingThreads.begin()); - wokeThreads = true; - thread = NULL; - } - // Unlike receives, we don't do partial sends. Stop at first blocked thread. - else - break; + // Remove any event for this thread. + s64 cyclesLeft = CoreTiming::UnscheduleEvent(waitTimer, threadID); + Memory::WriteOrException_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); } - - if (filledSpace) - wokeThreads |= CheckReceiveThreads(); - - return wokeThreads; } +} - // This function should be only ran when the temporary buffer size is not 0 (otherwise, data is copied directly to the threads) - bool CheckReceiveThreads() +void MsgPipeWaitingThread::Complete(SceUID waitID, int result) const +{ + if (IsStillWaiting(waitID)) { - SortReceiveThreads(); + WriteCurrentTimeout(waitID); + __KernelResumeThreadFromWait(threadID, result); + } +} - bool wokeThreads = false; - bool freedSpace = false; - while (!receiveWaitingThreads.empty() && GetUsedSize() > 0) +void MsgPipeWaitingThread::Cancel(SceUID waitID, int result) const +{ + Complete(waitID, result); +} + +void MsgPipeWaitingThread::ReadBuffer(u32 destPtr, u32 len) +{ + Memory::Memcpy(destPtr, bufAddr + bufSize - freeSize, len, "MsgPipeReadBuffer"); + freeSize -= len; + if (transferredBytes.IsValid()) + *transferredBytes += len; +} + +void MsgPipeWaitingThread::WriteBuffer(u32 srcPtr, u32 len) +{ + Memory::Memcpy(bufAddr + (bufSize - freeSize), srcPtr, len, "MsgPipeWriteBuffer"); + freeSize -= len; + if (transferredBytes.IsValid()) + *transferredBytes += len; +} + +MsgPipe::MsgPipe() : buffer(0) {} +MsgPipe::~MsgPipe() { + if (buffer != 0) { + BlockAllocator *alloc = BlockAllocatorFromAddr(buffer); + _assert_msg_(alloc != nullptr, "Should always have a valid allocator/address"); + if (alloc) + alloc->Free(buffer); + } +} + +u32 MsgPipe::GetUsedSize() +{ + return (u32)(nmp.bufSize - nmp.freeSize); +} + +void MsgPipe::AddWaitingThread(std::vector &list, SceUID id, u32 addr, u32 size, int waitMode, u32 transferredBytesAddr) +{ + MsgPipeWaitingThread thread = { id, addr, size, size, waitMode, { transferredBytesAddr } }; + // Start out with 0 transferred bytes while waiting. + // TODO: for receive, it might be a different (partial) number. + if (thread.transferredBytes.IsValid()) + *thread.transferredBytes = 0; + + list.push_back(thread); +} + +void MsgPipe::AddSendWaitingThread(SceUID id, u32 addr, u32 size, int waitMode, u32 transferredBytesAddr) +{ + AddWaitingThread(sendWaitingThreads, id, addr, size, waitMode, transferredBytesAddr); +} + +void MsgPipe::AddReceiveWaitingThread(SceUID id, u32 addr, u32 size, int waitMode, u32 transferredBytesAddr) +{ + AddWaitingThread(receiveWaitingThreads, id, addr, size, waitMode, transferredBytesAddr); +} + +bool MsgPipe::CheckSendThreads() +{ + SortSendThreads(); + + bool wokeThreads = false; + bool filledSpace = false; + while (!sendWaitingThreads.empty() && nmp.freeSize > 0) + { + MsgPipeWaitingThread *thread = &sendWaitingThreads.front(); + u32 bytesToSend = std::min(thread->freeSize, (u32) nmp.freeSize); + + thread->ReadBuffer(buffer + GetUsedSize(), bytesToSend); + nmp.freeSize -= bytesToSend; + filledSpace = true; + + if (thread->waitMode == SCE_KERNEL_MPW_ASAP || thread->freeSize == 0) { - MsgPipeWaitingThread *thread = &receiveWaitingThreads.front(); - // Receive as much as possible, even if it's not enough to wake up. - u32 bytesToSend = std::min(thread->freeSize, GetUsedSize()); - - u8* ptr = Memory::GetPointerWriteOrException(buffer); - thread->WriteBuffer(buffer, bytesToSend); - // Put the unused data at the start of the buffer. - nmp.freeSize += bytesToSend; - memmove(ptr, ptr + bytesToSend, GetUsedSize()); - freedSpace = true; - - if (thread->waitMode == SCE_KERNEL_MPW_ASAP || thread->freeSize == 0) - { - thread->Complete(GetUID(), 0); - receiveWaitingThreads.erase(receiveWaitingThreads.begin()); - wokeThreads = true; - thread = NULL; - } - // Stop at the first that can't wake up. - else - break; + thread->Complete(GetUID(), 0); + sendWaitingThreads.erase(sendWaitingThreads.begin()); + wokeThreads = true; + thread = NULL; } - - if (freedSpace) - wokeThreads |= CheckSendThreads(); - - return wokeThreads; + // Unlike receives, we don't do partial sends. Stop at first blocked thread. + else + break; } - void SortThreads(std::vector &waitingThreads, bool usePrio) + if (filledSpace) + wokeThreads |= CheckReceiveThreads(); + + return wokeThreads; +} + +// This function should be only ran when the temporary buffer size is not 0 (otherwise, data is copied directly to the threads) +bool MsgPipe::CheckReceiveThreads() +{ + SortReceiveThreads(); + + bool wokeThreads = false; + bool freedSpace = false; + while (!receiveWaitingThreads.empty() && GetUsedSize() > 0) { - // Clean up any not waiting at the same time. - HLEKernel::CleanupWaitingThreads(WAITTYPE_MSGPIPE, GetUID(), waitingThreads); + MsgPipeWaitingThread *thread = &receiveWaitingThreads.front(); + // Receive as much as possible, even if it's not enough to wake up. + u32 bytesToSend = std::min(thread->freeSize, GetUsedSize()); - if (usePrio) - std::stable_sort(waitingThreads.begin(), waitingThreads.end(), __KernelMsgPipeThreadSortPriority); + u8* ptr = Memory::GetPointerWriteOrException(buffer); + thread->WriteBuffer(buffer, bytesToSend); + // Put the unused data at the start of the buffer. + nmp.freeSize += bytesToSend; + memmove(ptr, ptr + bytesToSend, GetUsedSize()); + freedSpace = true; + + if (thread->waitMode == SCE_KERNEL_MPW_ASAP || thread->freeSize == 0) + { + thread->Complete(GetUID(), 0); + receiveWaitingThreads.erase(receiveWaitingThreads.begin()); + wokeThreads = true; + thread = NULL; + } + // Stop at the first that can't wake up. + else + break; } - void SortReceiveThreads() - { - bool usePrio = (nmp.attr & SCE_KERNEL_MPA_THPRI_R) != 0; - SortThreads(receiveWaitingThreads, usePrio); - } + if (freedSpace) + wokeThreads |= CheckSendThreads(); - void SortSendThreads() - { - bool usePrio = (nmp.attr & SCE_KERNEL_MPA_THPRI_S) != 0; - SortThreads(sendWaitingThreads, usePrio); - } + return wokeThreads; +} - void RemoveReceiveWaitingThread(SceUID threadID) - { - HLEKernel::RemoveWaitingThread(receiveWaitingThreads, threadID); - } +void MsgPipe::SortThreads(std::vector &waitingThreads, bool usePrio) +{ + // Clean up any not waiting at the same time. + HLEKernel::CleanupWaitingThreads(WAITTYPE_MSGPIPE, GetUID(), waitingThreads); - void RemoveSendWaitingThread(SceUID threadID) - { - HLEKernel::RemoveWaitingThread(sendWaitingThreads, threadID); - } + if (usePrio) + std::stable_sort(waitingThreads.begin(), waitingThreads.end(), __KernelMsgPipeThreadSortPriority); +} - void DoState(PointerWrap &p) override - { - auto s = p.Section("MsgPipe", 1); - if (!s) - return; +void MsgPipe::SortReceiveThreads() +{ + bool usePrio = (nmp.attr & SCE_KERNEL_MPA_THPRI_R) != 0; + SortThreads(receiveWaitingThreads, usePrio); +} - Do(p, nmp); - MsgPipeWaitingThread mpwt1 = {0}, mpwt2 = {0}; - Do(p, sendWaitingThreads, mpwt1); - Do(p, receiveWaitingThreads, mpwt2); - Do(p, pausedSendWaits); - Do(p, pausedReceiveWaits); - Do(p, buffer); - } +void MsgPipe::SortSendThreads() +{ + bool usePrio = (nmp.attr & SCE_KERNEL_MPA_THPRI_S) != 0; + SortThreads(sendWaitingThreads, usePrio); +} - NativeMsgPipe nmp; +void MsgPipe::RemoveReceiveWaitingThread(SceUID threadID) +{ + HLEKernel::RemoveWaitingThread(receiveWaitingThreads, threadID); +} - std::vector sendWaitingThreads; - std::vector receiveWaitingThreads; - // Key is the callback id it was for, or if no callback, the thread id. - std::map pausedSendWaits; - std::map pausedReceiveWaits; +void MsgPipe::RemoveSendWaitingThread(SceUID threadID) +{ + HLEKernel::RemoveWaitingThread(sendWaitingThreads, threadID); +} - u32 buffer; -}; +void MsgPipe::DoState(PointerWrap &p) +{ + auto s = p.Section("MsgPipe", 1); + if (!s) + return; + + Do(p, nmp); + MsgPipeWaitingThread mpwt1 = {0}, mpwt2 = {0}; + Do(p, sendWaitingThreads, mpwt1); + Do(p, receiveWaitingThreads, mpwt2); + Do(p, pausedSendWaits); + Do(p, pausedReceiveWaits); + Do(p, buffer); +} KernelObject *__KernelMsgPipeObject() { diff --git a/Core/HLE/sceKernelMsgPipe.h b/Core/HLE/sceKernelMsgPipe.h index 28bd6e812c..fdbc097895 100644 --- a/Core/HLE/sceKernelMsgPipe.h +++ b/Core/HLE/sceKernelMsgPipe.h @@ -17,8 +17,89 @@ #pragma once +#include +#include + +#include "Core/HLE/sceKernel.h" +#include "Core/HLE/ErrorCodes.h" +#include "Core/MemMap.h" + class PointerWrap; +struct NativeMsgPipe { + SceSize_le size; + char name[32]; + SceUInt_le attr; + s32_le bufSize; + s32_le freeSize; + s32_le numSendWaitThreads; + s32_le numReceiveWaitThreads; +}; + +struct MsgPipeWaitingThread { + SceUID threadID; + u32 bufAddr; + u32 bufSize; + // Free space at the end for receive, valid/free to read bytes from end for send. + u32 freeSize; + s32 waitMode; + PSPPointer transferredBytes; + u64 pausedTimeout; + + bool IsStillWaiting(SceUID waitID) const; + void WriteCurrentTimeout(SceUID waitID) const; + void Complete(SceUID waitID, int result) const; + void Cancel(SceUID waitID, int result) const; + void ReadBuffer(u32 destPtr, u32 len); + void WriteBuffer(u32 srcPtr, u32 len); + + bool operator ==(const SceUID &otherThreadID) const { + return threadID == otherThreadID; + } +}; + +// Exposed here (rather than kept private to sceKernelMsgPipe.cpp) so the WebSocket debugger can +// read a live object's state directly via kernelObjects.Get()/Iterate() - see +// HLEKernelObjectSubscriber.cpp. That's a read-only use: nothing outside this file should call +// any of these methods (DoState, the Check*/Sort*/Add* helpers, etc.) or otherwise mutate a +// MsgPipe - it's public here for this file's own use as before, not an invitation to write to it +// from elsewhere. Method bodies stay defined in the .cpp (only the trivial one-liners are +// inline), so this header doesn't need to pull in Memory::/BlockAllocator/CoreTiming. +struct MsgPipe : public KernelObject { + const char *GetName() override { return nmp.name; } + const char *GetTypeName() override { return GetStaticTypeName(); } + static const char *GetStaticTypeName() { return "MsgPipe"; } + static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_MPPID; } + static int GetStaticIDType() { return SCE_KERNEL_TMID_Mpipe; } + int GetIDType() const override { return SCE_KERNEL_TMID_Mpipe; } + + MsgPipe(); + ~MsgPipe(); + + u32 GetUsedSize(); + void AddWaitingThread(std::vector &list, SceUID id, u32 addr, u32 size, int waitMode, u32 transferredBytesAddr); + void AddSendWaitingThread(SceUID id, u32 addr, u32 size, int waitMode, u32 transferredBytesAddr); + void AddReceiveWaitingThread(SceUID id, u32 addr, u32 size, int waitMode, u32 transferredBytesAddr); + bool CheckSendThreads(); + bool CheckReceiveThreads(); + void SortThreads(std::vector &waitingThreads, bool usePrio); + void SortReceiveThreads(); + void SortSendThreads(); + void RemoveReceiveWaitingThread(SceUID threadID); + void RemoveSendWaitingThread(SceUID threadID); + void DoState(PointerWrap &p) override; + + NativeMsgPipe nmp; + + std::vector sendWaitingThreads; + std::vector receiveWaitingThreads; + // Key is the callback id it was for, or if no callback, the thread id. + std::map pausedSendWaits; + std::map pausedReceiveWaits; + + u32 buffer; +}; + int sceKernelCreateMsgPipe(const char *name, int partition, u32 attr, u32 size, u32 optionsPtr); int sceKernelDeleteMsgPipe(SceUID uid); int sceKernelSendMsgPipe(SceUID uid, u32 sendBufAddr, u32 sendSize, u32 waitMode, u32 resultAddr, u32 timeoutPtr); diff --git a/Core/HLE/sceKernelMutex.cpp b/Core/HLE/sceKernelMutex.cpp index b61306e454..d939cc5fa9 100644 --- a/Core/HLE/sceKernelMutex.cpp +++ b/Core/HLE/sceKernelMutex.cpp @@ -39,45 +39,18 @@ #define PSP_MUTEX_ATTR_ALLOW_RECURSIVE 0x200 #define PSP_MUTEX_ATTR_KNOWN (PSP_MUTEX_ATTR_PRIORITY | PSP_MUTEX_ATTR_ALLOW_RECURSIVE) -struct NativeMutex -{ - SceSize_le size; - char name[KERNELOBJECT_MAX_NAME_LENGTH + 1]; - SceUInt_le attr; - s32_le initialCount; - s32_le lockLevel; - SceUID_le lockThread; - // Not kept up to date. - s32_le numWaitThreads; -}; - -struct PSPMutex : public KernelObject -{ - const char *GetName() override { return nm.name; } - const char *GetTypeName() override { return GetStaticTypeName(); } - static const char *GetStaticTypeName() { return "Mutex"; } - static u32 GetMissingErrorCode() { return SCE_MUTEX_ERROR_NO_SUCH_MUTEX; } - static int GetStaticIDType() { return SCE_KERNEL_TMID_Mutex; } - int GetIDType() const override { return SCE_KERNEL_TMID_Mutex; } - - void DoState(PointerWrap &p) override - { - auto s = p.Section("Mutex", 1); - if (!s) - return; - - Do(p, nm); - SceUID dv = 0; - Do(p, waitingThreads, dv); - Do(p, pausedWaits); - } - - NativeMutex nm; - std::vector waitingThreads; - // Key is the callback id it was for, or if no callback, the thread id. - std::map pausedWaits; -}; +// NativeMutex/PSPMutex itself now live in sceKernelMutex.h - see the comment on the class there +// for why. +void PSPMutex::DoState(PointerWrap &p) { + auto s = p.Section("Mutex", 1); + if (!s) + return; + Do(p, nm); + SceUID dv = 0; + Do(p, waitingThreads, dv); + Do(p, pausedWaits); +} struct NativeLwMutexWorkarea { diff --git a/Core/HLE/sceKernelMutex.h b/Core/HLE/sceKernelMutex.h index 69e63e0709..12674b7b02 100644 --- a/Core/HLE/sceKernelMutex.h +++ b/Core/HLE/sceKernelMutex.h @@ -17,6 +17,46 @@ #pragma once +#include +#include + +#include "Core/HLE/sceKernel.h" +#include "Core/HLE/ErrorCodes.h" + +class PointerWrap; + +struct NativeMutex { + SceSize_le size; + char name[KERNELOBJECT_MAX_NAME_LENGTH + 1]; + SceUInt_le attr; + s32_le initialCount; + s32_le lockLevel; + SceUID_le lockThread; + // Not kept up to date. + s32_le numWaitThreads; +}; + +// Exposed here (rather than kept private to sceKernelMutex.cpp) so the WebSocket debugger can +// read a live object's state directly via kernelObjects.Get()/Iterate() - see +// HLEKernelObjectSubscriber.cpp. That's a read-only use: nothing outside this file should call +// DoState() or otherwise mutate a PSPMutex - it's public here for this file's own use as before, +// not an invitation to write to it from elsewhere. +struct PSPMutex : public KernelObject { + const char *GetName() override { return nm.name; } + const char *GetTypeName() override { return GetStaticTypeName(); } + static const char *GetStaticTypeName() { return "Mutex"; } + static u32 GetMissingErrorCode() { return SCE_MUTEX_ERROR_NO_SUCH_MUTEX; } + static int GetStaticIDType() { return SCE_KERNEL_TMID_Mutex; } + int GetIDType() const override { return SCE_KERNEL_TMID_Mutex; } + + void DoState(PointerWrap &p) override; + + NativeMutex nm; + std::vector waitingThreads; + // Key is the callback id it was for, or if no callback, the thread id. + std::map pausedWaits; +}; + int sceKernelCancelMutex(SceUID uid, int count, u32 numWaitThreadsPtr); int sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optionsPtr); int sceKernelDeleteMutex(SceUID id); diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index a04740f11d..42c7bc4c28 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -38,51 +38,18 @@ * @see sceKernelReferSemaStatus. */ -struct NativeSemaphore -{ - /** Size of the ::SceKernelSemaInfo structure. */ - SceSize_le size; - /** NUL-terminated name of the semaphore. */ - char name[KERNELOBJECT_MAX_NAME_LENGTH + 1]; - /** Attributes. */ - SceUInt_le attr; - /** The initial count the semaphore was created with. */ - s32_le initCount; - /** The current count. */ - s32_le currentCount; - /** The maximum count. */ - s32_le maxCount; - /** The number of threads waiting on the semaphore. */ - s32_le numWaitThreads; -}; +// NativeSemaphore/PSPSemaphore itself now live in sceKernelSemaphore.h - see the comment on the +// class there for why. +void PSPSemaphore::DoState(PointerWrap &p) { + auto s = p.Section("Semaphore", 1); + if (!s) + return; - -struct PSPSemaphore : public KernelObject { - const char *GetName() override { return ns.name; } - const char *GetTypeName() override { return GetStaticTypeName(); } - static const char *GetStaticTypeName() { return "Semaphore"; } - - static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_SEMID; } - static int GetStaticIDType() { return SCE_KERNEL_TMID_Semaphore; } - int GetIDType() const override { return SCE_KERNEL_TMID_Semaphore; } - - void DoState(PointerWrap &p) override - { - auto s = p.Section("Semaphore", 1); - if (!s) - return; - - Do(p, ns); - SceUID dv = 0; - Do(p, waitingThreads, dv); - Do(p, pausedWaits); - } - - NativeSemaphore ns; - std::vector waitingThreads; - // Key is the callback id it was for, or if no callback, the thread id. - std::map pausedWaits; -}; + Do(p, ns); + SceUID dv = 0; + Do(p, waitingThreads, dv); + Do(p, pausedWaits); +} static int semaWaitTimer = -1; diff --git a/Core/HLE/sceKernelSemaphore.h b/Core/HLE/sceKernelSemaphore.h index 1a635925e6..74002ff9d6 100644 --- a/Core/HLE/sceKernelSemaphore.h +++ b/Core/HLE/sceKernelSemaphore.h @@ -17,6 +17,54 @@ #pragma once +#include +#include + +#include "Core/HLE/sceKernel.h" +#include "Core/HLE/ErrorCodes.h" + +class PointerWrap; + +struct NativeSemaphore { + /** Size of the ::SceKernelSemaInfo structure. */ + SceSize_le size; + /** NUL-terminated name of the semaphore. */ + char name[KERNELOBJECT_MAX_NAME_LENGTH + 1]; + /** Attributes. */ + SceUInt_le attr; + /** The initial count the semaphore was created with. */ + s32_le initCount; + /** The current count. */ + s32_le currentCount; + /** The maximum count. */ + s32_le maxCount; + /** The number of threads waiting on the semaphore. */ + s32_le numWaitThreads; +}; + +// Exposed here (rather than kept private to sceKernelSemaphore.cpp) so the WebSocket debugger +// can read a live object's state directly via +// kernelObjects.Get()/Iterate() - see HLEKernelObjectSubscriber.cpp. +// That's a read-only use: nothing outside this file should call DoState() or otherwise mutate a +// PSPSemaphore - it's public here for this file's own use as before, not an invitation to write +// to it from elsewhere. +struct PSPSemaphore : public KernelObject { + const char *GetName() override { return ns.name; } + const char *GetTypeName() override { return GetStaticTypeName(); } + static const char *GetStaticTypeName() { return "Semaphore"; } + + static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_SEMID; } + static int GetStaticIDType() { return SCE_KERNEL_TMID_Semaphore; } + int GetIDType() const override { return SCE_KERNEL_TMID_Semaphore; } + + void DoState(PointerWrap &p) override; + + NativeSemaphore ns; + std::vector waitingThreads; + // Key is the callback id it was for, or if no callback, the thread id. + std::map pausedWaits; +}; + int sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr); int sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u32 optionPtr); int sceKernelDeleteSema(SceUID id); diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index 4c0e141f4c..57ddf1daae 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -107,56 +107,23 @@ enum ThreadEventType { bool __KernelThreadTriggerEvent(bool isKernel, SceUID threadID, ThreadEventType type); -struct NativeCallback +// NativeCallback/PSPCallback itself now live in sceKernelThread.h - see the comment on the class +// there for why. +void PSPCallback::DoState(PointerWrap &p) { - SceUInt_le size; - char name[32]; - SceUID_le threadId; - u32_le entrypoint; - u32_le commonArgument; + auto s = p.Section("Callback", 1); + if (!s) + return; - s32_le notifyCount; - s32_le notifyArg; -}; - -class PSPCallback : public KernelObject { -public: - const char *GetName() override { return nc.name; } - const char *GetTypeName() override { return GetStaticTypeName(); } - static const char *GetStaticTypeName() { return "CallBack"; } - - void GetQuickInfo(char *ptr, int size) override { - snprintf(ptr, size, "thread=%i, argument= %08x", - //hackAddress, - nc.threadId, - nc.commonArgument); - } - - ~PSPCallback() { - } - - static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_CBID; } - static int GetStaticIDType() { return SCE_KERNEL_TMID_Callback; } - int GetIDType() const override { return SCE_KERNEL_TMID_Callback; } - - void DoState(PointerWrap &p) override - { - auto s = p.Section("Callback", 1); - if (!s) - return; - - Do(p, nc); - // Saved values were moved to mips call, ignoring here. - u32 legacySaved = 0; - Do(p, legacySaved); - Do(p, legacySaved); - Do(p, legacySaved); - Do(p, legacySaved); - Do(p, legacySaved); - } - - NativeCallback nc; -}; + Do(p, nc); + // Saved values were moved to mips call, ignoring here. + u32 legacySaved = 0; + Do(p, legacySaved); + Do(p, legacySaved); + Do(p, legacySaved); + Do(p, legacySaved); + Do(p, legacySaved); +} // Owns outstanding MIPS calls and provides a way to get them by ID. class MipsCallManager { diff --git a/Core/HLE/sceKernelThread.h b/Core/HLE/sceKernelThread.h index 41e664fbed..40c6c37ddf 100644 --- a/Core/HLE/sceKernelThread.h +++ b/Core/HLE/sceKernelThread.h @@ -17,6 +17,7 @@ #pragma once +#include #include #include #include @@ -24,6 +25,7 @@ #include "Common/CommonTypes.h" #include "Core/HLE/sceKernel.h" +#include "Core/HLE/ErrorCodes.h" #include "Core/HLE/PSPThreadContext.h" #include "Core/HLE/KernelThreadDebugInterface.h" @@ -175,6 +177,46 @@ struct NativeThread { s32_le numReleases; }; +struct NativeCallback { + SceUInt_le size; + char name[32]; + SceUID_le threadId; + u32_le entrypoint; + u32_le commonArgument; + + s32_le notifyCount; + s32_le notifyArg; +}; + +// Exposed here (rather than kept private to sceKernelThread.cpp) so the WebSocket debugger can +// read a live object's state directly via kernelObjects.Get()/Iterate() +// - see HLEKernelObjectSubscriber.cpp. That's a read-only use: nothing outside this file should +// call DoState() or otherwise mutate a PSPCallback - it's public here for this file's own use as +// before, not an invitation to write to it from elsewhere. +class PSPCallback : public KernelObject { +public: + const char *GetName() override { return nc.name; } + const char *GetTypeName() override { return GetStaticTypeName(); } + static const char *GetStaticTypeName() { return "CallBack"; } + + void GetQuickInfo(char *ptr, int size) override { + snprintf(ptr, size, "thread=%i, argument= %08x", + nc.threadId, + nc.commonArgument); + } + + ~PSPCallback() { + } + + static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_CBID; } + static int GetStaticIDType() { return SCE_KERNEL_TMID_Callback; } + int GetIDType() const override { return SCE_KERNEL_TMID_Callback; } + + void DoState(PointerWrap &p) override; + + NativeCallback nc; +}; + struct ThreadWaitInfo { u32 waitValue; u32 timeoutPtr;