|
@@ -10,78 +10,88 @@
|
|
|
#include "core/hle/kernel/synchronization.h"
|
|
#include "core/hle/kernel/synchronization.h"
|
|
|
#include "core/hle/kernel/synchronization_object.h"
|
|
#include "core/hle/kernel/synchronization_object.h"
|
|
|
#include "core/hle/kernel/thread.h"
|
|
#include "core/hle/kernel/thread.h"
|
|
|
|
|
+#include "core/hle/kernel/time_manager.h"
|
|
|
|
|
|
|
|
namespace Kernel {
|
|
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} {}
|
|
Synchronization::Synchronization(Core::System& system) : system{system} {}
|
|
|
|
|
|
|
|
void Synchronization::SignalObject(SynchronizationObject& obj) const {
|
|
void Synchronization::SignalObject(SynchronizationObject& obj) const {
|
|
|
|
|
+ SchedulerLock lock(system.Kernel());
|
|
|
if (obj.IsSignaled()) {
|
|
if (obj.IsSignaled()) {
|
|
|
- obj.WakeupAllWaitingThreads();
|
|
|
|
|
|
|
+ for (auto thread : obj.GetWaitingThreads()) {
|
|
|
|
|
+ if (thread->GetSchedulingStatus() == ThreadSchedStatus::Paused) {
|
|
|
|
|
+ thread->SetSynchronizationResults(&obj, RESULT_SUCCESS);
|
|
|
|
|
+ thread->ResumeFromWait();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
std::pair<ResultCode, Handle> Synchronization::WaitFor(
|
|
std::pair<ResultCode, Handle> Synchronization::WaitFor(
|
|
|
std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds) {
|
|
std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds) {
|
|
|
|
|
+ auto& kernel = system.Kernel();
|
|
|
auto* const thread = system.CurrentScheduler().GetCurrentThread();
|
|
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};
|
|
|
|
|
|
|
+ Handle event_handle = InvalidHandle;
|
|
|
|
|
+ {
|
|
|
|
|
+ SchedulerLockAndSleep lock(kernel, event_handle, thread, nano_seconds);
|
|
|
|
|
+ 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));
|
|
|
|
|
+ lock.CancelSleep();
|
|
|
|
|
+ return {RESULT_SUCCESS, index};
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (nano_seconds == 0) {
|
|
|
|
|
+ lock.CancelSleep();
|
|
|
|
|
+ return {RESULT_TIMEOUT, InvalidHandle};
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// TODO(Blinkhawk): Check for termination pending
|
|
|
|
|
+
|
|
|
|
|
+ if (thread->IsSyncCancelled()) {
|
|
|
|
|
+ thread->SetSyncCancelled(false);
|
|
|
|
|
+ lock.CancelSleep();
|
|
|
|
|
+ return {ERR_SYNCHRONIZATION_CANCELED, InvalidHandle};
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for (auto& object : sync_objects) {
|
|
|
|
|
+ object->AddWaitingThread(SharedFrom(thread));
|
|
|
|
|
+ }
|
|
|
|
|
+ thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT);
|
|
|
|
|
+ thread->SetStatus(ThreadStatus::WaitSynch);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 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 (event_handle != InvalidHandle) {
|
|
|
|
|
+ auto& time_manager = kernel.TimeManager();
|
|
|
|
|
+ time_manager.UnscheduleTimeEvent(event_handle);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (thread->IsSyncCancelled()) {
|
|
|
|
|
- thread->SetSyncCancelled(false);
|
|
|
|
|
- return {ERR_SYNCHRONIZATION_CANCELED, InvalidHandle};
|
|
|
|
|
|
|
+ {
|
|
|
|
|
+ SchedulerLock lock(kernel);
|
|
|
|
|
+ ResultCode signaling_result = thread->GetSignalingResult();
|
|
|
|
|
+ SynchronizationObject* signaling_object = thread->GetSignalingObject();
|
|
|
|
|
+ if (signaling_result == RESULT_SUCCESS) {
|
|
|
|
|
+ const auto itr = std::find_if(
|
|
|
|
|
+ sync_objects.begin(), sync_objects.end(),
|
|
|
|
|
+ [signaling_object](const std::shared_ptr<SynchronizationObject>& object) {
|
|
|
|
|
+ return object.get() == signaling_object;
|
|
|
|
|
+ });
|
|
|
|
|
+ ASSERT(itr != sync_objects.end());
|
|
|
|
|
+ signaling_object->Acquire(thread);
|
|
|
|
|
+ const u32 index = static_cast<s32>(std::distance(sync_objects.begin(), itr));
|
|
|
|
|
+ return {RESULT_SUCCESS, index};
|
|
|
|
|
+ }
|
|
|
|
|
+ return {signaling_result, -1};
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- 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
|
|
} // namespace Kernel
|