diff options
author | bunnei <bunneidev@gmail.com> | 2020-02-14 20:40:20 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-02-14 20:40:20 +0100 |
commit | f552d553bac1374c583d748dad27f8c86e86c4a0 (patch) | |
tree | 1da4aa037ff417fa4fd43bffac267dcb2b55a72d /src/core/hle/kernel/synchronization.cpp | |
parent | Merge pull request #3379 from ReinUsesLisp/cbuf-offset (diff) | |
parent | Core: Correct compilition in GCC (diff) | |
download | yuzu-f552d553bac1374c583d748dad27f8c86e86c4a0.tar yuzu-f552d553bac1374c583d748dad27f8c86e86c4a0.tar.gz yuzu-f552d553bac1374c583d748dad27f8c86e86c4a0.tar.bz2 yuzu-f552d553bac1374c583d748dad27f8c86e86c4a0.tar.lz yuzu-f552d553bac1374c583d748dad27f8c86e86c4a0.tar.xz yuzu-f552d553bac1374c583d748dad27f8c86e86c4a0.tar.zst yuzu-f552d553bac1374c583d748dad27f8c86e86c4a0.zip |
Diffstat (limited to 'src/core/hle/kernel/synchronization.cpp')
-rw-r--r-- | src/core/hle/kernel/synchronization.cpp | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp new file mode 100644 index 000000000..dc37fad1a --- /dev/null +++ b/src/core/hle/kernel/synchronization.cpp @@ -0,0 +1,87 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/core.h" +#include "core/hle/kernel/errors.h" +#include "core/hle/kernel/handle_table.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/scheduler.h" +#include "core/hle/kernel/synchronization.h" +#include "core/hle/kernel/synchronization_object.h" +#include "core/hle/kernel/thread.h" + +namespace Kernel { + +/// Default thread wakeup callback for WaitSynchronization +static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread, + std::shared_ptr<SynchronizationObject> object, + std::size_t index) { + ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch); + + if (reason == ThreadWakeupReason::Timeout) { + thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); + return true; + } + + ASSERT(reason == ThreadWakeupReason::Signal); + thread->SetWaitSynchronizationResult(RESULT_SUCCESS); + thread->SetWaitSynchronizationOutput(static_cast<u32>(index)); + return true; +} + +Synchronization::Synchronization(Core::System& system) : system{system} {} + +void Synchronization::SignalObject(SynchronizationObject& obj) const { + if (obj.IsSignaled()) { + obj.WakeupAllWaitingThreads(); + } +} + +std::pair<ResultCode, Handle> Synchronization::WaitFor( + std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds) { + auto* const thread = system.CurrentScheduler().GetCurrentThread(); + // Find the first object that is acquirable in the provided list of objects + const auto itr = std::find_if(sync_objects.begin(), sync_objects.end(), + [thread](const std::shared_ptr<SynchronizationObject>& object) { + return object->IsSignaled(); + }); + + if (itr != sync_objects.end()) { + // We found a ready object, acquire it and set the result value + SynchronizationObject* object = itr->get(); + object->Acquire(thread); + const u32 index = static_cast<s32>(std::distance(sync_objects.begin(), itr)); + return {RESULT_SUCCESS, index}; + } + + // No objects were ready to be acquired, prepare to suspend the thread. + + // If a timeout value of 0 was provided, just return the Timeout error code instead of + // suspending the thread. + if (nano_seconds == 0) { + return {RESULT_TIMEOUT, InvalidHandle}; + } + + if (thread->IsSyncCancelled()) { + thread->SetSyncCancelled(false); + return {ERR_SYNCHRONIZATION_CANCELED, InvalidHandle}; + } + + for (auto& object : sync_objects) { + object->AddWaitingThread(SharedFrom(thread)); + } + + thread->SetSynchronizationObjects(std::move(sync_objects)); + thread->SetStatus(ThreadStatus::WaitSynch); + + // Create an event to wake the thread up after the specified nanosecond delay has passed + thread->WakeAfterDelay(nano_seconds); + thread->SetWakeupCallback(DefaultThreadWakeupCallback); + + system.PrepareReschedule(thread->GetProcessorID()); + + return {RESULT_TIMEOUT, InvalidHandle}; +} + +} // namespace Kernel |