summaryrefslogtreecommitdiff
path: root/Source/Core/Common/Debug/OSThread.h
blob: 7a588c670eab0ab62677f33a202b164e1bfe3de2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// 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