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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
|
// Copyright 2014 Citra Emulator Project / PPSSPP Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <string>
#include <vector>
#include <boost/container/flat_set.hpp>
#include "common/common_types.h"
#include "core/core.h"
#include "core/mem_map.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/result.h"
enum ThreadPriority {
THREADPRIO_HIGHEST = 0, ///< Highest thread priority
THREADPRIO_DEFAULT = 16, ///< Default thread priority for userland apps
THREADPRIO_LOW = 31, ///< Low range of thread priority for userland apps
THREADPRIO_LOWEST = 63, ///< Thread priority max checked by svcCreateThread
};
enum ThreadProcessorId {
THREADPROCESSORID_0 = 0xFFFFFFFE, ///< Enables core appcode
THREADPROCESSORID_1 = 0xFFFFFFFD, ///< Enables core syscore
THREADPROCESSORID_ALL = 0xFFFFFFFC, ///< Enables both cores
};
enum ThreadStatus {
THREADSTATUS_RUNNING, ///< Currently running
THREADSTATUS_READY, ///< Ready to run
THREADSTATUS_WAIT_ARB, ///< Waiting on an address arbiter
THREADSTATUS_WAIT_SLEEP, ///< Waiting due to a SleepThread SVC
THREADSTATUS_WAIT_SYNCH, ///< Waiting due to a WaitSynchronization SVC
THREADSTATUS_DORMANT, ///< Created but not yet made ready
THREADSTATUS_DEAD ///< Run to completion, or forcefully terminated
};
namespace Kernel {
class Mutex;
class Thread final : public WaitObject {
public:
/**
* Creates and returns a new thread. The new thread is immediately scheduled
* @param name The friendly name desired for the thread
* @param entry_point The address at which the thread should start execution
* @param priority The thread's priority
* @param arg User data to pass to the thread
* @param processor_id The ID(s) of the processors on which the thread is desired to be run
* @param stack_top The address of the thread's stack top
* @param stack_size The size of the thread's stack
* @return A shared pointer to the newly created thread
*/
static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, s32 priority,
u32 arg, s32 processor_id, VAddr stack_top);
std::string GetName() const override { return name; }
std::string GetTypeName() const override { return "Thread"; }
static const HandleType HANDLE_TYPE = HandleType::Thread;
HandleType GetHandleType() const override { return HANDLE_TYPE; }
bool ShouldWait() override;
void Acquire() override;
/**
* Checks if the thread is an idle (stub) thread
* @return True if the thread is an idle (stub) thread, false otherwise
*/
inline bool IsIdle() const { return idle; }
/**
* Gets the thread's current priority
* @return The current thread's priority
*/
s32 GetPriority() const { return current_priority; }
/**
* Sets the thread's current priority
* @param priority The new priority
*/
void SetPriority(s32 priority);
/**
* Gets the thread's thread ID
* @return The thread's ID
*/
u32 GetThreadId() const { return thread_id; }
/**
* Release an acquired wait object
* @param wait_object WaitObject to release
*/
void ReleaseWaitObject(WaitObject* wait_object);
/**
* Resumes a thread from waiting
*/
void ResumeFromWait();
/**
* Schedules an event to wake up the specified thread after the specified delay
* @param nanoseconds The time this thread will be allowed to sleep for
*/
void WakeAfterDelay(s64 nanoseconds);
/**
* Sets the result after the thread awakens (from either WaitSynchronization SVC)
* @param result Value to set to the returned result
*/
void SetWaitSynchronizationResult(ResultCode result);
/**
* Sets the output parameter value after the thread awakens (from WaitSynchronizationN SVC only)
* @param output Value to set to the output parameter
*/
void SetWaitSynchronizationOutput(s32 output);
/**
* Stops a thread, invalidating it from further use
*/
void Stop();
Core::ThreadContext context;
u32 thread_id;
u32 status;
u32 entry_point;
u32 stack_top;
s32 initial_priority;
s32 current_priority;
s32 processor_id;
/// Mutexes currently held by this thread, which will be released when it exits.
boost::container::flat_set<SharedPtr<Mutex>> held_mutexes;
std::vector<SharedPtr<WaitObject>> wait_objects; ///< Objects that the thread is waiting on
VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address
bool wait_all; ///< True if the thread is waiting on all objects before resuming
bool wait_set_output; ///< True if the output parameter should be set on thread wakeup
std::string name;
/// Whether this thread is intended to never actually be executed, i.e. always idle
bool idle = false;
private:
Thread();
~Thread() override;
/// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
Handle callback_handle;
};
extern SharedPtr<Thread> g_main_thread;
/**
* Sets up the primary application thread
* @param stack_size The size of the thread's stack
* @param entry_point The address at which the thread should start execution
* @param priority The priority to give the main thread
* @return A shared pointer to the main thread
*/
SharedPtr<Thread> SetupMainThread(u32 stack_size, u32 entry_point, s32 priority);
/**
* Reschedules to the next available thread (call after current thread is suspended)
*/
void Reschedule();
/**
* Arbitrate the highest priority thread that is waiting
* @param address The address for which waiting threads should be arbitrated
*/
Thread* ArbitrateHighestPriorityThread(u32 address);
/**
* Arbitrate all threads currently waiting.
* @param address The address for which waiting threads should be arbitrated
*/
void ArbitrateAllThreads(u32 address);
/**
* Gets the current thread
*/
Thread* GetCurrentThread();
/**
* Waits the current thread on a sleep
*/
void WaitCurrentThread_Sleep();
/**
* Waits the current thread from a WaitSynchronization call
* @param wait_objects Kernel objects that we are waiting on
* @param wait_set_output If true, set the output parameter on thread wakeup (for WaitSynchronizationN only)
* @param wait_all If true, wait on all objects before resuming (for WaitSynchronizationN only)
*/
void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wait_objects, bool wait_set_output, bool wait_all);
/**
* Waits the current thread from an ArbitrateAddress call
* @param wait_address Arbitration address used to resume from wait
*/
void WaitCurrentThread_ArbitrateAddress(VAddr wait_address);
/**
* Sets up the idle thread, this is a thread that is intended to never execute instructions,
* only to advance the timing. It is scheduled when there are no other ready threads in the thread queue
* and will try to yield on every call.
* @return The handle of the idle thread
*/
SharedPtr<Thread> SetupIdleThread();
/**
* Initialize threading
*/
void ThreadingInit();
/**
* Shutdown threading
*/
void ThreadingShutdown();
} // namespace
|