Browse Source
Kernel: Move WaitObject to a separate file
Kernel: Move WaitObject to a separate file
Now that HandleTable doesn't directly depend on WaitObject anymore, this can be separated from the main kernel.h header.nce_cpp
15 changed files with 178 additions and 135 deletions
-
1src/citra_qt/debugger/wait_tree.cpp
-
4src/citra_qt/debugger/wait_tree.h
-
2src/core/CMakeLists.txt
-
1src/core/hle/kernel/event.h
-
79src/core/hle/kernel/kernel.cpp
-
53src/core/hle/kernel/kernel.h
-
1src/core/hle/kernel/mutex.h
-
1src/core/hle/kernel/semaphore.h
-
1src/core/hle/kernel/server_port.h
-
1src/core/hle/kernel/server_session.h
-
1src/core/hle/kernel/thread.h
-
1src/core/hle/kernel/timer.h
-
99src/core/hle/kernel/wait_object.cpp
-
67src/core/hle/kernel/wait_object.h
-
1src/core/hle/svc.cpp
@ -0,0 +1,99 @@ |
|||
// Copyright 2014 Citra Emulator Project
|
|||
// Licensed under GPLv2 or any later version
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#include <algorithm>
|
|||
#include "common/assert.h"
|
|||
#include "common/logging/log.h"
|
|||
#include "core/hle/config_mem.h"
|
|||
#include "core/hle/kernel/errors.h"
|
|||
#include "core/hle/kernel/kernel.h"
|
|||
#include "core/hle/kernel/memory.h"
|
|||
#include "core/hle/kernel/process.h"
|
|||
#include "core/hle/kernel/resource_limit.h"
|
|||
#include "core/hle/kernel/thread.h"
|
|||
#include "core/hle/kernel/timer.h"
|
|||
#include "core/hle/shared_page.h"
|
|||
|
|||
namespace Kernel { |
|||
|
|||
void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) { |
|||
auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); |
|||
if (itr == waiting_threads.end()) |
|||
waiting_threads.push_back(std::move(thread)); |
|||
} |
|||
|
|||
void WaitObject::RemoveWaitingThread(Thread* thread) { |
|||
auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); |
|||
// If a thread passed multiple handles to the same object,
|
|||
// the kernel might attempt to remove the thread from the object's
|
|||
// waiting threads list multiple times.
|
|||
if (itr != waiting_threads.end()) |
|||
waiting_threads.erase(itr); |
|||
} |
|||
|
|||
SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() { |
|||
Thread* candidate = nullptr; |
|||
s32 candidate_priority = THREADPRIO_LOWEST + 1; |
|||
|
|||
for (const auto& thread : waiting_threads) { |
|||
// The list of waiting threads must not contain threads that are not waiting to be awakened.
|
|||
ASSERT_MSG(thread->status == THREADSTATUS_WAIT_SYNCH_ANY || |
|||
thread->status == THREADSTATUS_WAIT_SYNCH_ALL, |
|||
"Inconsistent thread statuses in waiting_threads"); |
|||
|
|||
if (thread->current_priority >= candidate_priority) |
|||
continue; |
|||
|
|||
if (ShouldWait(thread.get())) |
|||
continue; |
|||
|
|||
// A thread is ready to run if it's either in THREADSTATUS_WAIT_SYNCH_ANY or
|
|||
// in THREADSTATUS_WAIT_SYNCH_ALL and the rest of the objects it is waiting on are ready.
|
|||
bool ready_to_run = true; |
|||
if (thread->status == THREADSTATUS_WAIT_SYNCH_ALL) { |
|||
ready_to_run = std::none_of(thread->wait_objects.begin(), thread->wait_objects.end(), |
|||
[&thread](const SharedPtr<WaitObject>& object) { |
|||
return object->ShouldWait(thread.get()); |
|||
}); |
|||
} |
|||
|
|||
if (ready_to_run) { |
|||
candidate = thread.get(); |
|||
candidate_priority = thread->current_priority; |
|||
} |
|||
} |
|||
|
|||
return candidate; |
|||
} |
|||
|
|||
void WaitObject::WakeupAllWaitingThreads() { |
|||
while (auto thread = GetHighestPriorityReadyThread()) { |
|||
if (!thread->IsSleepingOnWaitAll()) { |
|||
Acquire(thread.get()); |
|||
// Set the output index of the WaitSynchronizationN call to the index of this object.
|
|||
if (thread->wait_set_output) { |
|||
thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(this)); |
|||
thread->wait_set_output = false; |
|||
} |
|||
} else { |
|||
for (auto& object : thread->wait_objects) { |
|||
object->Acquire(thread.get()); |
|||
} |
|||
// Note: This case doesn't update the output index of WaitSynchronizationN.
|
|||
} |
|||
|
|||
for (auto& object : thread->wait_objects) |
|||
object->RemoveWaitingThread(thread.get()); |
|||
thread->wait_objects.clear(); |
|||
|
|||
thread->SetWaitSynchronizationResult(RESULT_SUCCESS); |
|||
thread->ResumeFromWait(); |
|||
} |
|||
} |
|||
|
|||
const std::vector<SharedPtr<Thread>>& WaitObject::GetWaitingThreads() const { |
|||
return waiting_threads; |
|||
} |
|||
|
|||
} // namespace Kernel
|
|||
@ -0,0 +1,67 @@ |
|||
// Copyright 2014 Citra Emulator Project |
|||
// Licensed under GPLv2 or any later version |
|||
// Refer to the license.txt file included. |
|||
|
|||
#pragma once |
|||
|
|||
#include <vector> |
|||
#include <boost/smart_ptr/intrusive_ptr.hpp> |
|||
#include "common/common_types.h" |
|||
#include "core/hle/kernel/kernel.h" |
|||
|
|||
namespace Kernel { |
|||
|
|||
class Thread; |
|||
|
|||
/// Class that represents a Kernel object that a thread can be waiting on |
|||
class WaitObject : public Object { |
|||
public: |
|||
/** |
|||
* Check if the specified thread should wait until the object is available |
|||
* @param thread The thread about which we're deciding. |
|||
* @return True if the current thread should wait due to this object being unavailable |
|||
*/ |
|||
virtual bool ShouldWait(Thread* thread) const = 0; |
|||
|
|||
/// Acquire/lock the object for the specified thread if it is available |
|||
virtual void Acquire(Thread* thread) = 0; |
|||
|
|||
/** |
|||
* Add a thread to wait on this object |
|||
* @param thread Pointer to thread to add |
|||
*/ |
|||
virtual void AddWaitingThread(SharedPtr<Thread> thread); |
|||
|
|||
/** |
|||
* Removes a thread from waiting on this object (e.g. if it was resumed already) |
|||
* @param thread Pointer to thread to remove |
|||
*/ |
|||
virtual void RemoveWaitingThread(Thread* thread); |
|||
|
|||
/** |
|||
* Wake up all threads waiting on this object that can be awoken, in priority order, |
|||
* and set the synchronization result and output of the thread. |
|||
*/ |
|||
virtual void WakeupAllWaitingThreads(); |
|||
|
|||
/// Obtains the highest priority thread that is ready to run from this object's waiting list. |
|||
SharedPtr<Thread> GetHighestPriorityReadyThread(); |
|||
|
|||
/// Get a const reference to the waiting threads list for debug use |
|||
const std::vector<SharedPtr<Thread>>& GetWaitingThreads() const; |
|||
|
|||
private: |
|||
/// Threads waiting for this object to become available |
|||
std::vector<SharedPtr<Thread>> waiting_threads; |
|||
}; |
|||
|
|||
// Specialization of DynamicObjectCast for WaitObjects |
|||
template <> |
|||
inline SharedPtr<WaitObject> DynamicObjectCast<WaitObject>(SharedPtr<Object> object) { |
|||
if (object != nullptr && object->IsWaitable()) { |
|||
return boost::static_pointer_cast<WaitObject>(std::move(object)); |
|||
} |
|||
return nullptr; |
|||
} |
|||
|
|||
} // namespace Kernel |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue