2017-05-30 00:45:30 +02:00
|
|
|
// Copyright 2014 Citra Emulator Project
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include "common/assert.h"
|
2019-01-01 00:09:41 +01:00
|
|
|
#include "common/common_types.h"
|
2017-05-30 00:45:30 +02:00
|
|
|
#include "common/logging/log.h"
|
2019-03-29 22:13:00 +01:00
|
|
|
#include "core/core.h"
|
2019-09-11 18:47:37 +02:00
|
|
|
#include "core/hle/kernel/kernel.h"
|
2018-08-02 04:40:00 +02:00
|
|
|
#include "core/hle/kernel/object.h"
|
2017-05-30 00:45:30 +02:00
|
|
|
#include "core/hle/kernel/process.h"
|
2020-02-11 22:36:39 +01:00
|
|
|
#include "core/hle/kernel/synchronization.h"
|
2020-02-11 15:46:25 +01:00
|
|
|
#include "core/hle/kernel/synchronization_object.h"
|
2017-05-30 00:45:30 +02:00
|
|
|
#include "core/hle/kernel/thread.h"
|
|
|
|
|
|
|
|
namespace Kernel {
|
|
|
|
|
2020-02-11 15:46:25 +01:00
|
|
|
SynchronizationObject::SynchronizationObject(KernelCore& kernel) : Object{kernel} {}
|
|
|
|
SynchronizationObject::~SynchronizationObject() = default;
|
2018-08-28 18:30:33 +02:00
|
|
|
|
2020-02-11 22:36:39 +01:00
|
|
|
void SynchronizationObject::Signal() {
|
|
|
|
kernel.Synchronization().SignalObject(*this);
|
|
|
|
}
|
|
|
|
|
2020-02-11 15:46:25 +01:00
|
|
|
void SynchronizationObject::AddWaitingThread(std::shared_ptr<Thread> thread) {
|
2017-05-30 00:45:30 +02:00
|
|
|
auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
|
|
|
|
if (itr == waiting_threads.end())
|
|
|
|
waiting_threads.push_back(std::move(thread));
|
|
|
|
}
|
|
|
|
|
2020-02-11 15:46:25 +01:00
|
|
|
void SynchronizationObject::RemoveWaitingThread(std::shared_ptr<Thread> thread) {
|
2017-05-30 00:45:30 +02:00
|
|
|
auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
|
|
|
|
// If a thread passed multiple handles to the same object,
|
|
|
|
// the kernel might attempt to remove the thread from the object's
|
|
|
|
// waiting threads list multiple times.
|
|
|
|
if (itr != waiting_threads.end())
|
|
|
|
waiting_threads.erase(itr);
|
|
|
|
}
|
|
|
|
|
2020-02-11 15:46:25 +01:00
|
|
|
std::shared_ptr<Thread> SynchronizationObject::GetHighestPriorityReadyThread() const {
|
2017-05-30 00:45:30 +02:00
|
|
|
Thread* candidate = nullptr;
|
2017-09-27 01:26:09 +02:00
|
|
|
u32 candidate_priority = THREADPRIO_LOWEST + 1;
|
2017-05-30 00:45:30 +02:00
|
|
|
|
|
|
|
for (const auto& thread : waiting_threads) {
|
2018-10-04 00:47:57 +02:00
|
|
|
const ThreadStatus thread_status = thread->GetStatus();
|
|
|
|
|
2017-05-30 00:45:30 +02:00
|
|
|
// The list of waiting threads must not contain threads that are not waiting to be awakened.
|
2019-04-17 13:21:19 +02:00
|
|
|
ASSERT_MSG(thread_status == ThreadStatus::WaitSynch ||
|
2018-10-04 00:47:57 +02:00
|
|
|
thread_status == ThreadStatus::WaitHLEEvent,
|
2017-05-30 00:45:30 +02:00
|
|
|
"Inconsistent thread statuses in waiting_threads");
|
|
|
|
|
2018-10-04 00:47:57 +02:00
|
|
|
if (thread->GetPriority() >= candidate_priority)
|
2017-05-30 00:45:30 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (ShouldWait(thread.get()))
|
|
|
|
continue;
|
|
|
|
|
2019-07-04 05:21:48 +02:00
|
|
|
candidate = thread.get();
|
|
|
|
candidate_priority = thread->GetPriority();
|
2017-05-30 00:45:30 +02:00
|
|
|
}
|
|
|
|
|
2019-11-25 02:15:51 +01:00
|
|
|
return SharedFrom(candidate);
|
2017-05-30 00:45:30 +02:00
|
|
|
}
|
|
|
|
|
2020-02-11 15:46:25 +01:00
|
|
|
void SynchronizationObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) {
|
2018-01-08 17:35:03 +01:00
|
|
|
ASSERT(!ShouldWait(thread.get()));
|
|
|
|
|
2019-04-17 13:21:19 +02:00
|
|
|
if (!thread) {
|
2018-01-07 22:33:41 +01:00
|
|
|
return;
|
2019-04-17 13:21:19 +02:00
|
|
|
}
|
2018-01-07 22:33:41 +01:00
|
|
|
|
2019-04-17 13:21:19 +02:00
|
|
|
if (thread->IsSleepingOnWait()) {
|
2020-02-11 15:46:25 +01:00
|
|
|
for (const auto& object : thread->GetSynchronizationObjects()) {
|
2018-01-08 17:35:03 +01:00
|
|
|
ASSERT(!object->ShouldWait(thread.get()));
|
2018-01-07 22:33:41 +01:00
|
|
|
object->Acquire(thread.get());
|
2017-05-30 00:45:30 +02:00
|
|
|
}
|
2019-04-17 13:21:19 +02:00
|
|
|
} else {
|
|
|
|
Acquire(thread.get());
|
2018-01-07 22:33:41 +01:00
|
|
|
}
|
2017-05-30 00:45:30 +02:00
|
|
|
|
2020-02-11 15:46:25 +01:00
|
|
|
const std::size_t index = thread->GetSynchronizationObjectIndex(SharedFrom(this));
|
2017-09-28 18:53:32 +02:00
|
|
|
|
2020-02-11 15:46:25 +01:00
|
|
|
thread->ClearSynchronizationObjects();
|
2017-05-30 00:45:30 +02:00
|
|
|
|
2018-01-08 17:35:03 +01:00
|
|
|
thread->CancelWakeupTimer();
|
|
|
|
|
|
|
|
bool resume = true;
|
2019-04-17 13:21:19 +02:00
|
|
|
if (thread->HasWakeupCallback()) {
|
2019-11-25 02:15:51 +01:00
|
|
|
resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Signal, thread, SharedFrom(this),
|
|
|
|
index);
|
2019-04-17 13:21:19 +02:00
|
|
|
}
|
|
|
|
if (resume) {
|
2018-01-08 17:35:03 +01:00
|
|
|
thread->ResumeFromWait();
|
2020-01-26 19:23:46 +01:00
|
|
|
kernel.PrepareReschedule(thread->GetProcessorID());
|
2019-04-17 13:21:19 +02:00
|
|
|
}
|
2018-01-07 22:33:41 +01:00
|
|
|
}
|
|
|
|
|
2020-02-11 15:46:25 +01:00
|
|
|
void SynchronizationObject::WakeupAllWaitingThreads() {
|
2018-01-07 22:33:41 +01:00
|
|
|
while (auto thread = GetHighestPriorityReadyThread()) {
|
|
|
|
WakeupWaitingThread(thread);
|
2017-05-30 00:45:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-11 15:46:25 +01:00
|
|
|
const std::vector<std::shared_ptr<Thread>>& SynchronizationObject::GetWaitingThreads() const {
|
2017-05-30 00:45:30 +02:00
|
|
|
return waiting_threads;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Kernel
|