diff options
Diffstat (limited to '')
23 files changed, 212 insertions, 80 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 052907f08..26612e692 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -183,6 +183,8 @@ add_library(core STATIC | |||
| 183 | hle/kernel/svc_wrap.h | 183 | hle/kernel/svc_wrap.h |
| 184 | hle/kernel/synchronization_object.cpp | 184 | hle/kernel/synchronization_object.cpp |
| 185 | hle/kernel/synchronization_object.h | 185 | hle/kernel/synchronization_object.h |
| 186 | hle/kernel/synchronization.cpp | ||
| 187 | hle/kernel/synchronization.h | ||
| 186 | hle/kernel/thread.cpp | 188 | hle/kernel/thread.cpp |
| 187 | hle/kernel/thread.h | 189 | hle/kernel/thread.h |
| 188 | hle/kernel/transfer_memory.cpp | 190 | hle/kernel/transfer_memory.cpp |
diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index 3dfeb9813..6d66276bc 100644 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp | |||
| @@ -31,6 +31,11 @@ void ClientSession::Acquire(Thread* thread) { | |||
| 31 | UNIMPLEMENTED(); | 31 | UNIMPLEMENTED(); |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | bool ClientSession::IsSignaled() const { | ||
| 35 | UNIMPLEMENTED(); | ||
| 36 | return true; | ||
| 37 | } | ||
| 38 | |||
| 34 | ResultVal<std::shared_ptr<ClientSession>> ClientSession::Create(KernelCore& kernel, | 39 | ResultVal<std::shared_ptr<ClientSession>> ClientSession::Create(KernelCore& kernel, |
| 35 | std::shared_ptr<Session> parent, | 40 | std::shared_ptr<Session> parent, |
| 36 | std::string name) { | 41 | std::string name) { |
diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h index 9cf9219b1..d15b09554 100644 --- a/src/core/hle/kernel/client_session.h +++ b/src/core/hle/kernel/client_session.h | |||
| @@ -48,6 +48,8 @@ public: | |||
| 48 | 48 | ||
| 49 | void Acquire(Thread* thread) override; | 49 | void Acquire(Thread* thread) override; |
| 50 | 50 | ||
| 51 | bool IsSignaled() const override; | ||
| 52 | |||
| 51 | private: | 53 | private: |
| 52 | static ResultVal<std::shared_ptr<ClientSession>> Create(KernelCore& kernel, | 54 | static ResultVal<std::shared_ptr<ClientSession>> Create(KernelCore& kernel, |
| 53 | std::shared_ptr<Session> parent, | 55 | std::shared_ptr<Session> parent, |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 26799f6b5..4eb1d8703 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include "core/hle/kernel/process.h" | 23 | #include "core/hle/kernel/process.h" |
| 24 | #include "core/hle/kernel/resource_limit.h" | 24 | #include "core/hle/kernel/resource_limit.h" |
| 25 | #include "core/hle/kernel/scheduler.h" | 25 | #include "core/hle/kernel/scheduler.h" |
| 26 | #include "core/hle/kernel/synchronization.h" | ||
| 26 | #include "core/hle/kernel/thread.h" | 27 | #include "core/hle/kernel/thread.h" |
| 27 | #include "core/hle/lock.h" | 28 | #include "core/hle/lock.h" |
| 28 | #include "core/hle/result.h" | 29 | #include "core/hle/result.h" |
| @@ -96,7 +97,8 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_ | |||
| 96 | } | 97 | } |
| 97 | 98 | ||
| 98 | struct KernelCore::Impl { | 99 | struct KernelCore::Impl { |
| 99 | explicit Impl(Core::System& system) : system{system}, global_scheduler{system} {} | 100 | explicit Impl(Core::System& system) |
| 101 | : system{system}, global_scheduler{system}, synchronization{system} {} | ||
| 100 | 102 | ||
| 101 | void Initialize(KernelCore& kernel) { | 103 | void Initialize(KernelCore& kernel) { |
| 102 | Shutdown(); | 104 | Shutdown(); |
| @@ -191,6 +193,7 @@ struct KernelCore::Impl { | |||
| 191 | std::vector<std::shared_ptr<Process>> process_list; | 193 | std::vector<std::shared_ptr<Process>> process_list; |
| 192 | Process* current_process = nullptr; | 194 | Process* current_process = nullptr; |
| 193 | Kernel::GlobalScheduler global_scheduler; | 195 | Kernel::GlobalScheduler global_scheduler; |
| 196 | Kernel::Synchronization synchronization; | ||
| 194 | 197 | ||
| 195 | std::shared_ptr<ResourceLimit> system_resource_limit; | 198 | std::shared_ptr<ResourceLimit> system_resource_limit; |
| 196 | 199 | ||
| @@ -270,6 +273,14 @@ const Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) const { | |||
| 270 | return impl->cores[id]; | 273 | return impl->cores[id]; |
| 271 | } | 274 | } |
| 272 | 275 | ||
| 276 | Kernel::Synchronization& KernelCore::Synchronization() { | ||
| 277 | return impl->synchronization; | ||
| 278 | } | ||
| 279 | |||
| 280 | const Kernel::Synchronization& KernelCore::Synchronization() const { | ||
| 281 | return impl->synchronization; | ||
| 282 | } | ||
| 283 | |||
| 273 | Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() { | 284 | Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() { |
| 274 | return *impl->exclusive_monitor; | 285 | return *impl->exclusive_monitor; |
| 275 | } | 286 | } |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index fccffaf3a..1eede3063 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -29,6 +29,7 @@ class HandleTable; | |||
| 29 | class PhysicalCore; | 29 | class PhysicalCore; |
| 30 | class Process; | 30 | class Process; |
| 31 | class ResourceLimit; | 31 | class ResourceLimit; |
| 32 | class Synchronization; | ||
| 32 | class Thread; | 33 | class Thread; |
| 33 | 34 | ||
| 34 | /// Represents a single instance of the kernel. | 35 | /// Represents a single instance of the kernel. |
| @@ -92,6 +93,12 @@ public: | |||
| 92 | /// Gets the an instance of the respective physical CPU core. | 93 | /// Gets the an instance of the respective physical CPU core. |
| 93 | const Kernel::PhysicalCore& PhysicalCore(std::size_t id) const; | 94 | const Kernel::PhysicalCore& PhysicalCore(std::size_t id) const; |
| 94 | 95 | ||
| 96 | /// Gets the an instance of the Synchronization Interface. | ||
| 97 | Kernel::Synchronization& Synchronization(); | ||
| 98 | |||
| 99 | /// Gets the an instance of the Synchronization Interface. | ||
| 100 | const Kernel::Synchronization& Synchronization() const; | ||
| 101 | |||
| 95 | /// Stops execution of 'id' core, in order to reschedule a new thread. | 102 | /// Stops execution of 'id' core, in order to reschedule a new thread. |
| 96 | void PrepareReschedule(std::size_t id); | 103 | void PrepareReschedule(std::size_t id); |
| 97 | 104 | ||
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 7a616435a..2fcb7326c 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp | |||
| @@ -357,7 +357,7 @@ void Process::ChangeStatus(ProcessStatus new_status) { | |||
| 357 | 357 | ||
| 358 | status = new_status; | 358 | status = new_status; |
| 359 | is_signaled = true; | 359 | is_signaled = true; |
| 360 | WakeupAllWaitingThreads(); | 360 | Signal(); |
| 361 | } | 361 | } |
| 362 | 362 | ||
| 363 | void Process::AllocateMainThreadStack(u64 stack_size) { | 363 | void Process::AllocateMainThreadStack(u64 stack_size) { |
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 7b64c564a..4887132a7 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h | |||
| @@ -359,10 +359,6 @@ private: | |||
| 359 | /// specified by metadata provided to the process during loading. | 359 | /// specified by metadata provided to the process during loading. |
| 360 | bool is_64bit_process = true; | 360 | bool is_64bit_process = true; |
| 361 | 361 | ||
| 362 | /// Whether or not this process is signaled. This occurs | ||
| 363 | /// upon the process changing to a different state. | ||
| 364 | bool is_signaled = false; | ||
| 365 | |||
| 366 | /// Total running time for the process in ticks. | 362 | /// Total running time for the process in ticks. |
| 367 | u64 total_process_running_time_ticks = 0; | 363 | u64 total_process_running_time_ticks = 0; |
| 368 | 364 | ||
diff --git a/src/core/hle/kernel/readable_event.cpp b/src/core/hle/kernel/readable_event.cpp index 8ab796ba8..9d3d3a81b 100644 --- a/src/core/hle/kernel/readable_event.cpp +++ b/src/core/hle/kernel/readable_event.cpp | |||
| @@ -15,26 +15,26 @@ ReadableEvent::ReadableEvent(KernelCore& kernel) : SynchronizationObject{kernel} | |||
| 15 | ReadableEvent::~ReadableEvent() = default; | 15 | ReadableEvent::~ReadableEvent() = default; |
| 16 | 16 | ||
| 17 | bool ReadableEvent::ShouldWait(const Thread* thread) const { | 17 | bool ReadableEvent::ShouldWait(const Thread* thread) const { |
| 18 | return !signaled; | 18 | return !is_signaled; |
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | void ReadableEvent::Acquire(Thread* thread) { | 21 | void ReadableEvent::Acquire(Thread* thread) { |
| 22 | ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); | 22 | ASSERT_MSG(IsSignaled(), "object unavailable!"); |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | void ReadableEvent::Signal() { | 25 | void ReadableEvent::Signal() { |
| 26 | if (!signaled) { | 26 | if (!is_signaled) { |
| 27 | signaled = true; | 27 | is_signaled = true; |
| 28 | WakeupAllWaitingThreads(); | 28 | SynchronizationObject::Signal(); |
| 29 | }; | 29 | }; |
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | void ReadableEvent::Clear() { | 32 | void ReadableEvent::Clear() { |
| 33 | signaled = false; | 33 | is_signaled = false; |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | ResultCode ReadableEvent::Reset() { | 36 | ResultCode ReadableEvent::Reset() { |
| 37 | if (!signaled) { | 37 | if (!is_signaled) { |
| 38 | return ERR_INVALID_STATE; | 38 | return ERR_INVALID_STATE; |
| 39 | } | 39 | } |
| 40 | 40 | ||
diff --git a/src/core/hle/kernel/readable_event.h b/src/core/hle/kernel/readable_event.h index c7b0d6add..3264dd066 100644 --- a/src/core/hle/kernel/readable_event.h +++ b/src/core/hle/kernel/readable_event.h | |||
| @@ -46,13 +46,11 @@ public: | |||
| 46 | /// then ERR_INVALID_STATE will be returned. | 46 | /// then ERR_INVALID_STATE will be returned. |
| 47 | ResultCode Reset(); | 47 | ResultCode Reset(); |
| 48 | 48 | ||
| 49 | void Signal() override; | ||
| 50 | |||
| 49 | private: | 51 | private: |
| 50 | explicit ReadableEvent(KernelCore& kernel); | 52 | explicit ReadableEvent(KernelCore& kernel); |
| 51 | 53 | ||
| 52 | void Signal(); | ||
| 53 | |||
| 54 | bool signaled{}; | ||
| 55 | |||
| 56 | std::string name; ///< Name of event (optional) | 54 | std::string name; ///< Name of event (optional) |
| 57 | }; | 55 | }; |
| 58 | 56 | ||
diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp index 4f02f8df2..a549ae9d7 100644 --- a/src/core/hle/kernel/server_port.cpp +++ b/src/core/hle/kernel/server_port.cpp | |||
| @@ -39,6 +39,10 @@ void ServerPort::Acquire(Thread* thread) { | |||
| 39 | ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); | 39 | ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | bool ServerPort::IsSignaled() const { | ||
| 43 | return !pending_sessions.empty(); | ||
| 44 | } | ||
| 45 | |||
| 42 | ServerPort::PortPair ServerPort::CreatePortPair(KernelCore& kernel, u32 max_sessions, | 46 | ServerPort::PortPair ServerPort::CreatePortPair(KernelCore& kernel, u32 max_sessions, |
| 43 | std::string name) { | 47 | std::string name) { |
| 44 | std::shared_ptr<ServerPort> server_port = std::make_shared<ServerPort>(kernel); | 48 | std::shared_ptr<ServerPort> server_port = std::make_shared<ServerPort>(kernel); |
diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h index 43cf3ae18..41b191b86 100644 --- a/src/core/hle/kernel/server_port.h +++ b/src/core/hle/kernel/server_port.h | |||
| @@ -82,6 +82,8 @@ public: | |||
| 82 | bool ShouldWait(const Thread* thread) const override; | 82 | bool ShouldWait(const Thread* thread) const override; |
| 83 | void Acquire(Thread* thread) override; | 83 | void Acquire(Thread* thread) override; |
| 84 | 84 | ||
| 85 | bool IsSignaled() const override; | ||
| 86 | |||
| 85 | private: | 87 | private: |
| 86 | /// ServerSessions waiting to be accepted by the port | 88 | /// ServerSessions waiting to be accepted by the port |
| 87 | std::vector<std::shared_ptr<ServerSession>> pending_sessions; | 89 | std::vector<std::shared_ptr<ServerSession>> pending_sessions; |
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 8207f71c3..ca98fd984 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp | |||
| @@ -50,6 +50,16 @@ bool ServerSession::ShouldWait(const Thread* thread) const { | |||
| 50 | return pending_requesting_threads.empty() || currently_handling != nullptr; | 50 | return pending_requesting_threads.empty() || currently_handling != nullptr; |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | bool ServerSession::IsSignaled() const { | ||
| 54 | // Closed sessions should never wait, an error will be returned from svcReplyAndReceive. | ||
| 55 | if (!parent->Client()) { | ||
| 56 | return true; | ||
| 57 | } | ||
| 58 | |||
| 59 | // Wait if we have no pending requests, or if we're currently handling a request. | ||
| 60 | return !(pending_requesting_threads.empty() || currently_handling != nullptr); | ||
| 61 | } | ||
| 62 | |||
| 53 | void ServerSession::Acquire(Thread* thread) { | 63 | void ServerSession::Acquire(Thread* thread) { |
| 54 | ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); | 64 | ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); |
| 55 | // We are now handling a request, pop it from the stack. | 65 | // We are now handling a request, pop it from the stack. |
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index 3688c7d11..77e4f6721 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h | |||
| @@ -73,6 +73,8 @@ public: | |||
| 73 | return parent.get(); | 73 | return parent.get(); |
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | bool IsSignaled() const override; | ||
| 77 | |||
| 76 | /** | 78 | /** |
| 77 | * Sets the HLE handler for the session. This handler will be called to service IPC requests | 79 | * Sets the HLE handler for the session. This handler will be called to service IPC requests |
| 78 | * instead of the regular IPC machinery. (The regular IPC machinery is currently not | 80 | * instead of the regular IPC machinery. (The regular IPC machinery is currently not |
diff --git a/src/core/hle/kernel/session.cpp b/src/core/hle/kernel/session.cpp index 1c1fc440d..e4dd53e24 100644 --- a/src/core/hle/kernel/session.cpp +++ b/src/core/hle/kernel/session.cpp | |||
| @@ -29,6 +29,11 @@ bool Session::ShouldWait(const Thread* thread) const { | |||
| 29 | return {}; | 29 | return {}; |
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | bool Session::IsSignaled() const { | ||
| 33 | UNIMPLEMENTED(); | ||
| 34 | return true; | ||
| 35 | } | ||
| 36 | |||
| 32 | void Session::Acquire(Thread* thread) { | 37 | void Session::Acquire(Thread* thread) { |
| 33 | UNIMPLEMENTED(); | 38 | UNIMPLEMENTED(); |
| 34 | } | 39 | } |
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h index d107dd9aa..7cd9c0d77 100644 --- a/src/core/hle/kernel/session.h +++ b/src/core/hle/kernel/session.h | |||
| @@ -39,6 +39,8 @@ public: | |||
| 39 | 39 | ||
| 40 | bool ShouldWait(const Thread* thread) const override; | 40 | bool ShouldWait(const Thread* thread) const override; |
| 41 | 41 | ||
| 42 | bool IsSignaled() const override; | ||
| 43 | |||
| 42 | void Acquire(Thread* thread) override; | 44 | void Acquire(Thread* thread) override; |
| 43 | 45 | ||
| 44 | std::shared_ptr<ClientSession> Client() { | 46 | std::shared_ptr<ClientSession> Client() { |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 39552a176..86c660cdf 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -32,6 +32,7 @@ | |||
| 32 | #include "core/hle/kernel/shared_memory.h" | 32 | #include "core/hle/kernel/shared_memory.h" |
| 33 | #include "core/hle/kernel/svc.h" | 33 | #include "core/hle/kernel/svc.h" |
| 34 | #include "core/hle/kernel/svc_wrap.h" | 34 | #include "core/hle/kernel/svc_wrap.h" |
| 35 | #include "core/hle/kernel/synchronization.h" | ||
| 35 | #include "core/hle/kernel/thread.h" | 36 | #include "core/hle/kernel/thread.h" |
| 36 | #include "core/hle/kernel/transfer_memory.h" | 37 | #include "core/hle/kernel/transfer_memory.h" |
| 37 | #include "core/hle/kernel/writable_event.h" | 38 | #include "core/hle/kernel/writable_event.h" |
| @@ -433,23 +434,6 @@ static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle han | |||
| 433 | return ERR_INVALID_HANDLE; | 434 | return ERR_INVALID_HANDLE; |
| 434 | } | 435 | } |
| 435 | 436 | ||
| 436 | /// Default thread wakeup callback for WaitSynchronization | ||
| 437 | static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread, | ||
| 438 | std::shared_ptr<SynchronizationObject> object, | ||
| 439 | std::size_t index) { | ||
| 440 | ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch); | ||
| 441 | |||
| 442 | if (reason == ThreadWakeupReason::Timeout) { | ||
| 443 | thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); | ||
| 444 | return true; | ||
| 445 | } | ||
| 446 | |||
| 447 | ASSERT(reason == ThreadWakeupReason::Signal); | ||
| 448 | thread->SetWaitSynchronizationResult(RESULT_SUCCESS); | ||
| 449 | thread->SetWaitSynchronizationOutput(static_cast<u32>(index)); | ||
| 450 | return true; | ||
| 451 | }; | ||
| 452 | |||
| 453 | /// Wait for the given handles to synchronize, timeout after the specified nanoseconds | 437 | /// Wait for the given handles to synchronize, timeout after the specified nanoseconds |
| 454 | static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr handles_address, | 438 | static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr handles_address, |
| 455 | u64 handle_count, s64 nano_seconds) { | 439 | u64 handle_count, s64 nano_seconds) { |
| @@ -473,10 +457,10 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr | |||
| 473 | } | 457 | } |
| 474 | 458 | ||
| 475 | auto* const thread = system.CurrentScheduler().GetCurrentThread(); | 459 | auto* const thread = system.CurrentScheduler().GetCurrentThread(); |
| 476 | 460 | auto& kernel = system.Kernel(); | |
| 477 | using ObjectPtr = Thread::ThreadSynchronizationObjects::value_type; | 461 | using ObjectPtr = Thread::ThreadSynchronizationObjects::value_type; |
| 478 | Thread::ThreadSynchronizationObjects objects(handle_count); | 462 | Thread::ThreadSynchronizationObjects objects(handle_count); |
| 479 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 463 | const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); |
| 480 | 464 | ||
| 481 | for (u64 i = 0; i < handle_count; ++i) { | 465 | for (u64 i = 0; i < handle_count; ++i) { |
| 482 | const Handle handle = memory.Read32(handles_address + i * sizeof(Handle)); | 466 | const Handle handle = memory.Read32(handles_address + i * sizeof(Handle)); |
| @@ -489,47 +473,10 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr | |||
| 489 | 473 | ||
| 490 | objects[i] = object; | 474 | objects[i] = object; |
| 491 | } | 475 | } |
| 492 | 476 | auto& synchronization = kernel.Synchronization(); | |
| 493 | // Find the first object that is acquirable in the provided list of objects | 477 | auto [result, handle_result] = synchronization.WaitFor(objects, nano_seconds); |
| 494 | auto itr = std::find_if(objects.begin(), objects.end(), [thread](const ObjectPtr& object) { | 478 | *index = handle_result; |
| 495 | return !object->ShouldWait(thread); | 479 | return result; |
| 496 | }); | ||
| 497 | |||
| 498 | if (itr != objects.end()) { | ||
| 499 | // We found a ready object, acquire it and set the result value | ||
| 500 | SynchronizationObject* object = itr->get(); | ||
| 501 | object->Acquire(thread); | ||
| 502 | *index = static_cast<s32>(std::distance(objects.begin(), itr)); | ||
| 503 | return RESULT_SUCCESS; | ||
| 504 | } | ||
| 505 | |||
| 506 | // No objects were ready to be acquired, prepare to suspend the thread. | ||
| 507 | |||
| 508 | // If a timeout value of 0 was provided, just return the Timeout error code instead of | ||
| 509 | // suspending the thread. | ||
| 510 | if (nano_seconds == 0) { | ||
| 511 | return RESULT_TIMEOUT; | ||
| 512 | } | ||
| 513 | |||
| 514 | if (thread->IsSyncCancelled()) { | ||
| 515 | thread->SetSyncCancelled(false); | ||
| 516 | return ERR_SYNCHRONIZATION_CANCELED; | ||
| 517 | } | ||
| 518 | |||
| 519 | for (auto& object : objects) { | ||
| 520 | object->AddWaitingThread(SharedFrom(thread)); | ||
| 521 | } | ||
| 522 | |||
| 523 | thread->SetSynchronizationObjects(std::move(objects)); | ||
| 524 | thread->SetStatus(ThreadStatus::WaitSynch); | ||
| 525 | |||
| 526 | // Create an event to wake the thread up after the specified nanosecond delay has passed | ||
| 527 | thread->WakeAfterDelay(nano_seconds); | ||
| 528 | thread->SetWakeupCallback(DefaultThreadWakeupCallback); | ||
| 529 | |||
| 530 | system.PrepareReschedule(thread->GetProcessorID()); | ||
| 531 | |||
| 532 | return RESULT_TIMEOUT; | ||
| 533 | } | 480 | } |
| 534 | 481 | ||
| 535 | /// Resumes a thread waiting on WaitSynchronization | 482 | /// Resumes a thread waiting on WaitSynchronization |
diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp new file mode 100644 index 000000000..25afc162f --- /dev/null +++ b/src/core/hle/kernel/synchronization.cpp | |||
| @@ -0,0 +1,86 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/core.h" | ||
| 6 | #include "core/hle/kernel/errors.h" | ||
| 7 | #include "core/hle/kernel/kernel.h" | ||
| 8 | #include "core/hle/kernel/scheduler.h" | ||
| 9 | #include "core/hle/kernel/synchronization.h" | ||
| 10 | #include "core/hle/kernel/synchronization_object.h" | ||
| 11 | #include "core/hle/kernel/thread.h" | ||
| 12 | |||
| 13 | namespace Kernel { | ||
| 14 | |||
| 15 | /// Default thread wakeup callback for WaitSynchronization | ||
| 16 | static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread, | ||
| 17 | std::shared_ptr<SynchronizationObject> object, | ||
| 18 | std::size_t index) { | ||
| 19 | ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch); | ||
| 20 | |||
| 21 | if (reason == ThreadWakeupReason::Timeout) { | ||
| 22 | thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); | ||
| 23 | return true; | ||
| 24 | } | ||
| 25 | |||
| 26 | ASSERT(reason == ThreadWakeupReason::Signal); | ||
| 27 | thread->SetWaitSynchronizationResult(RESULT_SUCCESS); | ||
| 28 | thread->SetWaitSynchronizationOutput(static_cast<u32>(index)); | ||
| 29 | return true; | ||
| 30 | }; | ||
| 31 | |||
| 32 | Synchronization::Synchronization(Core::System& system) : system{system} {} | ||
| 33 | |||
| 34 | void Synchronization::SignalObject(SynchronizationObject& obj) const { | ||
| 35 | if (obj.IsSignaled()) { | ||
| 36 | obj.WakeupAllWaitingThreads(); | ||
| 37 | }; | ||
| 38 | } | ||
| 39 | |||
| 40 | std::pair<ResultCode, Handle> Synchronization::WaitFor( | ||
| 41 | std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds) { | ||
| 42 | auto* const thread = system.CurrentScheduler().GetCurrentThread(); | ||
| 43 | // Find the first object that is acquirable in the provided list of objects | ||
| 44 | auto itr = std::find_if(sync_objects.begin(), sync_objects.end(), | ||
| 45 | [thread](const std::shared_ptr<SynchronizationObject>& object) { | ||
| 46 | return object->IsSignaled(); | ||
| 47 | }); | ||
| 48 | |||
| 49 | if (itr != sync_objects.end()) { | ||
| 50 | // We found a ready object, acquire it and set the result value | ||
| 51 | SynchronizationObject* object = itr->get(); | ||
| 52 | object->Acquire(thread); | ||
| 53 | u32 index = static_cast<s32>(std::distance(sync_objects.begin(), itr)); | ||
| 54 | return {RESULT_SUCCESS, index}; | ||
| 55 | } | ||
| 56 | |||
| 57 | // No objects were ready to be acquired, prepare to suspend the thread. | ||
| 58 | |||
| 59 | // If a timeout value of 0 was provided, just return the Timeout error code instead of | ||
| 60 | // suspending the thread. | ||
| 61 | if (nano_seconds == 0) { | ||
| 62 | return {RESULT_TIMEOUT, 0}; | ||
| 63 | } | ||
| 64 | |||
| 65 | if (thread->IsSyncCancelled()) { | ||
| 66 | thread->SetSyncCancelled(false); | ||
| 67 | return {ERR_SYNCHRONIZATION_CANCELED, 0}; | ||
| 68 | } | ||
| 69 | |||
| 70 | for (auto& object : sync_objects) { | ||
| 71 | object->AddWaitingThread(SharedFrom(thread)); | ||
| 72 | } | ||
| 73 | |||
| 74 | thread->SetSynchronizationObjects(std::move(sync_objects)); | ||
| 75 | thread->SetStatus(ThreadStatus::WaitSynch); | ||
| 76 | |||
| 77 | // Create an event to wake the thread up after the specified nanosecond delay has passed | ||
| 78 | thread->WakeAfterDelay(nano_seconds); | ||
| 79 | thread->SetWakeupCallback(DefaultThreadWakeupCallback); | ||
| 80 | |||
| 81 | system.PrepareReschedule(thread->GetProcessorID()); | ||
| 82 | |||
| 83 | return {RESULT_TIMEOUT, 0}; | ||
| 84 | } | ||
| 85 | |||
| 86 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/synchronization.h b/src/core/hle/kernel/synchronization.h new file mode 100644 index 000000000..3417a9f13 --- /dev/null +++ b/src/core/hle/kernel/synchronization.h | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include <utility> | ||
| 9 | |||
| 10 | #include "core/hle/kernel/object.h" | ||
| 11 | #include "core/hle/result.h" | ||
| 12 | |||
| 13 | namespace Core { | ||
| 14 | class System; | ||
| 15 | } // namespace Core | ||
| 16 | |||
| 17 | namespace Kernel { | ||
| 18 | |||
| 19 | class KernelCore; | ||
| 20 | class SynchronizationObject; | ||
| 21 | |||
| 22 | class Synchronization { | ||
| 23 | public: | ||
| 24 | Synchronization(Core::System& system); | ||
| 25 | |||
| 26 | void SignalObject(SynchronizationObject& obj) const; | ||
| 27 | |||
| 28 | std::pair<ResultCode, Handle> WaitFor( | ||
| 29 | std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds); | ||
| 30 | |||
| 31 | private: | ||
| 32 | Core::System& system; | ||
| 33 | }; | ||
| 34 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/synchronization_object.cpp b/src/core/hle/kernel/synchronization_object.cpp index 95f3f9245..43f3eef18 100644 --- a/src/core/hle/kernel/synchronization_object.cpp +++ b/src/core/hle/kernel/synchronization_object.cpp | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include "core/hle/kernel/kernel.h" | 10 | #include "core/hle/kernel/kernel.h" |
| 11 | #include "core/hle/kernel/object.h" | 11 | #include "core/hle/kernel/object.h" |
| 12 | #include "core/hle/kernel/process.h" | 12 | #include "core/hle/kernel/process.h" |
| 13 | #include "core/hle/kernel/synchronization.h" | ||
| 13 | #include "core/hle/kernel/synchronization_object.h" | 14 | #include "core/hle/kernel/synchronization_object.h" |
| 14 | #include "core/hle/kernel/thread.h" | 15 | #include "core/hle/kernel/thread.h" |
| 15 | 16 | ||
| @@ -18,6 +19,10 @@ namespace Kernel { | |||
| 18 | SynchronizationObject::SynchronizationObject(KernelCore& kernel) : Object{kernel} {} | 19 | SynchronizationObject::SynchronizationObject(KernelCore& kernel) : Object{kernel} {} |
| 19 | SynchronizationObject::~SynchronizationObject() = default; | 20 | SynchronizationObject::~SynchronizationObject() = default; |
| 20 | 21 | ||
| 22 | void SynchronizationObject::Signal() { | ||
| 23 | kernel.Synchronization().SignalObject(*this); | ||
| 24 | } | ||
| 25 | |||
| 21 | void SynchronizationObject::AddWaitingThread(std::shared_ptr<Thread> thread) { | 26 | void SynchronizationObject::AddWaitingThread(std::shared_ptr<Thread> thread) { |
| 22 | auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); | 27 | auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); |
| 23 | if (itr == waiting_threads.end()) | 28 | if (itr == waiting_threads.end()) |
diff --git a/src/core/hle/kernel/synchronization_object.h b/src/core/hle/kernel/synchronization_object.h index a0f891c97..741c31faf 100644 --- a/src/core/hle/kernel/synchronization_object.h +++ b/src/core/hle/kernel/synchronization_object.h | |||
| @@ -30,6 +30,13 @@ public: | |||
| 30 | /// Acquire/lock the object for the specified thread if it is available | 30 | /// Acquire/lock the object for the specified thread if it is available |
| 31 | virtual void Acquire(Thread* thread) = 0; | 31 | virtual void Acquire(Thread* thread) = 0; |
| 32 | 32 | ||
| 33 | /// Signal this object | ||
| 34 | virtual void Signal(); | ||
| 35 | |||
| 36 | virtual bool IsSignaled() const { | ||
| 37 | return is_signaled; | ||
| 38 | } | ||
| 39 | |||
| 33 | /** | 40 | /** |
| 34 | * Add a thread to wait on this object | 41 | * Add a thread to wait on this object |
| 35 | * @param thread Pointer to thread to add | 42 | * @param thread Pointer to thread to add |
| @@ -60,6 +67,9 @@ public: | |||
| 60 | /// Get a const reference to the waiting threads list for debug use | 67 | /// Get a const reference to the waiting threads list for debug use |
| 61 | const std::vector<std::shared_ptr<Thread>>& GetWaitingThreads() const; | 68 | const std::vector<std::shared_ptr<Thread>>& GetWaitingThreads() const; |
| 62 | 69 | ||
| 70 | protected: | ||
| 71 | bool is_signaled{}; // Tells if this sync object is signalled; | ||
| 72 | |||
| 63 | private: | 73 | private: |
| 64 | /// Threads waiting for this object to become available | 74 | /// Threads waiting for this object to become available |
| 65 | std::vector<std::shared_ptr<Thread>> waiting_threads; | 75 | std::vector<std::shared_ptr<Thread>> waiting_threads; |
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 0f096ed6d..ee9ea7d67 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -31,6 +31,10 @@ bool Thread::ShouldWait(const Thread* thread) const { | |||
| 31 | return status != ThreadStatus::Dead; | 31 | return status != ThreadStatus::Dead; |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | bool Thread::IsSignaled() const { | ||
| 35 | return status == ThreadStatus::Dead; | ||
| 36 | } | ||
| 37 | |||
| 34 | void Thread::Acquire(Thread* thread) { | 38 | void Thread::Acquire(Thread* thread) { |
| 35 | ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); | 39 | ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); |
| 36 | } | 40 | } |
| @@ -45,7 +49,7 @@ void Thread::Stop() { | |||
| 45 | kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle); | 49 | kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle); |
| 46 | callback_handle = 0; | 50 | callback_handle = 0; |
| 47 | SetStatus(ThreadStatus::Dead); | 51 | SetStatus(ThreadStatus::Dead); |
| 48 | WakeupAllWaitingThreads(); | 52 | Signal(); |
| 49 | 53 | ||
| 50 | // Clean up any dangling references in objects that this thread was waiting for | 54 | // Clean up any dangling references in objects that this thread was waiting for |
| 51 | for (auto& wait_object : wait_objects) { | 55 | for (auto& wait_object : wait_objects) { |
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 895258095..7a4916318 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h | |||
| @@ -146,6 +146,7 @@ public: | |||
| 146 | 146 | ||
| 147 | bool ShouldWait(const Thread* thread) const override; | 147 | bool ShouldWait(const Thread* thread) const override; |
| 148 | void Acquire(Thread* thread) override; | 148 | void Acquire(Thread* thread) override; |
| 149 | bool IsSignaled() const override; | ||
| 149 | 150 | ||
| 150 | /** | 151 | /** |
| 151 | * Gets the thread's current priority | 152 | * Gets the thread's current priority |
diff --git a/src/core/hle/kernel/writable_event.cpp b/src/core/hle/kernel/writable_event.cpp index c9332e3e1..fc2f7c424 100644 --- a/src/core/hle/kernel/writable_event.cpp +++ b/src/core/hle/kernel/writable_event.cpp | |||
| @@ -22,7 +22,6 @@ EventPair WritableEvent::CreateEventPair(KernelCore& kernel, std::string name) { | |||
| 22 | writable_event->name = name + ":Writable"; | 22 | writable_event->name = name + ":Writable"; |
| 23 | writable_event->readable = readable_event; | 23 | writable_event->readable = readable_event; |
| 24 | readable_event->name = name + ":Readable"; | 24 | readable_event->name = name + ":Readable"; |
| 25 | readable_event->signaled = false; | ||
| 26 | 25 | ||
| 27 | return {std::move(readable_event), std::move(writable_event)}; | 26 | return {std::move(readable_event), std::move(writable_event)}; |
| 28 | } | 27 | } |
| @@ -40,7 +39,7 @@ void WritableEvent::Clear() { | |||
| 40 | } | 39 | } |
| 41 | 40 | ||
| 42 | bool WritableEvent::IsSignaled() const { | 41 | bool WritableEvent::IsSignaled() const { |
| 43 | return readable->signaled; | 42 | return readable->IsSignaled(); |
| 44 | } | 43 | } |
| 45 | 44 | ||
| 46 | } // namespace Kernel | 45 | } // namespace Kernel |