summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hle/kernel/client_session.cpp5
-rw-r--r--src/core/hle/kernel/client_session.h2
-rw-r--r--src/core/hle/kernel/kernel.cpp13
-rw-r--r--src/core/hle/kernel/kernel.h7
-rw-r--r--src/core/hle/kernel/process.cpp2
-rw-r--r--src/core/hle/kernel/process.h4
-rw-r--r--src/core/hle/kernel/readable_event.cpp14
-rw-r--r--src/core/hle/kernel/readable_event.h6
-rw-r--r--src/core/hle/kernel/server_port.cpp4
-rw-r--r--src/core/hle/kernel/server_port.h2
-rw-r--r--src/core/hle/kernel/server_session.cpp10
-rw-r--r--src/core/hle/kernel/server_session.h2
-rw-r--r--src/core/hle/kernel/session.cpp5
-rw-r--r--src/core/hle/kernel/session.h2
-rw-r--r--src/core/hle/kernel/svc.cpp67
-rw-r--r--src/core/hle/kernel/synchronization.cpp86
-rw-r--r--src/core/hle/kernel/synchronization.h34
-rw-r--r--src/core/hle/kernel/synchronization_object.cpp5
-rw-r--r--src/core/hle/kernel/synchronization_object.h10
-rw-r--r--src/core/hle/kernel/thread.cpp6
-rw-r--r--src/core/hle/kernel/thread.h1
-rw-r--r--src/core/hle/kernel/writable_event.cpp3
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
34bool ClientSession::IsSignaled() const {
35 UNIMPLEMENTED();
36 return true;
37}
38
34ResultVal<std::shared_ptr<ClientSession>> ClientSession::Create(KernelCore& kernel, 39ResultVal<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
51private: 53private:
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
98struct KernelCore::Impl { 99struct 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
276Kernel::Synchronization& KernelCore::Synchronization() {
277 return impl->synchronization;
278}
279
280const Kernel::Synchronization& KernelCore::Synchronization() const {
281 return impl->synchronization;
282}
283
273Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() { 284Core::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;
29class PhysicalCore; 29class PhysicalCore;
30class Process; 30class Process;
31class ResourceLimit; 31class ResourceLimit;
32class Synchronization;
32class Thread; 33class 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
363void Process::AllocateMainThreadStack(u64 stack_size) { 363void 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}
15ReadableEvent::~ReadableEvent() = default; 15ReadableEvent::~ReadableEvent() = default;
16 16
17bool ReadableEvent::ShouldWait(const Thread* thread) const { 17bool ReadableEvent::ShouldWait(const Thread* thread) const {
18 return !signaled; 18 return !is_signaled;
19} 19}
20 20
21void ReadableEvent::Acquire(Thread* thread) { 21void ReadableEvent::Acquire(Thread* thread) {
22 ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); 22 ASSERT_MSG(IsSignaled(), "object unavailable!");
23} 23}
24 24
25void ReadableEvent::Signal() { 25void 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
32void ReadableEvent::Clear() { 32void ReadableEvent::Clear() {
33 signaled = false; 33 is_signaled = false;
34} 34}
35 35
36ResultCode ReadableEvent::Reset() { 36ResultCode 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
49private: 51private:
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
42bool ServerPort::IsSignaled() const {
43 return !pending_sessions.empty();
44}
45
42ServerPort::PortPair ServerPort::CreatePortPair(KernelCore& kernel, u32 max_sessions, 46ServerPort::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
85private: 87private:
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
53bool 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
53void ServerSession::Acquire(Thread* thread) { 63void 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
32bool Session::IsSignaled() const {
33 UNIMPLEMENTED();
34 return true;
35}
36
32void Session::Acquire(Thread* thread) { 37void 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
437static 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
454static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr handles_address, 438static 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
13namespace Kernel {
14
15/// Default thread wakeup callback for WaitSynchronization
16static 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
32Synchronization::Synchronization(Core::System& system) : system{system} {}
33
34void Synchronization::SignalObject(SynchronizationObject& obj) const {
35 if (obj.IsSignaled()) {
36 obj.WakeupAllWaitingThreads();
37 };
38}
39
40std::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
13namespace Core {
14class System;
15} // namespace Core
16
17namespace Kernel {
18
19class KernelCore;
20class SynchronizationObject;
21
22class Synchronization {
23public:
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
31private:
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 {
18SynchronizationObject::SynchronizationObject(KernelCore& kernel) : Object{kernel} {} 19SynchronizationObject::SynchronizationObject(KernelCore& kernel) : Object{kernel} {}
19SynchronizationObject::~SynchronizationObject() = default; 20SynchronizationObject::~SynchronizationObject() = default;
20 21
22void SynchronizationObject::Signal() {
23 kernel.Synchronization().SignalObject(*this);
24}
25
21void SynchronizationObject::AddWaitingThread(std::shared_ptr<Thread> thread) { 26void 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
70protected:
71 bool is_signaled{}; // Tells if this sync object is signalled;
72
63private: 73private:
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
34bool Thread::IsSignaled() const {
35 return status == ThreadStatus::Dead;
36}
37
34void Thread::Acquire(Thread* thread) { 38void 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
42bool WritableEvent::IsSignaled() const { 41bool WritableEvent::IsSignaled() const {
43 return readable->signaled; 42 return readable->IsSignaled();
44} 43}
45 44
46} // namespace Kernel 45} // namespace Kernel