Common: Move OSThreads into core

Common shouldn't be depending on APIs in Core (in this, case depending
on the PowerPC namespace). Because of the poor separation here, this
moves OSThread functionality into core, so that it resolves the implicit
dependency on core.
This commit is contained in:
Lioncash
2020-10-20 18:05:59 -04:00
parent 7e197186b9
commit 57534777d4
9 changed files with 49 additions and 45 deletions

View File

@ -1,204 +0,0 @@
// Copyright 2020 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Common/Debug/OSThread.h"
#include <algorithm>
#include <fmt/format.h>
#include "Core/PowerPC/MMU.h"
// Context offsets based on the following functions:
// - OSSaveContext
// - OSSaveFPUContext
// - OSDumpContext
// - OSClearContext
// - OSExceptionVector
void Common::Debug::OSContext::Read(u32 addr)
{
for (std::size_t i = 0; i < gpr.size(); i++)
gpr[i] = PowerPC::HostRead_U32(addr + u32(i * sizeof(int)));
cr = PowerPC::HostRead_U32(addr + 0x80);
lr = PowerPC::HostRead_U32(addr + 0x84);
ctr = PowerPC::HostRead_U32(addr + 0x88);
xer = PowerPC::HostRead_U32(addr + 0x8C);
for (std::size_t i = 0; i < fpr.size(); i++)
fpr[i] = PowerPC::HostRead_F64(addr + 0x90 + u32(i * sizeof(double)));
fpscr = PowerPC::HostRead_U64(addr + 0x190);
srr0 = PowerPC::HostRead_U32(addr + 0x198);
srr1 = PowerPC::HostRead_U32(addr + 0x19c);
dummy = PowerPC::HostRead_U16(addr + 0x1a0);
state = static_cast<OSContext::State>(PowerPC::HostRead_U16(addr + 0x1a2));
for (std::size_t i = 0; i < gqr.size(); i++)
gqr[i] = PowerPC::HostRead_U32(addr + 0x1a4 + u32(i * sizeof(int)));
psf_padding = 0;
for (std::size_t i = 0; i < psf.size(); i++)
psf[i] = PowerPC::HostRead_F64(addr + 0x1c8 + u32(i * sizeof(double)));
}
// Mutex offsets based on the following functions:
// - OSInitMutex
// - OSLockMutex
// - __OSUnlockAllMutex
void Common::Debug::OSMutex::Read(u32 addr)
{
thread_queue.head = PowerPC::HostRead_U32(addr);
thread_queue.tail = PowerPC::HostRead_U32(addr + 0x4);
owner_addr = PowerPC::HostRead_U32(addr + 0x8);
lock_count = PowerPC::HostRead_U32(addr + 0xc);
link.next = PowerPC::HostRead_U32(addr + 0x10);
link.prev = PowerPC::HostRead_U32(addr + 0x14);
}
// Thread offsets based on the following functions:
// - OSCreateThread
// - OSIsThreadTerminated
// - OSJoinThread
// - OSSuspendThread
// - OSSetPriority
// - OSExitThread
// - OSLockMutex
// - __OSUnlockAllMutex
// - __OSThreadInit
// - OSSetThreadSpecific
// - SOInit (for errno)
void Common::Debug::OSThread::Read(u32 addr)
{
context.Read(addr);
state = PowerPC::HostRead_U16(addr + 0x2c8);
is_detached = PowerPC::HostRead_U16(addr + 0x2ca);
suspend = PowerPC::HostRead_U32(addr + 0x2cc);
effective_priority = PowerPC::HostRead_U32(addr + 0x2d0);
base_priority = PowerPC::HostRead_U32(addr + 0x2d4);
exit_code_addr = PowerPC::HostRead_U32(addr + 0x2d8);
queue_addr = PowerPC::HostRead_U32(addr + 0x2dc);
queue_link.next = PowerPC::HostRead_U32(addr + 0x2e0);
queue_link.prev = PowerPC::HostRead_U32(addr + 0x2e4);
join_queue.head = PowerPC::HostRead_U32(addr + 0x2e8);
join_queue.tail = PowerPC::HostRead_U32(addr + 0x2ec);
mutex_addr = PowerPC::HostRead_U32(addr + 0x2f0);
mutex_queue.head = PowerPC::HostRead_U32(addr + 0x2f4);
mutex_queue.tail = PowerPC::HostRead_U32(addr + 0x2f8);
thread_link.next = PowerPC::HostRead_U32(addr + 0x2fc);
thread_link.prev = PowerPC::HostRead_U32(addr + 0x300);
stack_addr = PowerPC::HostRead_U32(addr + 0x304);
stack_end = PowerPC::HostRead_U32(addr + 0x308);
error = PowerPC::HostRead_U32(addr + 0x30c);
specific[0] = PowerPC::HostRead_U32(addr + 0x310);
specific[1] = PowerPC::HostRead_U32(addr + 0x314);
}
bool Common::Debug::OSThread::IsValid() const
{
return PowerPC::HostIsRAMAddress(stack_end) && PowerPC::HostRead_U32(stack_end) == STACK_MAGIC;
}
Common::Debug::OSThreadView::OSThreadView(u32 addr)
{
m_address = addr;
m_thread.Read(addr);
}
const Common::Debug::OSThread& Common::Debug::OSThreadView::Data() const
{
return m_thread;
}
Common::Debug::PartialContext Common::Debug::OSThreadView::GetContext() const
{
PartialContext context;
if (!IsValid())
return context;
context.gpr = m_thread.context.gpr;
context.cr = m_thread.context.cr;
context.lr = m_thread.context.lr;
context.ctr = m_thread.context.ctr;
context.xer = m_thread.context.xer;
context.fpr = m_thread.context.fpr;
context.fpscr = m_thread.context.fpscr;
context.srr0 = m_thread.context.srr0;
context.srr1 = m_thread.context.srr1;
context.dummy = m_thread.context.dummy;
context.state = static_cast<u16>(m_thread.context.state);
context.gqr = m_thread.context.gqr;
context.psf = m_thread.context.psf;
return context;
}
u32 Common::Debug::OSThreadView::GetAddress() const
{
return m_address;
}
u16 Common::Debug::OSThreadView::GetState() const
{
return m_thread.state;
}
bool Common::Debug::OSThreadView::IsSuspended() const
{
return m_thread.suspend > 0;
}
bool Common::Debug::OSThreadView::IsDetached() const
{
return m_thread.is_detached != 0;
}
s32 Common::Debug::OSThreadView::GetBasePriority() const
{
return m_thread.base_priority;
}
s32 Common::Debug::OSThreadView::GetEffectivePriority() const
{
return m_thread.effective_priority;
}
u32 Common::Debug::OSThreadView::GetStackStart() const
{
return m_thread.stack_addr;
}
u32 Common::Debug::OSThreadView::GetStackEnd() const
{
return m_thread.stack_end;
}
std::size_t Common::Debug::OSThreadView::GetStackSize() const
{
return GetStackStart() - GetStackEnd();
}
s32 Common::Debug::OSThreadView::GetErrno() const
{
return m_thread.error;
}
std::string Common::Debug::OSThreadView::GetSpecific() const
{
std::string specific;
for (u32 addr : m_thread.specific)
{
if (!PowerPC::HostIsRAMAddress(addr))
break;
specific += fmt::format("{:08x} \"{}\"\n", addr, PowerPC::HostGetString(addr));
}
return specific;
}
bool Common::Debug::OSThreadView::IsValid() const
{
return m_thread.IsValid();
}

View File

@ -1,154 +0,0 @@
// Copyright 2020 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <string>
#include <type_traits>
#include "Common/CommonTypes.h"
#include "Common/Debug/Threads.h"
namespace Common::Debug
{
template <class C>
struct OSQueue
{
u32 head;
u32 tail;
};
template <class C>
struct OSLink
{
u32 next;
u32 prev;
};
struct OSMutex;
struct OSThread;
using OSThreadQueue = OSQueue<OSThread>;
using OSThreadLink = OSLink<OSThread>;
using OSMutexQueue = OSQueue<OSMutex>;
using OSMutexLink = OSLink<OSMutex>;
struct OSContext
{
enum class State : u16
{
HasFPU = 1,
HasException = 2,
};
std::array<u32, 32> gpr;
u32 cr;
u32 lr;
u32 ctr;
u32 xer;
std::array<double, 32> fpr;
u64 fpscr;
u32 srr0;
u32 srr1;
u16 dummy;
State state;
std::array<u32, 8> gqr;
u32 psf_padding;
std::array<double, 32> psf;
void Read(u32 addr);
};
static_assert(std::is_trivially_copyable_v<OSContext>);
static_assert(std::is_standard_layout_v<OSContext>);
static_assert(offsetof(OSContext, cr) == 0x80);
static_assert(offsetof(OSContext, fpscr) == 0x190);
static_assert(offsetof(OSContext, gqr) == 0x1a4);
static_assert(offsetof(OSContext, psf) == 0x1c8);
struct OSThread
{
OSContext context;
u16 state; // Thread state (ready, running, waiting, moribund)
u16 is_detached; // Is thread detached
s32 suspend; // Suspended if greater than zero
s32 effective_priority; // Effective priority
s32 base_priority; // Base priority
u32 exit_code_addr; // Exit value address
u32 queue_addr; // Address of the queue the thread is on
OSThreadLink queue_link; // Used to traverse the thread queue
// OSSleepThread uses it to insert the current thread at the end of the thread queue
OSThreadQueue join_queue; // Threads waiting to be joined
u32 mutex_addr; // Mutex waiting
OSMutexQueue mutex_queue; // Mutex owned
OSThreadLink thread_link; // Link containing all active threads
// The STACK_MAGIC is written at stack_end
u32 stack_addr;
u32 stack_end;
s32 error; // errno value
std::array<u32, 2> specific; // Pointers to data (can be used to store thread names)
static constexpr u32 STACK_MAGIC = 0xDEADBABE;
void Read(u32 addr);
bool IsValid() const;
};
static_assert(std::is_trivially_copyable_v<OSThread>);
static_assert(std::is_standard_layout_v<OSThread>);
static_assert(offsetof(OSThread, state) == 0x2c8);
static_assert(offsetof(OSThread, mutex_addr) == 0x2f0);
static_assert(offsetof(OSThread, stack_addr) == 0x304);
static_assert(offsetof(OSThread, specific) == 0x310);
struct OSMutex
{
OSThreadQueue thread_queue; // Threads waiting to own the mutex
u32 owner_addr; // Thread owning the mutex
s32 lock_count; // Mutex lock count
OSMutexLink link; // Used to traverse the thread's mutex queue
// OSLockMutex uses it to insert the acquired mutex at the end of the queue
void Read(u32 addr);
};
static_assert(std::is_trivially_copyable_v<OSMutex>);
static_assert(std::is_standard_layout_v<OSMutex>);
static_assert(offsetof(OSMutex, owner_addr) == 0x8);
static_assert(offsetof(OSMutex, link) == 0x10);
class OSThreadView : public Common::Debug::ThreadView
{
public:
explicit OSThreadView(u32 addr);
~OSThreadView() = default;
const OSThread& Data() const;
PartialContext GetContext() const override;
u32 GetAddress() const override;
u16 GetState() const override;
bool IsSuspended() const override;
bool IsDetached() const override;
s32 GetBasePriority() const override;
s32 GetEffectivePriority() const override;
u32 GetStackStart() const override;
u32 GetStackEnd() const override;
std::size_t GetStackSize() const override;
s32 GetErrno() const override;
std::string GetSpecific() const override;
bool IsValid() const override;
private:
u32 m_address = 0;
OSThread m_thread;
};
} // namespace Common::Debug