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