mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	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.
This commit is contained in:
		
							parent
							
								
									9453223075
								
							
						
					
					
						commit
						64ecf81a3c
					
				
					 15 changed files with 178 additions and 135 deletions
				
			
		|  | @ -10,6 +10,7 @@ | |||
| #include "core/hle/kernel/semaphore.h" | ||||
| #include "core/hle/kernel/thread.h" | ||||
| #include "core/hle/kernel/timer.h" | ||||
| #include "core/hle/kernel/wait_object.h" | ||||
| 
 | ||||
| WaitTreeItem::~WaitTreeItem() {} | ||||
| 
 | ||||
|  |  | |||
|  | @ -4,12 +4,10 @@ | |||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <boost/container/flat_set.hpp> | ||||
| 
 | ||||
| #include <QAbstractItemModel> | ||||
| #include <QDockWidget> | ||||
| #include <QTreeView> | ||||
| 
 | ||||
| #include <boost/container/flat_set.hpp> | ||||
| #include "core/core.h" | ||||
| #include "core/hle/kernel/kernel.h" | ||||
| 
 | ||||
|  |  | |||
|  | @ -57,6 +57,7 @@ set(SRCS | |||
|             hle/kernel/thread.cpp | ||||
|             hle/kernel/timer.cpp | ||||
|             hle/kernel/vm_manager.cpp | ||||
|             hle/kernel/wait_object.cpp | ||||
|             hle/service/ac/ac.cpp | ||||
|             hle/service/ac/ac_i.cpp | ||||
|             hle/service/ac/ac_u.cpp | ||||
|  | @ -249,6 +250,7 @@ set(HEADERS | |||
|             hle/kernel/thread.h | ||||
|             hle/kernel/timer.h | ||||
|             hle/kernel/vm_manager.h | ||||
|             hle/kernel/wait_object.h | ||||
|             hle/result.h | ||||
|             hle/service/ac/ac.h | ||||
|             hle/service/ac/ac_i.h | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ | |||
| 
 | ||||
| #include "common/common_types.h" | ||||
| #include "core/hle/kernel/kernel.h" | ||||
| #include "core/hle/kernel/wait_object.h" | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
|  |  | |||
|  | @ -20,85 +20,6 @@ namespace Kernel { | |||
| unsigned int Object::next_object_id; | ||||
| HandleTable g_handle_table; | ||||
| 
 | ||||
| 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; | ||||
| } | ||||
| 
 | ||||
| HandleTable::HandleTable() { | ||||
|     next_generation = 1; | ||||
|     Clear(); | ||||
|  |  | |||
|  | @ -17,8 +17,6 @@ namespace Kernel { | |||
| 
 | ||||
| using Handle = u32; | ||||
| 
 | ||||
| class Thread; | ||||
| 
 | ||||
| enum KernelHandle : Handle { | ||||
|     CurrentThread = 0xFFFF8000, | ||||
|     CurrentProcess = 0xFFFF8001, | ||||
|  | @ -133,57 +131,6 @@ inline SharedPtr<T> DynamicObjectCast(SharedPtr<Object> object) { | |||
|     return nullptr; | ||||
| } | ||||
| 
 | ||||
| /// 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; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * This class allows the creation of Handles, which are references to objects that can be tested | ||||
|  * for validity and looked up. Here they are used to pass references to kernel objects to/from the | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ | |||
| #include <string> | ||||
| #include "common/common_types.h" | ||||
| #include "core/hle/kernel/kernel.h" | ||||
| #include "core/hle/kernel/wait_object.h" | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
|  |  | |||
|  | @ -8,6 +8,7 @@ | |||
| #include <string> | ||||
| #include "common/common_types.h" | ||||
| #include "core/hle/kernel/kernel.h" | ||||
| #include "core/hle/kernel/wait_object.h" | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ | |||
| #include <tuple> | ||||
| #include "common/common_types.h" | ||||
| #include "core/hle/kernel/kernel.h" | ||||
| #include "core/hle/kernel/wait_object.h" | ||||
| 
 | ||||
| namespace Service { | ||||
| class SessionRequestHandler; | ||||
|  |  | |||
|  | @ -11,6 +11,7 @@ | |||
| #include "core/hle/kernel/kernel.h" | ||||
| #include "core/hle/kernel/session.h" | ||||
| #include "core/hle/kernel/thread.h" | ||||
| #include "core/hle/kernel/wait_object.h" | ||||
| #include "core/hle/result.h" | ||||
| #include "core/hle/service/service.h" | ||||
| #include "core/memory.h" | ||||
|  |  | |||
|  | @ -12,6 +12,7 @@ | |||
| #include "common/common_types.h" | ||||
| #include "core/arm/arm_interface.h" | ||||
| #include "core/hle/kernel/kernel.h" | ||||
| #include "core/hle/kernel/wait_object.h" | ||||
| #include "core/hle/result.h" | ||||
| 
 | ||||
| enum ThreadPriority : s32 { | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ | |||
| 
 | ||||
| #include "common/common_types.h" | ||||
| #include "core/hle/kernel/kernel.h" | ||||
| #include "core/hle/kernel/wait_object.h" | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										99
									
								
								src/core/hle/kernel/wait_object.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								src/core/hle/kernel/wait_object.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -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
 | ||||
							
								
								
									
										67
									
								
								src/core/hle/kernel/wait_object.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								src/core/hle/kernel/wait_object.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -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
 | ||||
|  | @ -27,6 +27,7 @@ | |||
| #include "core/hle/kernel/thread.h" | ||||
| #include "core/hle/kernel/timer.h" | ||||
| #include "core/hle/kernel/vm_manager.h" | ||||
| #include "core/hle/kernel/wait_object.h" | ||||
| #include "core/hle/result.h" | ||||
| #include "core/hle/service/service.h" | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue