| 
									
										
										
										
											2014-12-16 21:38:14 -08:00
										 |  |  | // Copyright 2014 Citra Emulator Project
 | 
					
						
							|  |  |  | // Licensed under GPLv2 or any later version
 | 
					
						
							| 
									
										
										
										
											2014-11-19 08:49:13 +00:00
										 |  |  | // Refer to the license.txt file included.
 | 
					
						
							| 
									
										
										
										
											2014-05-09 22:11:18 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  | #include <atomic>
 | 
					
						
							|  |  |  | #include <memory>
 | 
					
						
							|  |  |  | #include <mutex>
 | 
					
						
							|  |  |  | #include <utility>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "common/assert.h"
 | 
					
						
							|  |  |  | #include "common/logging/log.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "core/core.h"
 | 
					
						
							|  |  |  | #include "core/core_timing.h"
 | 
					
						
							| 
									
										
										
										
											2018-09-02 11:58:58 -04:00
										 |  |  | #include "core/hle/kernel/client_port.h"
 | 
					
						
							| 
									
										
										
										
											2017-05-29 16:45:42 -07:00
										 |  |  | #include "core/hle/kernel/handle_table.h"
 | 
					
						
							| 
									
										
										
										
											2016-09-20 23:52:38 -07:00
										 |  |  | #include "core/hle/kernel/kernel.h"
 | 
					
						
							| 
									
										
										
										
											2015-05-04 00:01:16 -03:00
										 |  |  | #include "core/hle/kernel/process.h"
 | 
					
						
							| 
									
										
										
										
											2015-08-05 21:26:52 -03:00
										 |  |  | #include "core/hle/kernel/resource_limit.h"
 | 
					
						
							| 
									
										
										
										
											2014-05-09 22:11:18 -04:00
										 |  |  | #include "core/hle/kernel/thread.h"
 | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  | #include "core/hle/lock.h"
 | 
					
						
							|  |  |  | #include "core/hle/result.h"
 | 
					
						
							| 
									
										
										
										
											2014-05-09 22:11:18 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-20 18:13:25 -04:00
										 |  |  | namespace Kernel { | 
					
						
							| 
									
										
										
										
											2014-05-09 22:11:18 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Callback that will wake up the thread it was scheduled for | 
					
						
							|  |  |  |  * @param thread_handle The handle of the thread that's been awoken | 
					
						
							|  |  |  |  * @param cycles_late The number of CPU cycles that have passed since the desired wakeup time | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] int cycles_late) { | 
					
						
							|  |  |  |     const auto proper_handle = static_cast<Handle>(thread_handle); | 
					
						
							| 
									
										
										
										
											2018-10-28 17:44:46 -04:00
										 |  |  |     const auto& system = Core::System::GetInstance(); | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Lock the global kernel mutex when we enter the kernel HLE.
 | 
					
						
							|  |  |  |     std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     SharedPtr<Thread> thread = | 
					
						
							|  |  |  |         system.Kernel().RetrieveThreadFromWakeupCallbackHandleTable(proper_handle); | 
					
						
							|  |  |  |     if (thread == nullptr) { | 
					
						
							|  |  |  |         LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", proper_handle); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool resume = true; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-03 18:47:57 -04:00
										 |  |  |     if (thread->GetStatus() == ThreadStatus::WaitSynchAny || | 
					
						
							|  |  |  |         thread->GetStatus() == ThreadStatus::WaitSynchAll || | 
					
						
							|  |  |  |         thread->GetStatus() == ThreadStatus::WaitHLEEvent) { | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  |         // Remove the thread from each of its waiting objects' waitlists
 | 
					
						
							| 
									
										
										
										
											2018-10-03 18:47:57 -04:00
										 |  |  |         for (const auto& object : thread->GetWaitObjects()) { | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  |             object->RemoveWaitingThread(thread.get()); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-10-03 18:47:57 -04:00
										 |  |  |         thread->ClearWaitObjects(); | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // Invoke the wakeup callback before clearing the wait objects
 | 
					
						
							| 
									
										
										
										
											2018-10-03 18:47:57 -04:00
										 |  |  |         if (thread->HasWakeupCallback()) { | 
					
						
							|  |  |  |             resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Timeout, thread, nullptr, 0); | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-03 18:47:57 -04:00
										 |  |  |     if (thread->GetMutexWaitAddress() != 0 || thread->GetCondVarWaitAddress() != 0 || | 
					
						
							|  |  |  |         thread->GetWaitHandle() != 0) { | 
					
						
							|  |  |  |         ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex); | 
					
						
							|  |  |  |         thread->SetMutexWaitAddress(0); | 
					
						
							|  |  |  |         thread->SetCondVarWaitAddress(0); | 
					
						
							|  |  |  |         thread->SetWaitHandle(0); | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-03 18:47:57 -04:00
										 |  |  |         auto* const lock_owner = thread->GetLockOwner(); | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  |         // Threads waking up by timeout from WaitProcessWideKey do not perform priority inheritance
 | 
					
						
							|  |  |  |         // and don't have a lock owner unless SignalProcessWideKey was called first and the thread
 | 
					
						
							|  |  |  |         // wasn't awakened due to the mutex already being acquired.
 | 
					
						
							| 
									
										
										
										
											2018-10-03 18:47:57 -04:00
										 |  |  |         if (lock_owner != nullptr) { | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  |             lock_owner->RemoveMutexWaiter(thread); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-03 18:47:57 -04:00
										 |  |  |     if (thread->GetArbiterWaitAddress() != 0) { | 
					
						
							|  |  |  |         ASSERT(thread->GetStatus() == ThreadStatus::WaitArb); | 
					
						
							|  |  |  |         thread->SetArbiterWaitAddress(0); | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (resume) { | 
					
						
							|  |  |  |         thread->ResumeFromWait(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct KernelCore::Impl { | 
					
						
							| 
									
										
										
										
											2019-02-14 12:42:58 -05:00
										 |  |  |     void Initialize(KernelCore& kernel, Core::Timing::CoreTiming& core_timing) { | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  |         Shutdown(); | 
					
						
							| 
									
										
										
										
											2015-04-27 22:12:35 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-19 12:54:06 -05:00
										 |  |  |         InitializeSystemResourceLimit(kernel); | 
					
						
							| 
									
										
										
										
											2019-02-14 12:42:58 -05:00
										 |  |  |         InitializeThreads(core_timing); | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void Shutdown() { | 
					
						
							|  |  |  |         next_object_id = 0; | 
					
						
							| 
									
										
										
										
											2018-12-18 22:53:58 -05:00
										 |  |  |         next_process_id = Process::ProcessIDMin; | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  |         next_thread_id = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         process_list.clear(); | 
					
						
							| 
									
										
										
										
											2018-10-10 00:42:10 -04:00
										 |  |  |         current_process = nullptr; | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-19 12:54:06 -05:00
										 |  |  |         system_resource_limit = nullptr; | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |         thread_wakeup_callback_handle_table.Clear(); | 
					
						
							|  |  |  |         thread_wakeup_event_type = nullptr; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-02 11:58:58 -04:00
										 |  |  |         named_ports.clear(); | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-19 12:54:06 -05:00
										 |  |  |     // Creates the default system resource limit
 | 
					
						
							|  |  |  |     void InitializeSystemResourceLimit(KernelCore& kernel) { | 
					
						
							|  |  |  |         system_resource_limit = ResourceLimit::Create(kernel, "System"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // If setting the default system values fails, then something seriously wrong has occurred.
 | 
					
						
							|  |  |  |         ASSERT(system_resource_limit->SetLimitValue(ResourceType::PhysicalMemory, 0x200000000) | 
					
						
							|  |  |  |                    .IsSuccess()); | 
					
						
							|  |  |  |         ASSERT(system_resource_limit->SetLimitValue(ResourceType::Threads, 800).IsSuccess()); | 
					
						
							|  |  |  |         ASSERT(system_resource_limit->SetLimitValue(ResourceType::Events, 700).IsSuccess()); | 
					
						
							|  |  |  |         ASSERT(system_resource_limit->SetLimitValue(ResourceType::TransferMemory, 200).IsSuccess()); | 
					
						
							|  |  |  |         ASSERT(system_resource_limit->SetLimitValue(ResourceType::Sessions, 900).IsSuccess()); | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-14 12:42:58 -05:00
										 |  |  |     void InitializeThreads(Core::Timing::CoreTiming& core_timing) { | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  |         thread_wakeup_event_type = | 
					
						
							| 
									
										
										
										
											2019-02-14 12:42:58 -05:00
										 |  |  |             core_timing.RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback); | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     std::atomic<u32> next_object_id{0}; | 
					
						
							| 
									
										
										
										
											2018-12-18 22:53:58 -05:00
										 |  |  |     std::atomic<u64> next_process_id{Process::ProcessIDMin}; | 
					
						
							| 
									
										
										
										
											2018-12-18 22:37:01 -05:00
										 |  |  |     std::atomic<u64> next_thread_id{1}; | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Lists all processes that exist in the current session.
 | 
					
						
							|  |  |  |     std::vector<SharedPtr<Process>> process_list; | 
					
						
							| 
									
										
										
										
											2018-10-10 00:42:10 -04:00
										 |  |  |     Process* current_process = nullptr; | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-19 12:54:06 -05:00
										 |  |  |     SharedPtr<ResourceLimit> system_resource_limit; | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-12 12:32:15 -05:00
										 |  |  |     Core::Timing::EventType* thread_wakeup_event_type = nullptr; | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  |     // TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future,
 | 
					
						
							|  |  |  |     // allowing us to simply use a pool index or similar.
 | 
					
						
							|  |  |  |     Kernel::HandleTable thread_wakeup_callback_handle_table; | 
					
						
							| 
									
										
										
										
											2018-09-02 11:58:58 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /// Map of named ports managed by the kernel, which can be retrieved using
 | 
					
						
							|  |  |  |     /// the ConnectToPort SVC.
 | 
					
						
							|  |  |  |     NamedPortTable named_ports; | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | KernelCore::KernelCore() : impl{std::make_unique<Impl>()} {} | 
					
						
							|  |  |  | KernelCore::~KernelCore() { | 
					
						
							|  |  |  |     Shutdown(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-14 12:42:58 -05:00
										 |  |  | void KernelCore::Initialize(Core::Timing::CoreTiming& core_timing) { | 
					
						
							|  |  |  |     impl->Initialize(*this, core_timing); | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void KernelCore::Shutdown() { | 
					
						
							|  |  |  |     impl->Shutdown(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-19 12:54:06 -05:00
										 |  |  | SharedPtr<ResourceLimit> KernelCore::GetSystemResourceLimit() const { | 
					
						
							|  |  |  |     return impl->system_resource_limit; | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | SharedPtr<Thread> KernelCore::RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const { | 
					
						
							|  |  |  |     return impl->thread_wakeup_callback_handle_table.Get<Thread>(handle); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void KernelCore::AppendNewProcess(SharedPtr<Process> process) { | 
					
						
							|  |  |  |     impl->process_list.push_back(std::move(process)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-10 00:42:10 -04:00
										 |  |  | void KernelCore::MakeCurrentProcess(Process* process) { | 
					
						
							|  |  |  |     impl->current_process = process; | 
					
						
							| 
									
										
										
										
											2018-09-06 20:34:51 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-10 00:42:10 -04:00
										 |  |  | Process* KernelCore::CurrentProcess() { | 
					
						
							| 
									
										
										
										
											2018-09-06 20:34:51 -04:00
										 |  |  |     return impl->current_process; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-10 00:42:10 -04:00
										 |  |  | const Process* KernelCore::CurrentProcess() const { | 
					
						
							| 
									
										
										
										
											2018-09-06 20:34:51 -04:00
										 |  |  |     return impl->current_process; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-02 11:58:58 -04:00
										 |  |  | void KernelCore::AddNamedPort(std::string name, SharedPtr<ClientPort> port) { | 
					
						
							|  |  |  |     impl->named_ports.emplace(std::move(name), std::move(port)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | KernelCore::NamedPortTable::iterator KernelCore::FindNamedPort(const std::string& name) { | 
					
						
							|  |  |  |     return impl->named_ports.find(name); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | KernelCore::NamedPortTable::const_iterator KernelCore::FindNamedPort( | 
					
						
							|  |  |  |     const std::string& name) const { | 
					
						
							|  |  |  |     return impl->named_ports.find(name); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool KernelCore::IsValidNamedPort(NamedPortTable::const_iterator port) const { | 
					
						
							|  |  |  |     return port != impl->named_ports.cend(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  | u32 KernelCore::CreateNewObjectID() { | 
					
						
							|  |  |  |     return impl->next_object_id++; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-18 22:37:01 -05:00
										 |  |  | u64 KernelCore::CreateNewThreadID() { | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  |     return impl->next_thread_id++; | 
					
						
							| 
									
										
										
										
											2014-05-20 18:13:25 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-18 22:16:53 -05:00
										 |  |  | u64 KernelCore::CreateNewProcessID() { | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  |     return impl->next_process_id++; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-08-05 21:26:52 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-12 12:32:15 -05:00
										 |  |  | Core::Timing::EventType* KernelCore::ThreadWakeupCallbackEventType() const { | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  |     return impl->thread_wakeup_event_type; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Kernel::HandleTable& KernelCore::ThreadWakeupCallbackHandleTable() { | 
					
						
							|  |  |  |     return impl->thread_wakeup_callback_handle_table; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-08-05 21:26:52 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-28 12:30:33 -04:00
										 |  |  | const Kernel::HandleTable& KernelCore::ThreadWakeupCallbackHandleTable() const { | 
					
						
							|  |  |  |     return impl->thread_wakeup_callback_handle_table; | 
					
						
							| 
									
										
										
										
											2014-05-13 21:57:12 -04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-05-22 19:06:12 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-01 13:25:37 -05:00
										 |  |  | } // namespace Kernel
 |