mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-15 07:50:07 +00:00
Thread: Keep track of multiple wait objects.
This commit is contained in:
parent
14cbbf4d9b
commit
1f7a04f05a
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
class AddressArbiter : public Object {
|
class AddressArbiter : public WaitObject {
|
||||||
public:
|
public:
|
||||||
std::string GetTypeName() const override { return "Arbiter"; }
|
std::string GetTypeName() const override { return "Arbiter"; }
|
||||||
std::string GetName() const override { return name; }
|
std::string GetName() const override { return name; }
|
||||||
@ -30,7 +30,8 @@ public:
|
|||||||
|
|
||||||
/// Arbitrate an address
|
/// Arbitrate an address
|
||||||
ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value, u64 nanoseconds) {
|
ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value, u64 nanoseconds) {
|
||||||
Object* object = Kernel::g_handle_table.GetGeneric(handle).get();
|
WaitObject* object = static_cast<WaitObject*>(Kernel::g_handle_table.GetGeneric(handle).get());
|
||||||
|
|
||||||
if (object == nullptr)
|
if (object == nullptr)
|
||||||
return InvalidHandle(ErrorModule::Kernel);
|
return InvalidHandle(ErrorModule::Kernel);
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ static void ResetThread(Thread* t, u32 arg, s32 lowest_priority) {
|
|||||||
t->current_priority = t->initial_priority;
|
t->current_priority = t->initial_priority;
|
||||||
}
|
}
|
||||||
t->wait_type = WAITTYPE_NONE;
|
t->wait_type = WAITTYPE_NONE;
|
||||||
t->wait_object = nullptr;
|
t->wait_objects.clear();
|
||||||
t->wait_address = 0;
|
t->wait_address = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +92,11 @@ static bool CheckWaitType(const Thread* thread, WaitType type) {
|
|||||||
|
|
||||||
/// Check if a thread is blocking on a specified wait type with a specified handle
|
/// Check if a thread is blocking on a specified wait type with a specified handle
|
||||||
static bool CheckWaitType(const Thread* thread, WaitType type, Object* wait_object) {
|
static bool CheckWaitType(const Thread* thread, WaitType type, Object* wait_object) {
|
||||||
return CheckWaitType(thread, type) && wait_object == thread->wait_object;
|
auto itr = std::find(thread->wait_objects.begin(), thread->wait_objects.end(), wait_object);
|
||||||
|
if (itr == thread->wait_objects.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return CheckWaitType(thread, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if a thread is blocking on a specified wait type with a specified handle and address
|
/// Check if a thread is blocking on a specified wait type with a specified handle and address
|
||||||
@ -111,7 +115,7 @@ void Thread::Stop(const char* reason) {
|
|||||||
|
|
||||||
// Stopped threads are never waiting.
|
// Stopped threads are never waiting.
|
||||||
wait_type = WAITTYPE_NONE;
|
wait_type = WAITTYPE_NONE;
|
||||||
wait_object = nullptr;
|
wait_objects.clear();
|
||||||
wait_address = 0;
|
wait_address = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,14 +220,18 @@ static Thread* NextThread() {
|
|||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaitCurrentThread(WaitType wait_type, Object* wait_object) {
|
void WaitCurrentThread(WaitType wait_type, WaitObject* wait_object) {
|
||||||
Thread* thread = GetCurrentThread();
|
Thread* thread = GetCurrentThread();
|
||||||
thread->wait_type = wait_type;
|
thread->wait_type = wait_type;
|
||||||
thread->wait_object = wait_object;
|
|
||||||
|
auto res = std::find(thread->wait_objects.begin(), thread->wait_objects.end(), wait_object);
|
||||||
|
if (res == thread->wait_objects.end()) {
|
||||||
|
thread->wait_objects.push_back(wait_object);
|
||||||
|
}
|
||||||
ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND)));
|
ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaitCurrentThread(WaitType wait_type, Object* wait_object, VAddr wait_address) {
|
void WaitCurrentThread(WaitType wait_type, WaitObject* wait_object, VAddr wait_address) {
|
||||||
WaitCurrentThread(wait_type, wait_object);
|
WaitCurrentThread(wait_type, wait_object);
|
||||||
GetCurrentThread()->wait_address = wait_address;
|
GetCurrentThread()->wait_address = wait_address;
|
||||||
}
|
}
|
||||||
@ -260,7 +268,13 @@ void Thread::ResumeFromWait() {
|
|||||||
CoreTiming::UnscheduleEvent(ThreadWakeupEventType, GetHandle());
|
CoreTiming::UnscheduleEvent(ThreadWakeupEventType, GetHandle());
|
||||||
|
|
||||||
status &= ~THREADSTATUS_WAIT;
|
status &= ~THREADSTATUS_WAIT;
|
||||||
wait_object = nullptr;
|
|
||||||
|
// Remove this thread from all other WaitObjects
|
||||||
|
for (auto wait_object : wait_objects)
|
||||||
|
wait_object->RemoveWaitingThread(this);
|
||||||
|
|
||||||
|
wait_objects.clear();
|
||||||
|
|
||||||
wait_type = WAITTYPE_NONE;
|
wait_type = WAITTYPE_NONE;
|
||||||
if (!(status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) {
|
if (!(status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) {
|
||||||
ChangeReadyState(this, true);
|
ChangeReadyState(this, true);
|
||||||
@ -328,7 +342,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
|
|||||||
thread->initial_priority = thread->current_priority = priority;
|
thread->initial_priority = thread->current_priority = priority;
|
||||||
thread->processor_id = processor_id;
|
thread->processor_id = processor_id;
|
||||||
thread->wait_type = WAITTYPE_NONE;
|
thread->wait_type = WAITTYPE_NONE;
|
||||||
thread->wait_object = nullptr;
|
thread->wait_objects.clear();
|
||||||
thread->wait_address = 0;
|
thread->wait_address = 0;
|
||||||
thread->name = std::move(name);
|
thread->name = std::move(name);
|
||||||
|
|
||||||
@ -412,9 +426,8 @@ void Reschedule() {
|
|||||||
LOG_TRACE(Kernel, "cannot context switch from 0x%08X, no higher priority thread!", prev->GetHandle());
|
LOG_TRACE(Kernel, "cannot context switch from 0x%08X, no higher priority thread!", prev->GetHandle());
|
||||||
|
|
||||||
for (auto& thread : thread_list) {
|
for (auto& thread : thread_list) {
|
||||||
LOG_TRACE(Kernel, "\thandle=0x%08X prio=0x%02X, status=0x%08X wait_type=0x%08X wait_handle=0x%08X",
|
LOG_TRACE(Kernel, "\thandle=0x%08X prio=0x%02X, status=0x%08X wait_type=0x%08X",
|
||||||
thread->GetHandle(), thread->current_priority, thread->status, thread->wait_type,
|
thread->GetHandle(), thread->current_priority, thread->status, thread->wait_type);
|
||||||
(thread->wait_object ? thread->wait_object->GetHandle() : INVALID_HANDLE));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ public:
|
|||||||
s32 processor_id;
|
s32 processor_id;
|
||||||
|
|
||||||
WaitType wait_type;
|
WaitType wait_type;
|
||||||
Object* wait_object;
|
std::vector<SharedPtr<WaitObject>> wait_objects;
|
||||||
VAddr wait_address;
|
VAddr wait_address;
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
@ -128,7 +128,7 @@ Thread* GetCurrentThread();
|
|||||||
* @param wait_type Type of wait
|
* @param wait_type Type of wait
|
||||||
* @param wait_object Kernel object that we are waiting on, defaults to current thread
|
* @param wait_object Kernel object that we are waiting on, defaults to current thread
|
||||||
*/
|
*/
|
||||||
void WaitCurrentThread(WaitType wait_type, Object* wait_object = GetCurrentThread());
|
void WaitCurrentThread(WaitType wait_type, WaitObject* wait_object = GetCurrentThread());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Schedules an event to wake up the specified thread after the specified delay.
|
* Schedules an event to wake up the specified thread after the specified delay.
|
||||||
@ -143,7 +143,7 @@ void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds);
|
|||||||
* @param wait_object Kernel object that we are waiting on
|
* @param wait_object Kernel object that we are waiting on
|
||||||
* @param wait_address Arbitration address used to resume from wait
|
* @param wait_address Arbitration address used to resume from wait
|
||||||
*/
|
*/
|
||||||
void WaitCurrentThread(WaitType wait_type, Object* wait_object, VAddr wait_address);
|
void WaitCurrentThread(WaitType wait_type, WaitObject* wait_object, VAddr wait_address);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user