core: hle: kernel: Update KSynchronizationObject.
This commit is contained in:
parent
1ae883435d
commit
35c3c078e3
33 changed files with 397 additions and 621 deletions
|
@ -164,6 +164,8 @@ add_library(core STATIC
|
||||||
hle/kernel/k_scheduler_lock.h
|
hle/kernel/k_scheduler_lock.h
|
||||||
hle/kernel/k_scoped_lock.h
|
hle/kernel/k_scoped_lock.h
|
||||||
hle/kernel/k_scoped_scheduler_lock_and_sleep.h
|
hle/kernel/k_scoped_scheduler_lock_and_sleep.h
|
||||||
|
hle/kernel/k_synchronization_object.cpp
|
||||||
|
hle/kernel/k_synchronization_object.h
|
||||||
hle/kernel/kernel.cpp
|
hle/kernel/kernel.cpp
|
||||||
hle/kernel/kernel.h
|
hle/kernel/kernel.h
|
||||||
hle/kernel/memory/address_space_info.cpp
|
hle/kernel/memory/address_space_info.cpp
|
||||||
|
@ -213,10 +215,6 @@ add_library(core STATIC
|
||||||
hle/kernel/svc_results.h
|
hle/kernel/svc_results.h
|
||||||
hle/kernel/svc_types.h
|
hle/kernel/svc_types.h
|
||||||
hle/kernel/svc_wrap.h
|
hle/kernel/svc_wrap.h
|
||||||
hle/kernel/synchronization_object.cpp
|
|
||||||
hle/kernel/synchronization_object.h
|
|
||||||
hle/kernel/synchronization.cpp
|
|
||||||
hle/kernel/synchronization.h
|
|
||||||
hle/kernel/thread.cpp
|
hle/kernel/thread.cpp
|
||||||
hle/kernel/thread.h
|
hle/kernel/thread.h
|
||||||
hle/kernel/time_manager.cpp
|
hle/kernel/time_manager.cpp
|
||||||
|
|
|
@ -37,7 +37,7 @@ void AddressArbiter::WakeThreads(const std::vector<std::shared_ptr<Thread>>& wai
|
||||||
waiting_threads[i]->SetSynchronizationResults(nullptr, RESULT_SUCCESS);
|
waiting_threads[i]->SetSynchronizationResults(nullptr, RESULT_SUCCESS);
|
||||||
RemoveThread(waiting_threads[i]);
|
RemoveThread(waiting_threads[i]);
|
||||||
waiting_threads[i]->WaitForArbitration(false);
|
waiting_threads[i]->WaitForArbitration(false);
|
||||||
waiting_threads[i]->ResumeFromWait();
|
waiting_threads[i]->Wakeup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +160,7 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6
|
||||||
{
|
{
|
||||||
KScopedSchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout);
|
KScopedSchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout);
|
||||||
|
|
||||||
if (current_thread->IsPendingTermination()) {
|
if (current_thread->IsTerminationRequested()) {
|
||||||
lock.CancelSleep();
|
lock.CancelSleep();
|
||||||
return ERR_THREAD_TERMINATING;
|
return ERR_THREAD_TERMINATING;
|
||||||
}
|
}
|
||||||
|
@ -201,7 +201,7 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6
|
||||||
|
|
||||||
current_thread->SetArbiterWaitAddress(address);
|
current_thread->SetArbiterWaitAddress(address);
|
||||||
InsertThread(SharedFrom(current_thread));
|
InsertThread(SharedFrom(current_thread));
|
||||||
current_thread->SetStatus(ThreadStatus::WaitArb);
|
current_thread->SetState(ThreadStatus::WaitArb);
|
||||||
current_thread->WaitForArbitration(true);
|
current_thread->WaitForArbitration(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,7 +230,7 @@ ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 t
|
||||||
{
|
{
|
||||||
KScopedSchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout);
|
KScopedSchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout);
|
||||||
|
|
||||||
if (current_thread->IsPendingTermination()) {
|
if (current_thread->IsTerminationRequested()) {
|
||||||
lock.CancelSleep();
|
lock.CancelSleep();
|
||||||
return ERR_THREAD_TERMINATING;
|
return ERR_THREAD_TERMINATING;
|
||||||
}
|
}
|
||||||
|
@ -256,7 +256,7 @@ ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 t
|
||||||
current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT);
|
current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT);
|
||||||
current_thread->SetArbiterWaitAddress(address);
|
current_thread->SetArbiterWaitAddress(address);
|
||||||
InsertThread(SharedFrom(current_thread));
|
InsertThread(SharedFrom(current_thread));
|
||||||
current_thread->SetStatus(ThreadStatus::WaitArb);
|
current_thread->SetState(ThreadStatus::WaitArb);
|
||||||
current_thread->WaitForArbitration(true);
|
current_thread->WaitForArbitration(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,9 +33,6 @@ ResultVal<std::shared_ptr<ClientSession>> ClientPort::Connect() {
|
||||||
server_port->AppendPendingSession(std::move(server));
|
server_port->AppendPendingSession(std::move(server));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wake the threads waiting on the ServerPort
|
|
||||||
server_port->Signal();
|
|
||||||
|
|
||||||
return MakeResult(std::move(client));
|
return MakeResult(std::move(client));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
ClientSession::ClientSession(KernelCore& kernel) : SynchronizationObject{kernel} {}
|
ClientSession::ClientSession(KernelCore& kernel) : KSynchronizationObject{kernel} {}
|
||||||
|
|
||||||
ClientSession::~ClientSession() {
|
ClientSession::~ClientSession() {
|
||||||
// This destructor will be called automatically when the last ClientSession handle is closed by
|
// This destructor will be called automatically when the last ClientSession handle is closed by
|
||||||
|
@ -22,15 +22,6 @@ ClientSession::~ClientSession() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ClientSession::ShouldWait(const Thread* thread) const {
|
|
||||||
UNIMPLEMENTED();
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClientSession::Acquire(Thread* thread) {
|
|
||||||
UNIMPLEMENTED();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ClientSession::IsSignaled() const {
|
bool ClientSession::IsSignaled() const {
|
||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "core/hle/kernel/synchronization_object.h"
|
#include "core/hle/kernel/k_synchronization_object.h"
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
union ResultCode;
|
union ResultCode;
|
||||||
|
@ -26,7 +26,7 @@ class KernelCore;
|
||||||
class Session;
|
class Session;
|
||||||
class Thread;
|
class Thread;
|
||||||
|
|
||||||
class ClientSession final : public SynchronizationObject {
|
class ClientSession final : public KSynchronizationObject {
|
||||||
public:
|
public:
|
||||||
explicit ClientSession(KernelCore& kernel);
|
explicit ClientSession(KernelCore& kernel);
|
||||||
~ClientSession() override;
|
~ClientSession() override;
|
||||||
|
@ -49,10 +49,6 @@ public:
|
||||||
ResultCode SendSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory,
|
ResultCode SendSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory,
|
||||||
Core::Timing::CoreTiming& core_timing);
|
Core::Timing::CoreTiming& core_timing);
|
||||||
|
|
||||||
bool ShouldWait(const Thread* thread) const override;
|
|
||||||
|
|
||||||
void Acquire(Thread* thread) override;
|
|
||||||
|
|
||||||
bool IsSignaled() const override;
|
bool IsSignaled() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -13,12 +13,14 @@ namespace Kernel {
|
||||||
constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED{ErrorModule::Kernel, 7};
|
constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED{ErrorModule::Kernel, 7};
|
||||||
constexpr ResultCode ERR_INVALID_CAPABILITY_DESCRIPTOR{ErrorModule::Kernel, 14};
|
constexpr ResultCode ERR_INVALID_CAPABILITY_DESCRIPTOR{ErrorModule::Kernel, 14};
|
||||||
constexpr ResultCode ERR_THREAD_TERMINATING{ErrorModule::Kernel, 59};
|
constexpr ResultCode ERR_THREAD_TERMINATING{ErrorModule::Kernel, 59};
|
||||||
|
constexpr ResultCode ERR_TERMINATION_REQUESTED{ErrorModule::Kernel, 59};
|
||||||
constexpr ResultCode ERR_INVALID_SIZE{ErrorModule::Kernel, 101};
|
constexpr ResultCode ERR_INVALID_SIZE{ErrorModule::Kernel, 101};
|
||||||
constexpr ResultCode ERR_INVALID_ADDRESS{ErrorModule::Kernel, 102};
|
constexpr ResultCode ERR_INVALID_ADDRESS{ErrorModule::Kernel, 102};
|
||||||
constexpr ResultCode ERR_OUT_OF_RESOURCES{ErrorModule::Kernel, 103};
|
constexpr ResultCode ERR_OUT_OF_RESOURCES{ErrorModule::Kernel, 103};
|
||||||
constexpr ResultCode ERR_OUT_OF_MEMORY{ErrorModule::Kernel, 104};
|
constexpr ResultCode ERR_OUT_OF_MEMORY{ErrorModule::Kernel, 104};
|
||||||
constexpr ResultCode ERR_HANDLE_TABLE_FULL{ErrorModule::Kernel, 105};
|
constexpr ResultCode ERR_HANDLE_TABLE_FULL{ErrorModule::Kernel, 105};
|
||||||
constexpr ResultCode ERR_INVALID_ADDRESS_STATE{ErrorModule::Kernel, 106};
|
constexpr ResultCode ERR_INVALID_ADDRESS_STATE{ErrorModule::Kernel, 106};
|
||||||
|
constexpr ResultCode ERR_INVALID_CURRENT_MEMORY{ErrorModule::Kernel, 106};
|
||||||
constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS{ErrorModule::Kernel, 108};
|
constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS{ErrorModule::Kernel, 108};
|
||||||
constexpr ResultCode ERR_INVALID_MEMORY_RANGE{ErrorModule::Kernel, 110};
|
constexpr ResultCode ERR_INVALID_MEMORY_RANGE{ErrorModule::Kernel, 110};
|
||||||
constexpr ResultCode ERR_INVALID_PROCESSOR_ID{ErrorModule::Kernel, 113};
|
constexpr ResultCode ERR_INVALID_PROCESSOR_ID{ErrorModule::Kernel, 113};
|
||||||
|
@ -28,6 +30,7 @@ constexpr ResultCode ERR_INVALID_POINTER{ErrorModule::Kernel, 115};
|
||||||
constexpr ResultCode ERR_INVALID_COMBINATION{ErrorModule::Kernel, 116};
|
constexpr ResultCode ERR_INVALID_COMBINATION{ErrorModule::Kernel, 116};
|
||||||
constexpr ResultCode RESULT_TIMEOUT{ErrorModule::Kernel, 117};
|
constexpr ResultCode RESULT_TIMEOUT{ErrorModule::Kernel, 117};
|
||||||
constexpr ResultCode ERR_SYNCHRONIZATION_CANCELED{ErrorModule::Kernel, 118};
|
constexpr ResultCode ERR_SYNCHRONIZATION_CANCELED{ErrorModule::Kernel, 118};
|
||||||
|
constexpr ResultCode ERR_CANCELLED{ErrorModule::Kernel, 118};
|
||||||
constexpr ResultCode ERR_OUT_OF_RANGE{ErrorModule::Kernel, 119};
|
constexpr ResultCode ERR_OUT_OF_RANGE{ErrorModule::Kernel, 119};
|
||||||
constexpr ResultCode ERR_INVALID_ENUM_VALUE{ErrorModule::Kernel, 120};
|
constexpr ResultCode ERR_INVALID_ENUM_VALUE{ErrorModule::Kernel, 120};
|
||||||
constexpr ResultCode ERR_NOT_FOUND{ErrorModule::Kernel, 121};
|
constexpr ResultCode ERR_NOT_FOUND{ErrorModule::Kernel, 121};
|
||||||
|
|
|
@ -645,8 +645,7 @@ void KScheduler::Unload(Thread* thread) {
|
||||||
|
|
||||||
void KScheduler::Reload(Thread* thread) {
|
void KScheduler::Reload(Thread* thread) {
|
||||||
if (thread) {
|
if (thread) {
|
||||||
ASSERT_MSG(thread->GetSchedulingStatus() == ThreadSchedStatus::Runnable,
|
ASSERT_MSG(thread->GetState() == ThreadSchedStatus::Runnable, "Thread must be runnable.");
|
||||||
"Thread must be runnable.");
|
|
||||||
|
|
||||||
// Cancel any outstanding wakeup events for this thread
|
// Cancel any outstanding wakeup events for this thread
|
||||||
thread->SetIsRunning(true);
|
thread->SetIsRunning(true);
|
||||||
|
@ -772,7 +771,7 @@ void KScheduler::Initialize() {
|
||||||
|
|
||||||
{
|
{
|
||||||
KScopedSchedulerLock lock{system.Kernel()};
|
KScopedSchedulerLock lock{system.Kernel()};
|
||||||
idle_thread->SetStatus(ThreadStatus::Ready);
|
idle_thread->SetState(ThreadStatus::Ready);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
171
src/core/hle/kernel/k_synchronization_object.cpp
Normal file
171
src/core/hle/kernel/k_synchronization_object.cpp
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
// Copyright 2021 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "common/assert.h"
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
|
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
||||||
|
#include "core/hle/kernel/k_synchronization_object.h"
|
||||||
|
#include "core/hle/kernel/kernel.h"
|
||||||
|
#include "core/hle/kernel/svc_results.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
|
||||||
|
ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index,
|
||||||
|
KSynchronizationObject** objects, const s32 num_objects,
|
||||||
|
s64 timeout) {
|
||||||
|
// Allocate space on stack for thread nodes.
|
||||||
|
std::vector<ThreadListNode> thread_nodes(num_objects);
|
||||||
|
|
||||||
|
// Prepare for wait.
|
||||||
|
Thread* thread = kernel.CurrentScheduler()->GetCurrentThread();
|
||||||
|
Handle timer = InvalidHandle;
|
||||||
|
|
||||||
|
{
|
||||||
|
// Setup the scheduling lock and sleep.
|
||||||
|
KScopedSchedulerLockAndSleep slp(kernel, timer, thread, timeout);
|
||||||
|
|
||||||
|
// Check if any of the objects are already signaled.
|
||||||
|
for (auto i = 0; i < num_objects; ++i) {
|
||||||
|
ASSERT(objects[i] != nullptr);
|
||||||
|
|
||||||
|
if (objects[i]->IsSignaled()) {
|
||||||
|
*out_index = i;
|
||||||
|
slp.CancelSleep();
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the timeout is zero.
|
||||||
|
if (timeout == 0) {
|
||||||
|
slp.CancelSleep();
|
||||||
|
return Svc::ResultTimedOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the thread should terminate.
|
||||||
|
if (thread->IsTerminationRequested()) {
|
||||||
|
slp.CancelSleep();
|
||||||
|
return Svc::ResultTerminationRequested;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if waiting was canceled.
|
||||||
|
if (thread->IsWaitCancelled()) {
|
||||||
|
slp.CancelSleep();
|
||||||
|
thread->ClearWaitCancelled();
|
||||||
|
return Svc::ResultCancelled;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the waiters.
|
||||||
|
for (auto i = 0; i < num_objects; ++i) {
|
||||||
|
thread_nodes[i].thread = thread;
|
||||||
|
thread_nodes[i].next = nullptr;
|
||||||
|
|
||||||
|
if (objects[i]->thread_list_tail == nullptr) {
|
||||||
|
objects[i]->thread_list_head = std::addressof(thread_nodes[i]);
|
||||||
|
} else {
|
||||||
|
objects[i]->thread_list_tail->next = std::addressof(thread_nodes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
objects[i]->thread_list_tail = std::addressof(thread_nodes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For debugging only
|
||||||
|
thread->SetWaitObjectsForDebugging(objects, num_objects);
|
||||||
|
|
||||||
|
// Mark the thread as waiting.
|
||||||
|
thread->SetCancellable();
|
||||||
|
thread->SetSyncedObject(nullptr, Svc::ResultTimedOut);
|
||||||
|
thread->SetState(ThreadState::WaitSynch);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The lock/sleep is done, so we should be able to get our result.
|
||||||
|
|
||||||
|
// Thread is no longer cancellable.
|
||||||
|
thread->ClearCancellable();
|
||||||
|
|
||||||
|
// For debugging only
|
||||||
|
thread->SetWaitObjectsForDebugging(nullptr, 0);
|
||||||
|
|
||||||
|
// Cancel the timer as needed.
|
||||||
|
if (timer != InvalidHandle) {
|
||||||
|
auto& time_manager = kernel.TimeManager();
|
||||||
|
time_manager.UnscheduleTimeEvent(timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the wait result.
|
||||||
|
ResultCode wait_result{RESULT_SUCCESS};
|
||||||
|
s32 sync_index = -1;
|
||||||
|
{
|
||||||
|
KScopedSchedulerLock lock(kernel);
|
||||||
|
KSynchronizationObject* synced_obj;
|
||||||
|
wait_result = thread->GetWaitResult(std::addressof(synced_obj));
|
||||||
|
|
||||||
|
for (auto i = 0; i < num_objects; ++i) {
|
||||||
|
// Unlink the object from the list.
|
||||||
|
ThreadListNode* prev_ptr =
|
||||||
|
reinterpret_cast<ThreadListNode*>(std::addressof(objects[i]->thread_list_head));
|
||||||
|
ThreadListNode* prev_val = nullptr;
|
||||||
|
ThreadListNode *prev, *tail_prev;
|
||||||
|
|
||||||
|
do {
|
||||||
|
prev = prev_ptr;
|
||||||
|
prev_ptr = prev_ptr->next;
|
||||||
|
tail_prev = prev_val;
|
||||||
|
prev_val = prev_ptr;
|
||||||
|
} while (prev_ptr != std::addressof(thread_nodes[i]));
|
||||||
|
|
||||||
|
if (objects[i]->thread_list_tail == std::addressof(thread_nodes[i])) {
|
||||||
|
objects[i]->thread_list_tail = tail_prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
prev->next = thread_nodes[i].next;
|
||||||
|
|
||||||
|
if (objects[i] == synced_obj) {
|
||||||
|
sync_index = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set output.
|
||||||
|
*out_index = sync_index;
|
||||||
|
return wait_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
KSynchronizationObject::KSynchronizationObject(KernelCore& kernel) : Object{kernel} {}
|
||||||
|
|
||||||
|
KSynchronizationObject ::~KSynchronizationObject() = default;
|
||||||
|
|
||||||
|
void KSynchronizationObject::NotifyAvailable(ResultCode result) {
|
||||||
|
KScopedSchedulerLock lock(kernel);
|
||||||
|
|
||||||
|
// If we're not signaled, we've nothing to notify.
|
||||||
|
if (!this->IsSignaled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate over each thread.
|
||||||
|
for (auto* cur_node = thread_list_head; cur_node != nullptr; cur_node = cur_node->next) {
|
||||||
|
Thread* thread = cur_node->thread;
|
||||||
|
if (thread->GetState() == ThreadSchedStatus::Paused) {
|
||||||
|
thread->SetSyncedObject(this, result);
|
||||||
|
thread->SetState(ThreadStatus::Ready);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Thread*> KSynchronizationObject::GetWaitingThreadsForDebugging() const {
|
||||||
|
std::vector<Thread*> threads;
|
||||||
|
|
||||||
|
// If debugging, dump the list of waiters.
|
||||||
|
{
|
||||||
|
KScopedSchedulerLock lock(kernel);
|
||||||
|
for (auto* cur_node = thread_list_head; cur_node != nullptr; cur_node = cur_node->next) {
|
||||||
|
threads.emplace_back(cur_node->thread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return threads;
|
||||||
|
}
|
||||||
|
} // namespace Kernel
|
58
src/core/hle/kernel/k_synchronization_object.h
Normal file
58
src/core/hle/kernel/k_synchronization_object.h
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
// Copyright 2021 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "core/hle/kernel/object.h"
|
||||||
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
|
||||||
|
class KernelCore;
|
||||||
|
class Synchronization;
|
||||||
|
class Thread;
|
||||||
|
|
||||||
|
/// Class that represents a Kernel object that a thread can be waiting on
|
||||||
|
class KSynchronizationObject : public Object {
|
||||||
|
public:
|
||||||
|
struct ThreadListNode {
|
||||||
|
ThreadListNode* next{};
|
||||||
|
Thread* thread{};
|
||||||
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] static ResultCode Wait(KernelCore& kernel, s32* out_index,
|
||||||
|
KSynchronizationObject** objects, const s32 num_objects,
|
||||||
|
s64 timeout);
|
||||||
|
|
||||||
|
[[nodiscard]] virtual bool IsSignaled() const = 0;
|
||||||
|
|
||||||
|
[[nodiscard]] std::vector<Thread*> GetWaitingThreadsForDebugging() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
explicit KSynchronizationObject(KernelCore& kernel);
|
||||||
|
virtual ~KSynchronizationObject();
|
||||||
|
|
||||||
|
void NotifyAvailable(ResultCode result);
|
||||||
|
void NotifyAvailable() {
|
||||||
|
return this->NotifyAvailable(RESULT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ThreadListNode* thread_list_head{};
|
||||||
|
ThreadListNode* thread_list_tail{};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Specialization of DynamicObjectCast for KSynchronizationObjects
|
||||||
|
template <>
|
||||||
|
inline std::shared_ptr<KSynchronizationObject> DynamicObjectCast<KSynchronizationObject>(
|
||||||
|
std::shared_ptr<Object> object) {
|
||||||
|
if (object != nullptr && object->IsWaitable()) {
|
||||||
|
return std::static_pointer_cast<KSynchronizationObject>(object);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Kernel
|
|
@ -38,7 +38,6 @@
|
||||||
#include "core/hle/kernel/resource_limit.h"
|
#include "core/hle/kernel/resource_limit.h"
|
||||||
#include "core/hle/kernel/service_thread.h"
|
#include "core/hle/kernel/service_thread.h"
|
||||||
#include "core/hle/kernel/shared_memory.h"
|
#include "core/hle/kernel/shared_memory.h"
|
||||||
#include "core/hle/kernel/synchronization.h"
|
|
||||||
#include "core/hle/kernel/thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/kernel/time_manager.h"
|
#include "core/hle/kernel/time_manager.h"
|
||||||
#include "core/hle/lock.h"
|
#include "core/hle/lock.h"
|
||||||
|
@ -51,8 +50,7 @@ namespace Kernel {
|
||||||
|
|
||||||
struct KernelCore::Impl {
|
struct KernelCore::Impl {
|
||||||
explicit Impl(Core::System& system, KernelCore& kernel)
|
explicit Impl(Core::System& system, KernelCore& kernel)
|
||||||
: synchronization{system}, time_manager{system}, global_handle_table{kernel}, system{
|
: time_manager{system}, global_handle_table{kernel}, system{system} {}
|
||||||
system} {}
|
|
||||||
|
|
||||||
void SetMulticore(bool is_multicore) {
|
void SetMulticore(bool is_multicore) {
|
||||||
this->is_multicore = is_multicore;
|
this->is_multicore = is_multicore;
|
||||||
|
@ -307,7 +305,6 @@ struct KernelCore::Impl {
|
||||||
std::vector<std::shared_ptr<Process>> process_list;
|
std::vector<std::shared_ptr<Process>> process_list;
|
||||||
Process* current_process = nullptr;
|
Process* current_process = nullptr;
|
||||||
std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context;
|
std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context;
|
||||||
Kernel::Synchronization synchronization;
|
|
||||||
Kernel::TimeManager time_manager;
|
Kernel::TimeManager time_manager;
|
||||||
|
|
||||||
std::shared_ptr<ResourceLimit> system_resource_limit;
|
std::shared_ptr<ResourceLimit> system_resource_limit;
|
||||||
|
@ -461,14 +458,6 @@ const std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& Kern
|
||||||
return impl->interrupts;
|
return impl->interrupts;
|
||||||
}
|
}
|
||||||
|
|
||||||
Kernel::Synchronization& KernelCore::Synchronization() {
|
|
||||||
return impl->synchronization;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Kernel::Synchronization& KernelCore::Synchronization() const {
|
|
||||||
return impl->synchronization;
|
|
||||||
}
|
|
||||||
|
|
||||||
Kernel::TimeManager& KernelCore::TimeManager() {
|
Kernel::TimeManager& KernelCore::TimeManager() {
|
||||||
return impl->time_manager;
|
return impl->time_manager;
|
||||||
}
|
}
|
||||||
|
@ -615,7 +604,7 @@ void KernelCore::Suspend(bool in_suspention) {
|
||||||
KScopedSchedulerLock lock(*this);
|
KScopedSchedulerLock lock(*this);
|
||||||
ThreadStatus status = should_suspend ? ThreadStatus::Ready : ThreadStatus::WaitSleep;
|
ThreadStatus status = should_suspend ? ThreadStatus::Ready : ThreadStatus::WaitSleep;
|
||||||
for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
|
for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
|
||||||
impl->suspend_threads[i]->SetStatus(status);
|
impl->suspend_threads[i]->SetState(status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,12 +129,6 @@ public:
|
||||||
/// Gets the an instance of the current physical CPU core.
|
/// Gets the an instance of the current physical CPU core.
|
||||||
const Kernel::PhysicalCore& CurrentPhysicalCore() const;
|
const Kernel::PhysicalCore& CurrentPhysicalCore() const;
|
||||||
|
|
||||||
/// Gets the an instance of the Synchronization Interface.
|
|
||||||
Kernel::Synchronization& Synchronization();
|
|
||||||
|
|
||||||
/// Gets the an instance of the Synchronization Interface.
|
|
||||||
const Kernel::Synchronization& Synchronization() const;
|
|
||||||
|
|
||||||
/// Gets the an instance of the TimeManager Interface.
|
/// Gets the an instance of the TimeManager Interface.
|
||||||
Kernel::TimeManager& TimeManager();
|
Kernel::TimeManager& TimeManager();
|
||||||
|
|
||||||
|
|
|
@ -107,7 +107,7 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle,
|
||||||
current_thread->SetMutexWaitAddress(address);
|
current_thread->SetMutexWaitAddress(address);
|
||||||
current_thread->SetWaitHandle(requesting_thread_handle);
|
current_thread->SetWaitHandle(requesting_thread_handle);
|
||||||
|
|
||||||
current_thread->SetStatus(ThreadStatus::WaitMutex);
|
current_thread->SetState(ThreadStatus::WaitMutex);
|
||||||
|
|
||||||
// Update the lock holder thread's priority to prevent priority inversion.
|
// Update the lock holder thread's priority to prevent priority inversion.
|
||||||
holding_thread->AddMutexWaiter(current_thread);
|
holding_thread->AddMutexWaiter(current_thread);
|
||||||
|
@ -145,7 +145,7 @@ std::pair<ResultCode, std::shared_ptr<Thread>> Mutex::Unlock(std::shared_ptr<Thr
|
||||||
}
|
}
|
||||||
new_owner->SetSynchronizationResults(nullptr, RESULT_SUCCESS);
|
new_owner->SetSynchronizationResults(nullptr, RESULT_SUCCESS);
|
||||||
new_owner->SetLockOwner(nullptr);
|
new_owner->SetLockOwner(nullptr);
|
||||||
new_owner->ResumeFromWait();
|
new_owner->Wakeup();
|
||||||
|
|
||||||
system.Memory().Write32(address, mutex_value);
|
system.Memory().Write32(address, mutex_value);
|
||||||
return {RESULT_SUCCESS, new_owner};
|
return {RESULT_SUCCESS, new_owner};
|
||||||
|
|
|
@ -55,7 +55,7 @@ void SetupMainThread(Core::System& system, Process& owner_process, u32 priority,
|
||||||
// Threads by default are dormant, wake up the main thread so it runs when the scheduler fires
|
// Threads by default are dormant, wake up the main thread so it runs when the scheduler fires
|
||||||
{
|
{
|
||||||
KScopedSchedulerLock lock{kernel};
|
KScopedSchedulerLock lock{kernel};
|
||||||
thread->SetStatus(ThreadStatus::Ready);
|
thread->SetState(ThreadStatus::Ready);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
@ -406,21 +406,18 @@ void Process::LoadModule(CodeSet code_set, VAddr base_addr) {
|
||||||
ReprotectSegment(code_set.DataSegment(), Memory::MemoryPermission::ReadAndWrite);
|
ReprotectSegment(code_set.DataSegment(), Memory::MemoryPermission::ReadAndWrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Process::IsSignaled() const {
|
||||||
|
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
|
||||||
|
return is_signaled;
|
||||||
|
}
|
||||||
|
|
||||||
Process::Process(Core::System& system)
|
Process::Process(Core::System& system)
|
||||||
: SynchronizationObject{system.Kernel()}, page_table{std::make_unique<Memory::PageTable>(
|
: KSynchronizationObject{system.Kernel()}, page_table{std::make_unique<Memory::PageTable>(
|
||||||
system)},
|
system)},
|
||||||
handle_table{system.Kernel()}, address_arbiter{system}, mutex{system}, system{system} {}
|
handle_table{system.Kernel()}, address_arbiter{system}, mutex{system}, system{system} {}
|
||||||
|
|
||||||
Process::~Process() = default;
|
Process::~Process() = default;
|
||||||
|
|
||||||
void Process::Acquire(Thread* thread) {
|
|
||||||
ASSERT_MSG(!ShouldWait(thread), "Object unavailable!");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Process::ShouldWait(const Thread* thread) const {
|
|
||||||
return !is_signaled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Process::ChangeStatus(ProcessStatus new_status) {
|
void Process::ChangeStatus(ProcessStatus new_status) {
|
||||||
if (status == new_status) {
|
if (status == new_status) {
|
||||||
return;
|
return;
|
||||||
|
@ -428,7 +425,7 @@ void Process::ChangeStatus(ProcessStatus new_status) {
|
||||||
|
|
||||||
status = new_status;
|
status = new_status;
|
||||||
is_signaled = true;
|
is_signaled = true;
|
||||||
Signal();
|
NotifyAvailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode Process::AllocateMainThreadStack(std::size_t stack_size) {
|
ResultCode Process::AllocateMainThreadStack(std::size_t stack_size) {
|
||||||
|
|
|
@ -13,9 +13,9 @@
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/hle/kernel/address_arbiter.h"
|
#include "core/hle/kernel/address_arbiter.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
#include "core/hle/kernel/handle_table.h"
|
||||||
|
#include "core/hle/kernel/k_synchronization_object.h"
|
||||||
#include "core/hle/kernel/mutex.h"
|
#include "core/hle/kernel/mutex.h"
|
||||||
#include "core/hle/kernel/process_capability.h"
|
#include "core/hle/kernel/process_capability.h"
|
||||||
#include "core/hle/kernel/synchronization_object.h"
|
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
@ -63,7 +63,7 @@ enum class ProcessStatus {
|
||||||
DebugBreak,
|
DebugBreak,
|
||||||
};
|
};
|
||||||
|
|
||||||
class Process final : public SynchronizationObject {
|
class Process final : public KSynchronizationObject {
|
||||||
public:
|
public:
|
||||||
explicit Process(Core::System& system);
|
explicit Process(Core::System& system);
|
||||||
~Process() override;
|
~Process() override;
|
||||||
|
@ -304,6 +304,8 @@ public:
|
||||||
|
|
||||||
void LoadModule(CodeSet code_set, VAddr base_addr);
|
void LoadModule(CodeSet code_set, VAddr base_addr);
|
||||||
|
|
||||||
|
bool IsSignaled() const override;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Thread-local storage management
|
// Thread-local storage management
|
||||||
|
|
||||||
|
@ -314,12 +316,6 @@ public:
|
||||||
void FreeTLSRegion(VAddr tls_address);
|
void FreeTLSRegion(VAddr tls_address);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Checks if the specified thread should wait until this process is available.
|
|
||||||
bool ShouldWait(const Thread* thread) const override;
|
|
||||||
|
|
||||||
/// Acquires/locks this process for the specified thread if it's available.
|
|
||||||
void Acquire(Thread* thread) override;
|
|
||||||
|
|
||||||
/// Changes the process status. If the status is different
|
/// Changes the process status. If the status is different
|
||||||
/// from the current process status, then this will trigger
|
/// from the current process status, then this will trigger
|
||||||
/// a process signal.
|
/// a process signal.
|
||||||
|
@ -410,6 +406,8 @@ private:
|
||||||
/// Schedule count of this process
|
/// Schedule count of this process
|
||||||
s64 schedule_count{};
|
s64 schedule_count{};
|
||||||
|
|
||||||
|
bool is_signaled{};
|
||||||
|
|
||||||
/// System context
|
/// System context
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,24 +14,22 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
ReadableEvent::ReadableEvent(KernelCore& kernel) : SynchronizationObject{kernel} {}
|
ReadableEvent::ReadableEvent(KernelCore& kernel) : KSynchronizationObject{kernel} {}
|
||||||
ReadableEvent::~ReadableEvent() = default;
|
ReadableEvent::~ReadableEvent() = default;
|
||||||
|
|
||||||
bool ReadableEvent::ShouldWait(const Thread* thread) const {
|
|
||||||
return !is_signaled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReadableEvent::Acquire(Thread* thread) {
|
|
||||||
ASSERT_MSG(IsSignaled(), "object unavailable!");
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReadableEvent::Signal() {
|
void ReadableEvent::Signal() {
|
||||||
if (is_signaled) {
|
if (is_signaled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
is_signaled = true;
|
is_signaled = true;
|
||||||
SynchronizationObject::Signal();
|
NotifyAvailable();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadableEvent::IsSignaled() const {
|
||||||
|
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
|
||||||
|
|
||||||
|
return is_signaled;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReadableEvent::Clear() {
|
void ReadableEvent::Clear() {
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/kernel/k_synchronization_object.h"
|
||||||
#include "core/hle/kernel/object.h"
|
#include "core/hle/kernel/object.h"
|
||||||
#include "core/hle/kernel/synchronization_object.h"
|
|
||||||
|
|
||||||
union ResultCode;
|
union ResultCode;
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ namespace Kernel {
|
||||||
class KernelCore;
|
class KernelCore;
|
||||||
class WritableEvent;
|
class WritableEvent;
|
||||||
|
|
||||||
class ReadableEvent final : public SynchronizationObject {
|
class ReadableEvent final : public KSynchronizationObject {
|
||||||
friend class WritableEvent;
|
friend class WritableEvent;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -32,9 +32,6 @@ public:
|
||||||
return HANDLE_TYPE;
|
return HANDLE_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShouldWait(const Thread* thread) const override;
|
|
||||||
void Acquire(Thread* thread) override;
|
|
||||||
|
|
||||||
/// Unconditionally clears the readable event's state.
|
/// Unconditionally clears the readable event's state.
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
|
@ -46,11 +43,14 @@ public:
|
||||||
/// then ERR_INVALID_STATE will be returned.
|
/// then ERR_INVALID_STATE will be returned.
|
||||||
ResultCode Reset();
|
ResultCode Reset();
|
||||||
|
|
||||||
void Signal() override;
|
void Signal();
|
||||||
|
|
||||||
|
bool IsSignaled() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit ReadableEvent(KernelCore& kernel);
|
explicit ReadableEvent(KernelCore& kernel);
|
||||||
|
|
||||||
|
bool is_signaled{};
|
||||||
std::string name; ///< Name of event (optional)
|
std::string name; ///< Name of event (optional)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
ServerPort::ServerPort(KernelCore& kernel) : SynchronizationObject{kernel} {}
|
ServerPort::ServerPort(KernelCore& kernel) : KSynchronizationObject{kernel} {}
|
||||||
ServerPort::~ServerPort() = default;
|
ServerPort::~ServerPort() = default;
|
||||||
|
|
||||||
ResultVal<std::shared_ptr<ServerSession>> ServerPort::Accept() {
|
ResultVal<std::shared_ptr<ServerSession>> ServerPort::Accept() {
|
||||||
|
@ -28,15 +28,9 @@ ResultVal<std::shared_ptr<ServerSession>> ServerPort::Accept() {
|
||||||
|
|
||||||
void ServerPort::AppendPendingSession(std::shared_ptr<ServerSession> pending_session) {
|
void ServerPort::AppendPendingSession(std::shared_ptr<ServerSession> pending_session) {
|
||||||
pending_sessions.push_back(std::move(pending_session));
|
pending_sessions.push_back(std::move(pending_session));
|
||||||
}
|
if (pending_sessions.size() == 1) {
|
||||||
|
NotifyAvailable();
|
||||||
bool ServerPort::ShouldWait(const Thread* thread) const {
|
}
|
||||||
// If there are no pending sessions, we wait until a new one is added.
|
|
||||||
return pending_sessions.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerPort::Acquire(Thread* thread) {
|
|
||||||
ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ServerPort::IsSignaled() const {
|
bool ServerPort::IsSignaled() const {
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "core/hle/kernel/k_synchronization_object.h"
|
||||||
#include "core/hle/kernel/object.h"
|
#include "core/hle/kernel/object.h"
|
||||||
#include "core/hle/kernel/synchronization_object.h"
|
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
@ -20,7 +20,7 @@ class KernelCore;
|
||||||
class ServerSession;
|
class ServerSession;
|
||||||
class SessionRequestHandler;
|
class SessionRequestHandler;
|
||||||
|
|
||||||
class ServerPort final : public SynchronizationObject {
|
class ServerPort final : public KSynchronizationObject {
|
||||||
public:
|
public:
|
||||||
explicit ServerPort(KernelCore& kernel);
|
explicit ServerPort(KernelCore& kernel);
|
||||||
~ServerPort() override;
|
~ServerPort() override;
|
||||||
|
@ -79,9 +79,6 @@ public:
|
||||||
/// waiting to be accepted by this port.
|
/// waiting to be accepted by this port.
|
||||||
void AppendPendingSession(std::shared_ptr<ServerSession> pending_session);
|
void AppendPendingSession(std::shared_ptr<ServerSession> pending_session);
|
||||||
|
|
||||||
bool ShouldWait(const Thread* thread) const override;
|
|
||||||
void Acquire(Thread* thread) override;
|
|
||||||
|
|
||||||
bool IsSignaled() const override;
|
bool IsSignaled() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
ServerSession::ServerSession(KernelCore& kernel) : SynchronizationObject{kernel} {}
|
ServerSession::ServerSession(KernelCore& kernel) : KSynchronizationObject{kernel} {}
|
||||||
|
|
||||||
ServerSession::~ServerSession() {
|
ServerSession::~ServerSession() {
|
||||||
kernel.ReleaseServiceThread(service_thread);
|
kernel.ReleaseServiceThread(service_thread);
|
||||||
|
@ -42,16 +42,6 @@ ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kern
|
||||||
return MakeResult(std::move(session));
|
return MakeResult(std::move(session));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ServerSession::ShouldWait(const Thread* thread) const {
|
|
||||||
// Closed sessions should never wait, an error will be returned from svcReplyAndReceive.
|
|
||||||
if (!parent->Client()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait if we have no pending requests, or if we're currently handling a request.
|
|
||||||
return pending_requesting_threads.empty() || currently_handling != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ServerSession::IsSignaled() const {
|
bool ServerSession::IsSignaled() const {
|
||||||
// Closed sessions should never wait, an error will be returned from svcReplyAndReceive.
|
// Closed sessions should never wait, an error will be returned from svcReplyAndReceive.
|
||||||
if (!parent->Client()) {
|
if (!parent->Client()) {
|
||||||
|
@ -62,15 +52,6 @@ bool ServerSession::IsSignaled() const {
|
||||||
return !pending_requesting_threads.empty() && currently_handling == nullptr;
|
return !pending_requesting_threads.empty() && currently_handling == nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerSession::Acquire(Thread* thread) {
|
|
||||||
ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
|
|
||||||
// We are now handling a request, pop it from the stack.
|
|
||||||
// TODO(Subv): What happens if the client endpoint is closed before any requests are made?
|
|
||||||
ASSERT(!pending_requesting_threads.empty());
|
|
||||||
currently_handling = pending_requesting_threads.back();
|
|
||||||
pending_requesting_threads.pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerSession::ClientDisconnected() {
|
void ServerSession::ClientDisconnected() {
|
||||||
// We keep a shared pointer to the hle handler to keep it alive throughout
|
// We keep a shared pointer to the hle handler to keep it alive throughout
|
||||||
// the call to ClientDisconnected, as ClientDisconnected invalidates the
|
// the call to ClientDisconnected, as ClientDisconnected invalidates the
|
||||||
|
@ -172,7 +153,7 @@ ResultCode ServerSession::CompleteSyncRequest(HLERequestContext& context) {
|
||||||
{
|
{
|
||||||
KScopedSchedulerLock lock(kernel);
|
KScopedSchedulerLock lock(kernel);
|
||||||
if (!context.IsThreadWaiting()) {
|
if (!context.IsThreadWaiting()) {
|
||||||
context.GetThread().ResumeFromWait();
|
context.GetThread().Wakeup();
|
||||||
context.GetThread().SetSynchronizationResults(nullptr, result);
|
context.GetThread().SetSynchronizationResults(nullptr, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "common/threadsafe_queue.h"
|
#include "common/threadsafe_queue.h"
|
||||||
|
#include "core/hle/kernel/k_synchronization_object.h"
|
||||||
#include "core/hle/kernel/service_thread.h"
|
#include "core/hle/kernel/service_thread.h"
|
||||||
#include "core/hle/kernel/synchronization_object.h"
|
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
namespace Core::Memory {
|
namespace Core::Memory {
|
||||||
|
@ -43,7 +43,7 @@ class Thread;
|
||||||
* After the server replies to the request, the response is marshalled back to the caller's
|
* After the server replies to the request, the response is marshalled back to the caller's
|
||||||
* TLS buffer and control is transferred back to it.
|
* TLS buffer and control is transferred back to it.
|
||||||
*/
|
*/
|
||||||
class ServerSession final : public SynchronizationObject {
|
class ServerSession final : public KSynchronizationObject {
|
||||||
friend class ServiceThread;
|
friend class ServiceThread;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -77,8 +77,6 @@ public:
|
||||||
return parent.get();
|
return parent.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsSignaled() const override;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the HLE handler for the session. This handler will be called to service IPC requests
|
* Sets the HLE handler for the session. This handler will be called to service IPC requests
|
||||||
* instead of the regular IPC machinery. (The regular IPC machinery is currently not
|
* instead of the regular IPC machinery. (The regular IPC machinery is currently not
|
||||||
|
@ -100,10 +98,6 @@ public:
|
||||||
ResultCode HandleSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory,
|
ResultCode HandleSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory,
|
||||||
Core::Timing::CoreTiming& core_timing);
|
Core::Timing::CoreTiming& core_timing);
|
||||||
|
|
||||||
bool ShouldWait(const Thread* thread) const override;
|
|
||||||
|
|
||||||
void Acquire(Thread* thread) override;
|
|
||||||
|
|
||||||
/// Called when a client disconnection occurs.
|
/// Called when a client disconnection occurs.
|
||||||
void ClientDisconnected();
|
void ClientDisconnected();
|
||||||
|
|
||||||
|
@ -130,6 +124,8 @@ public:
|
||||||
convert_to_domain = true;
|
convert_to_domain = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsSignaled() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Queues a sync request from the emulated application.
|
/// Queues a sync request from the emulated application.
|
||||||
ResultCode QueueSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory);
|
ResultCode QueueSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory);
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
Session::Session(KernelCore& kernel) : SynchronizationObject{kernel} {}
|
Session::Session(KernelCore& kernel) : KSynchronizationObject{kernel} {}
|
||||||
Session::~Session() = default;
|
Session::~Session() = default;
|
||||||
|
|
||||||
Session::SessionPair Session::Create(KernelCore& kernel, std::string name) {
|
Session::SessionPair Session::Create(KernelCore& kernel, std::string name) {
|
||||||
|
@ -24,18 +24,9 @@ Session::SessionPair Session::Create(KernelCore& kernel, std::string name) {
|
||||||
return std::make_pair(std::move(client_session), std::move(server_session));
|
return std::make_pair(std::move(client_session), std::move(server_session));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Session::ShouldWait(const Thread* thread) const {
|
|
||||||
UNIMPLEMENTED();
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::IsSignaled() const {
|
bool Session::IsSignaled() const {
|
||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::Acquire(Thread* thread) {
|
|
||||||
UNIMPLEMENTED();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "core/hle/kernel/synchronization_object.h"
|
#include "core/hle/kernel/k_synchronization_object.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ class ServerSession;
|
||||||
* Parent structure to link the client and server endpoints of a session with their associated
|
* Parent structure to link the client and server endpoints of a session with their associated
|
||||||
* client port.
|
* client port.
|
||||||
*/
|
*/
|
||||||
class Session final : public SynchronizationObject {
|
class Session final : public KSynchronizationObject {
|
||||||
public:
|
public:
|
||||||
explicit Session(KernelCore& kernel);
|
explicit Session(KernelCore& kernel);
|
||||||
~Session() override;
|
~Session() override;
|
||||||
|
@ -37,12 +37,8 @@ public:
|
||||||
return HANDLE_TYPE;
|
return HANDLE_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShouldWait(const Thread* thread) const override;
|
|
||||||
|
|
||||||
bool IsSignaled() const override;
|
bool IsSignaled() const override;
|
||||||
|
|
||||||
void Acquire(Thread* thread) override;
|
|
||||||
|
|
||||||
std::shared_ptr<ClientSession> Client() {
|
std::shared_ptr<ClientSession> Client() {
|
||||||
if (auto result{client.lock()}) {
|
if (auto result{client.lock()}) {
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "core/hle/kernel/handle_table.h"
|
#include "core/hle/kernel/handle_table.h"
|
||||||
#include "core/hle/kernel/k_scheduler.h"
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
||||||
|
#include "core/hle/kernel/k_synchronization_object.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/memory/memory_block.h"
|
#include "core/hle/kernel/memory/memory_block.h"
|
||||||
#include "core/hle/kernel/memory/page_table.h"
|
#include "core/hle/kernel/memory/page_table.h"
|
||||||
|
@ -38,7 +39,6 @@
|
||||||
#include "core/hle/kernel/svc.h"
|
#include "core/hle/kernel/svc.h"
|
||||||
#include "core/hle/kernel/svc_types.h"
|
#include "core/hle/kernel/svc_types.h"
|
||||||
#include "core/hle/kernel/svc_wrap.h"
|
#include "core/hle/kernel/svc_wrap.h"
|
||||||
#include "core/hle/kernel/synchronization.h"
|
|
||||||
#include "core/hle/kernel/thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/kernel/time_manager.h"
|
#include "core/hle/kernel/time_manager.h"
|
||||||
#include "core/hle/kernel/transfer_memory.h"
|
#include "core/hle/kernel/transfer_memory.h"
|
||||||
|
@ -343,27 +343,16 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) {
|
||||||
auto thread = kernel.CurrentScheduler()->GetCurrentThread();
|
auto thread = kernel.CurrentScheduler()->GetCurrentThread();
|
||||||
{
|
{
|
||||||
KScopedSchedulerLock lock(kernel);
|
KScopedSchedulerLock lock(kernel);
|
||||||
thread->InvalidateHLECallback();
|
thread->SetState(ThreadStatus::WaitIPC);
|
||||||
thread->SetStatus(ThreadStatus::WaitIPC);
|
|
||||||
session->SendSyncRequest(SharedFrom(thread), system.Memory(), system.CoreTiming());
|
session->SendSyncRequest(SharedFrom(thread), system.Memory(), system.CoreTiming());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (thread->HasHLECallback()) {
|
|
||||||
Handle event_handle = thread->GetHLETimeEvent();
|
Handle event_handle = thread->GetHLETimeEvent();
|
||||||
if (event_handle != InvalidHandle) {
|
if (event_handle != InvalidHandle) {
|
||||||
auto& time_manager = kernel.TimeManager();
|
auto& time_manager = kernel.TimeManager();
|
||||||
time_manager.UnscheduleTimeEvent(event_handle);
|
time_manager.UnscheduleTimeEvent(event_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
KScopedSchedulerLock lock(kernel);
|
|
||||||
auto* sync_object = thread->GetHLESyncObject();
|
|
||||||
sync_object->RemoveWaitingThread(SharedFrom(thread));
|
|
||||||
}
|
|
||||||
|
|
||||||
thread->InvokeHLECallback(SharedFrom(thread));
|
|
||||||
}
|
|
||||||
|
|
||||||
return thread->GetSignalingResult();
|
return thread->GetSignalingResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -436,7 +425,7 @@ static ResultCode GetProcessId32(Core::System& system, u32* process_id_low, u32*
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
|
/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
|
||||||
static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr handles_address,
|
static ResultCode WaitSynchronization(Core::System& system, s32* index, VAddr handles_address,
|
||||||
u64 handle_count, s64 nano_seconds) {
|
u64 handle_count, s64 nano_seconds) {
|
||||||
LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}",
|
LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}",
|
||||||
handles_address, handle_count, nano_seconds);
|
handles_address, handle_count, nano_seconds);
|
||||||
|
@ -458,28 +447,26 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& kernel = system.Kernel();
|
auto& kernel = system.Kernel();
|
||||||
Thread::ThreadSynchronizationObjects objects(handle_count);
|
std::vector<KSynchronizationObject*> objects(handle_count);
|
||||||
const auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
|
const auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
|
||||||
|
|
||||||
for (u64 i = 0; i < handle_count; ++i) {
|
for (u64 i = 0; i < handle_count; ++i) {
|
||||||
const Handle handle = memory.Read32(handles_address + i * sizeof(Handle));
|
const Handle handle = memory.Read32(handles_address + i * sizeof(Handle));
|
||||||
const auto object = handle_table.Get<SynchronizationObject>(handle);
|
const auto object = handle_table.Get<KSynchronizationObject>(handle);
|
||||||
|
|
||||||
if (object == nullptr) {
|
if (object == nullptr) {
|
||||||
LOG_ERROR(Kernel_SVC, "Object is a nullptr");
|
LOG_ERROR(Kernel_SVC, "Object is a nullptr");
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
objects[i] = object;
|
objects[i] = object.get();
|
||||||
}
|
}
|
||||||
auto& synchronization = kernel.Synchronization();
|
return KSynchronizationObject::Wait(kernel, index, objects.data(),
|
||||||
const auto [result, handle_result] = synchronization.WaitFor(objects, nano_seconds);
|
static_cast<s32>(objects.size()), nano_seconds);
|
||||||
*index = handle_result;
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ResultCode WaitSynchronization32(Core::System& system, u32 timeout_low, u32 handles_address,
|
static ResultCode WaitSynchronization32(Core::System& system, u32 timeout_low, u32 handles_address,
|
||||||
s32 handle_count, u32 timeout_high, Handle* index) {
|
s32 handle_count, u32 timeout_high, s32* index) {
|
||||||
const s64 nano_seconds{(static_cast<s64>(timeout_high) << 32) | static_cast<s64>(timeout_low)};
|
const s64 nano_seconds{(static_cast<s64>(timeout_high) << 32) | static_cast<s64>(timeout_low)};
|
||||||
return WaitSynchronization(system, index, handles_address, handle_count, nano_seconds);
|
return WaitSynchronization(system, index, handles_address, handle_count, nano_seconds);
|
||||||
}
|
}
|
||||||
|
@ -1655,7 +1642,7 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add
|
||||||
|
|
||||||
current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT);
|
current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT);
|
||||||
|
|
||||||
if (thread->IsPendingTermination()) {
|
if (thread->IsTerminationRequested()) {
|
||||||
lock.CancelSleep();
|
lock.CancelSleep();
|
||||||
return ERR_THREAD_TERMINATING;
|
return ERR_THREAD_TERMINATING;
|
||||||
}
|
}
|
||||||
|
@ -1674,7 +1661,7 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add
|
||||||
current_thread->SetCondVarWaitAddress(condition_variable_addr);
|
current_thread->SetCondVarWaitAddress(condition_variable_addr);
|
||||||
current_thread->SetMutexWaitAddress(mutex_addr);
|
current_thread->SetMutexWaitAddress(mutex_addr);
|
||||||
current_thread->SetWaitHandle(thread_handle);
|
current_thread->SetWaitHandle(thread_handle);
|
||||||
current_thread->SetStatus(ThreadStatus::WaitCondVar);
|
current_thread->SetState(ThreadStatus::WaitCondVar);
|
||||||
current_process->InsertConditionVariableThread(SharedFrom(current_thread));
|
current_process->InsertConditionVariableThread(SharedFrom(current_thread));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1761,7 +1748,7 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_
|
||||||
|
|
||||||
thread->SetLockOwner(nullptr);
|
thread->SetLockOwner(nullptr);
|
||||||
thread->SetSynchronizationResults(nullptr, RESULT_SUCCESS);
|
thread->SetSynchronizationResults(nullptr, RESULT_SUCCESS);
|
||||||
thread->ResumeFromWait();
|
thread->Wakeup();
|
||||||
} else {
|
} else {
|
||||||
// The mutex is already owned by some other thread, make this thread wait on it.
|
// The mutex is already owned by some other thread, make this thread wait on it.
|
||||||
const Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask);
|
const Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask);
|
||||||
|
@ -1769,7 +1756,7 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_
|
||||||
auto owner = handle_table.Get<Thread>(owner_handle);
|
auto owner = handle_table.Get<Thread>(owner_handle);
|
||||||
ASSERT(owner);
|
ASSERT(owner);
|
||||||
if (thread->GetStatus() == ThreadStatus::WaitCondVar) {
|
if (thread->GetStatus() == ThreadStatus::WaitCondVar) {
|
||||||
thread->SetStatus(ThreadStatus::WaitMutex);
|
thread->SetState(ThreadStatus::WaitMutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
owner->AddMutexWaiter(thread);
|
owner->AddMutexWaiter(thread);
|
||||||
|
|
|
@ -215,9 +215,10 @@ void SvcWrap64(Core::System& system) {
|
||||||
func(system, static_cast<u32>(Param(system, 0)), Param(system, 1), Param(system, 2)).raw);
|
func(system, static_cast<u32>(Param(system, 0)), Param(system, 1), Param(system, 2)).raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <ResultCode func(Core::System&, u32*, u64, u64, s64)>
|
// Used by WaitSynchronization
|
||||||
|
template <ResultCode func(Core::System&, s32*, u64, u64, s64)>
|
||||||
void SvcWrap64(Core::System& system) {
|
void SvcWrap64(Core::System& system) {
|
||||||
u32 param_1 = 0;
|
s32 param_1 = 0;
|
||||||
const u32 retval = func(system, ¶m_1, Param(system, 1), static_cast<u32>(Param(system, 2)),
|
const u32 retval = func(system, ¶m_1, Param(system, 1), static_cast<u32>(Param(system, 2)),
|
||||||
static_cast<s64>(Param(system, 3)))
|
static_cast<s64>(Param(system, 3)))
|
||||||
.raw;
|
.raw;
|
||||||
|
@ -539,9 +540,9 @@ void SvcWrap32(Core::System& system) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used by WaitSynchronization32
|
// Used by WaitSynchronization32
|
||||||
template <ResultCode func(Core::System&, u32, u32, s32, u32, Handle*)>
|
template <ResultCode func(Core::System&, u32, u32, s32, u32, s32*)>
|
||||||
void SvcWrap32(Core::System& system) {
|
void SvcWrap32(Core::System& system) {
|
||||||
u32 param_1 = 0;
|
s32 param_1 = 0;
|
||||||
const u32 retval = func(system, Param32(system, 0), Param32(system, 1), Param32(system, 2),
|
const u32 retval = func(system, Param32(system, 0), Param32(system, 1), Param32(system, 2),
|
||||||
Param32(system, 3), ¶m_1)
|
Param32(system, 3), ¶m_1)
|
||||||
.raw;
|
.raw;
|
||||||
|
|
|
@ -1,116 +0,0 @@
|
||||||
// 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/k_scheduler.h"
|
|
||||||
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
|
||||||
#include "core/hle/kernel/kernel.h"
|
|
||||||
#include "core/hle/kernel/synchronization.h"
|
|
||||||
#include "core/hle/kernel/synchronization_object.h"
|
|
||||||
#include "core/hle/kernel/thread.h"
|
|
||||||
#include "core/hle/kernel/time_manager.h"
|
|
||||||
|
|
||||||
namespace Kernel {
|
|
||||||
|
|
||||||
Synchronization::Synchronization(Core::System& system) : system{system} {}
|
|
||||||
|
|
||||||
void Synchronization::SignalObject(SynchronizationObject& obj) const {
|
|
||||||
auto& kernel = system.Kernel();
|
|
||||||
KScopedSchedulerLock lock(kernel);
|
|
||||||
if (obj.IsSignaled()) {
|
|
||||||
for (auto thread : obj.GetWaitingThreads()) {
|
|
||||||
if (thread->GetSchedulingStatus() == ThreadSchedStatus::Paused) {
|
|
||||||
if (thread->GetStatus() != ThreadStatus::WaitHLEEvent) {
|
|
||||||
ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch);
|
|
||||||
ASSERT(thread->IsWaitingSync());
|
|
||||||
}
|
|
||||||
thread->SetSynchronizationResults(&obj, RESULT_SUCCESS);
|
|
||||||
thread->ResumeFromWait();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
obj.ClearWaitingThreads();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<ResultCode, Handle> Synchronization::WaitFor(
|
|
||||||
std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds) {
|
|
||||||
auto& kernel = system.Kernel();
|
|
||||||
auto* const thread = kernel.CurrentScheduler()->GetCurrentThread();
|
|
||||||
Handle event_handle = InvalidHandle;
|
|
||||||
{
|
|
||||||
KScopedSchedulerLockAndSleep 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};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (thread->IsPendingTermination()) {
|
|
||||||
lock.CancelSleep();
|
|
||||||
return {ERR_THREAD_TERMINATING, InvalidHandle};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (thread->IsSyncCancelled()) {
|
|
||||||
thread->SetSyncCancelled(false);
|
|
||||||
lock.CancelSleep();
|
|
||||||
return {ERR_SYNCHRONIZATION_CANCELED, InvalidHandle};
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& object : sync_objects) {
|
|
||||||
object->AddWaitingThread(SharedFrom(thread));
|
|
||||||
}
|
|
||||||
|
|
||||||
thread->SetSynchronizationObjects(&sync_objects);
|
|
||||||
thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT);
|
|
||||||
thread->SetStatus(ThreadStatus::WaitSynch);
|
|
||||||
thread->SetWaitingSync(true);
|
|
||||||
}
|
|
||||||
thread->SetWaitingSync(false);
|
|
||||||
|
|
||||||
if (event_handle != InvalidHandle) {
|
|
||||||
auto& time_manager = kernel.TimeManager();
|
|
||||||
time_manager.UnscheduleTimeEvent(event_handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
KScopedSchedulerLock lock(kernel);
|
|
||||||
ResultCode signaling_result = thread->GetSignalingResult();
|
|
||||||
SynchronizationObject* signaling_object = thread->GetSignalingObject();
|
|
||||||
thread->SetSynchronizationObjects(nullptr);
|
|
||||||
auto shared_thread = SharedFrom(thread);
|
|
||||||
for (auto& obj : sync_objects) {
|
|
||||||
obj->RemoveWaitingThread(shared_thread);
|
|
||||||
}
|
|
||||||
if (signaling_object != nullptr) {
|
|
||||||
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 {signaling_result, index};
|
|
||||||
}
|
|
||||||
return {signaling_result, -1};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Kernel
|
|
|
@ -1,44 +0,0 @@
|
||||||
// Copyright 2020 yuzu Emulator Project
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "core/hle/kernel/object.h"
|
|
||||||
#include "core/hle/result.h"
|
|
||||||
|
|
||||||
namespace Core {
|
|
||||||
class System;
|
|
||||||
} // namespace Core
|
|
||||||
|
|
||||||
namespace Kernel {
|
|
||||||
|
|
||||||
class SynchronizationObject;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The 'Synchronization' class is an interface for handling synchronization methods
|
|
||||||
* used by Synchronization objects and synchronization SVCs. This centralizes processing of
|
|
||||||
* such
|
|
||||||
*/
|
|
||||||
class Synchronization {
|
|
||||||
public:
|
|
||||||
explicit Synchronization(Core::System& system);
|
|
||||||
|
|
||||||
/// Signals a synchronization object, waking up all its waiting threads
|
|
||||||
void SignalObject(SynchronizationObject& obj) const;
|
|
||||||
|
|
||||||
/// Tries to see if waiting for any of the sync_objects is necessary, if not
|
|
||||||
/// it returns Success and the handle index of the signaled sync object. In
|
|
||||||
/// case not, the current thread will be locked and wait for nano_seconds or
|
|
||||||
/// for a synchronization object to signal.
|
|
||||||
std::pair<ResultCode, Handle> WaitFor(
|
|
||||||
std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Core::System& system;
|
|
||||||
};
|
|
||||||
} // namespace Kernel
|
|
|
@ -1,49 +0,0 @@
|
||||||
// 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"
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "common/logging/log.h"
|
|
||||||
#include "core/core.h"
|
|
||||||
#include "core/hle/kernel/kernel.h"
|
|
||||||
#include "core/hle/kernel/object.h"
|
|
||||||
#include "core/hle/kernel/process.h"
|
|
||||||
#include "core/hle/kernel/synchronization.h"
|
|
||||||
#include "core/hle/kernel/synchronization_object.h"
|
|
||||||
#include "core/hle/kernel/thread.h"
|
|
||||||
|
|
||||||
namespace Kernel {
|
|
||||||
|
|
||||||
SynchronizationObject::SynchronizationObject(KernelCore& kernel) : Object{kernel} {}
|
|
||||||
SynchronizationObject::~SynchronizationObject() = default;
|
|
||||||
|
|
||||||
void SynchronizationObject::Signal() {
|
|
||||||
kernel.Synchronization().SignalObject(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SynchronizationObject::AddWaitingThread(std::shared_ptr<Thread> thread) {
|
|
||||||
auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
|
|
||||||
if (itr == waiting_threads.end())
|
|
||||||
waiting_threads.push_back(std::move(thread));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SynchronizationObject::RemoveWaitingThread(std::shared_ptr<Thread> thread) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SynchronizationObject::ClearWaitingThreads() {
|
|
||||||
waiting_threads.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<std::shared_ptr<Thread>>& SynchronizationObject::GetWaitingThreads() const {
|
|
||||||
return waiting_threads;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Kernel
|
|
|
@ -1,77 +0,0 @@
|
||||||
// Copyright 2014 Citra Emulator Project
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
#include <memory>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "core/hle/kernel/object.h"
|
|
||||||
|
|
||||||
namespace Kernel {
|
|
||||||
|
|
||||||
class KernelCore;
|
|
||||||
class Synchronization;
|
|
||||||
class Thread;
|
|
||||||
|
|
||||||
/// Class that represents a Kernel object that a thread can be waiting on
|
|
||||||
class SynchronizationObject : public Object {
|
|
||||||
public:
|
|
||||||
explicit SynchronizationObject(KernelCore& kernel);
|
|
||||||
~SynchronizationObject() override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the specified thread should wait until the object is available
|
|
||||||
* @param thread The thread about which we're deciding.
|
|
||||||
* @return True if the current thread should wait due to this object being unavailable
|
|
||||||
*/
|
|
||||||
virtual bool ShouldWait(const Thread* thread) const = 0;
|
|
||||||
|
|
||||||
/// Acquire/lock the object for the specified thread if it is available
|
|
||||||
virtual void Acquire(Thread* thread) = 0;
|
|
||||||
|
|
||||||
/// Signal this object
|
|
||||||
virtual void Signal();
|
|
||||||
|
|
||||||
virtual bool IsSignaled() const {
|
|
||||||
return is_signaled;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a thread to wait on this object
|
|
||||||
* @param thread Pointer to thread to add
|
|
||||||
*/
|
|
||||||
void AddWaitingThread(std::shared_ptr<Thread> thread);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes a thread from waiting on this object (e.g. if it was resumed already)
|
|
||||||
* @param thread Pointer to thread to remove
|
|
||||||
*/
|
|
||||||
void RemoveWaitingThread(std::shared_ptr<Thread> thread);
|
|
||||||
|
|
||||||
/// Get a const reference to the waiting threads list for debug use
|
|
||||||
const std::vector<std::shared_ptr<Thread>>& GetWaitingThreads() const;
|
|
||||||
|
|
||||||
void ClearWaitingThreads();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
std::atomic_bool is_signaled{}; // Tells if this sync object is signaled
|
|
||||||
|
|
||||||
private:
|
|
||||||
/// Threads waiting for this object to become available
|
|
||||||
std::vector<std::shared_ptr<Thread>> waiting_threads;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Specialization of DynamicObjectCast for SynchronizationObjects
|
|
||||||
template <>
|
|
||||||
inline std::shared_ptr<SynchronizationObject> DynamicObjectCast<SynchronizationObject>(
|
|
||||||
std::shared_ptr<Object> object) {
|
|
||||||
if (object != nullptr && object->IsWaitable()) {
|
|
||||||
return std::static_pointer_cast<SynchronizationObject>(object);
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Kernel
|
|
|
@ -34,26 +34,19 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
bool Thread::ShouldWait(const Thread* thread) const {
|
|
||||||
return status != ThreadStatus::Dead;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Thread::IsSignaled() const {
|
bool Thread::IsSignaled() const {
|
||||||
return status == ThreadStatus::Dead;
|
return signaled;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::Acquire(Thread* thread) {
|
Thread::Thread(KernelCore& kernel) : KSynchronizationObject{kernel} {}
|
||||||
ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
|
|
||||||
}
|
|
||||||
|
|
||||||
Thread::Thread(KernelCore& kernel) : SynchronizationObject{kernel} {}
|
|
||||||
Thread::~Thread() = default;
|
Thread::~Thread() = default;
|
||||||
|
|
||||||
void Thread::Stop() {
|
void Thread::Stop() {
|
||||||
{
|
{
|
||||||
KScopedSchedulerLock lock(kernel);
|
KScopedSchedulerLock lock(kernel);
|
||||||
SetStatus(ThreadStatus::Dead);
|
SetState(ThreadStatus::Dead);
|
||||||
Signal();
|
signaled = true;
|
||||||
|
NotifyAvailable();
|
||||||
kernel.GlobalHandleTable().Close(global_handle);
|
kernel.GlobalHandleTable().Close(global_handle);
|
||||||
|
|
||||||
if (owner_process) {
|
if (owner_process) {
|
||||||
|
@ -67,7 +60,7 @@ void Thread::Stop() {
|
||||||
global_handle = 0;
|
global_handle = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::ResumeFromWait() {
|
void Thread::Wakeup() {
|
||||||
KScopedSchedulerLock lock(kernel);
|
KScopedSchedulerLock lock(kernel);
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case ThreadStatus::Paused:
|
case ThreadStatus::Paused:
|
||||||
|
@ -82,9 +75,6 @@ void Thread::ResumeFromWait() {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ThreadStatus::Ready:
|
case ThreadStatus::Ready:
|
||||||
// The thread's wakeup callback must have already been cleared when the thread was first
|
|
||||||
// awoken.
|
|
||||||
ASSERT(hle_callback == nullptr);
|
|
||||||
// If the thread is waiting on multiple wait objects, it might be awoken more than once
|
// If the thread is waiting on multiple wait objects, it might be awoken more than once
|
||||||
// before actually resuming. We can ignore subsequent wakeups if the thread status has
|
// before actually resuming. We can ignore subsequent wakeups if the thread status has
|
||||||
// already been set to ThreadStatus::Ready.
|
// already been set to ThreadStatus::Ready.
|
||||||
|
@ -96,30 +86,30 @@ void Thread::ResumeFromWait() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetStatus(ThreadStatus::Ready);
|
SetState(ThreadStatus::Ready);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::OnWakeUp() {
|
void Thread::OnWakeUp() {
|
||||||
KScopedSchedulerLock lock(kernel);
|
KScopedSchedulerLock lock(kernel);
|
||||||
SetStatus(ThreadStatus::Ready);
|
SetState(ThreadStatus::Ready);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode Thread::Start() {
|
ResultCode Thread::Start() {
|
||||||
KScopedSchedulerLock lock(kernel);
|
KScopedSchedulerLock lock(kernel);
|
||||||
SetStatus(ThreadStatus::Ready);
|
SetState(ThreadStatus::Ready);
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::CancelWait() {
|
void Thread::CancelWait() {
|
||||||
KScopedSchedulerLock lock(kernel);
|
KScopedSchedulerLock lock(kernel);
|
||||||
if (GetSchedulingStatus() != ThreadSchedStatus::Paused || !is_waiting_on_sync) {
|
if (GetState() != ThreadSchedStatus::Paused || !is_cancellable) {
|
||||||
is_sync_cancelled = true;
|
is_sync_cancelled = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// TODO(Blinkhawk): Implement cancel of server session
|
// TODO(Blinkhawk): Implement cancel of server session
|
||||||
is_sync_cancelled = false;
|
is_sync_cancelled = false;
|
||||||
SetSynchronizationResults(nullptr, ERR_SYNCHRONIZATION_CANCELED);
|
SetSynchronizationResults(nullptr, ERR_SYNCHRONIZATION_CANCELED);
|
||||||
SetStatus(ThreadStatus::Ready);
|
SetState(ThreadStatus::Ready);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ResetThreadContext32(Core::ARM_Interface::ThreadContext32& context, u32 stack_top,
|
static void ResetThreadContext32(Core::ARM_Interface::ThreadContext32& context, u32 stack_top,
|
||||||
|
@ -194,7 +184,6 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadTy
|
||||||
thread->processor_id = processor_id;
|
thread->processor_id = processor_id;
|
||||||
thread->ideal_core = processor_id;
|
thread->ideal_core = processor_id;
|
||||||
thread->affinity_mask.SetAffinity(processor_id, true);
|
thread->affinity_mask.SetAffinity(processor_id, true);
|
||||||
thread->wait_objects = nullptr;
|
|
||||||
thread->mutex_wait_address = 0;
|
thread->mutex_wait_address = 0;
|
||||||
thread->condvar_wait_address = 0;
|
thread->condvar_wait_address = 0;
|
||||||
thread->wait_handle = 0;
|
thread->wait_handle = 0;
|
||||||
|
@ -202,6 +191,7 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadTy
|
||||||
thread->global_handle = kernel.GlobalHandleTable().Create(thread).Unwrap();
|
thread->global_handle = kernel.GlobalHandleTable().Create(thread).Unwrap();
|
||||||
thread->owner_process = owner_process;
|
thread->owner_process = owner_process;
|
||||||
thread->type = type_flags;
|
thread->type = type_flags;
|
||||||
|
thread->signaled = false;
|
||||||
if ((type_flags & THREADTYPE_IDLE) == 0) {
|
if ((type_flags & THREADTYPE_IDLE) == 0) {
|
||||||
auto& scheduler = kernel.GlobalSchedulerContext();
|
auto& scheduler = kernel.GlobalSchedulerContext();
|
||||||
scheduler.AddThread(thread);
|
scheduler.AddThread(thread);
|
||||||
|
@ -234,24 +224,18 @@ void Thread::SetPriority(u32 priority) {
|
||||||
UpdatePriority();
|
UpdatePriority();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::SetSynchronizationResults(SynchronizationObject* object, ResultCode result) {
|
void Thread::SetSynchronizationResults(KSynchronizationObject* object, ResultCode result) {
|
||||||
signaling_object = object;
|
signaling_object = object;
|
||||||
signaling_result = result;
|
signaling_result = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 Thread::GetSynchronizationObjectIndex(std::shared_ptr<SynchronizationObject> object) const {
|
|
||||||
ASSERT_MSG(!wait_objects->empty(), "Thread is not waiting for anything");
|
|
||||||
const auto match = std::find(wait_objects->rbegin(), wait_objects->rend(), object);
|
|
||||||
return static_cast<s32>(std::distance(match, wait_objects->rend()) - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
VAddr Thread::GetCommandBufferAddress() const {
|
VAddr Thread::GetCommandBufferAddress() const {
|
||||||
// Offset from the start of TLS at which the IPC command buffer begins.
|
// Offset from the start of TLS at which the IPC command buffer begins.
|
||||||
constexpr u64 command_header_offset = 0x80;
|
constexpr u64 command_header_offset = 0x80;
|
||||||
return GetTLSAddress() + command_header_offset;
|
return GetTLSAddress() + command_header_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::SetStatus(ThreadStatus new_status) {
|
void Thread::SetState(ThreadStatus new_status) {
|
||||||
if (new_status == status) {
|
if (new_status == status) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -351,28 +335,16 @@ void Thread::UpdatePriority() {
|
||||||
lock_owner->UpdatePriority();
|
lock_owner->UpdatePriority();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Thread::AllSynchronizationObjectsReady() const {
|
|
||||||
return std::none_of(wait_objects->begin(), wait_objects->end(),
|
|
||||||
[this](const std::shared_ptr<SynchronizationObject>& object) {
|
|
||||||
return object->ShouldWait(this);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Thread::InvokeHLECallback(std::shared_ptr<Thread> thread) {
|
|
||||||
ASSERT(hle_callback);
|
|
||||||
return hle_callback(std::move(thread));
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultCode Thread::SetActivity(ThreadActivity value) {
|
ResultCode Thread::SetActivity(ThreadActivity value) {
|
||||||
KScopedSchedulerLock lock(kernel);
|
KScopedSchedulerLock lock(kernel);
|
||||||
|
|
||||||
auto sched_status = GetSchedulingStatus();
|
auto sched_status = GetState();
|
||||||
|
|
||||||
if (sched_status != ThreadSchedStatus::Runnable && sched_status != ThreadSchedStatus::Paused) {
|
if (sched_status != ThreadSchedStatus::Runnable && sched_status != ThreadSchedStatus::Paused) {
|
||||||
return ERR_INVALID_STATE;
|
return ERR_INVALID_STATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsPendingTermination()) {
|
if (IsTerminationRequested()) {
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,7 +366,7 @@ ResultCode Thread::Sleep(s64 nanoseconds) {
|
||||||
Handle event_handle{};
|
Handle event_handle{};
|
||||||
{
|
{
|
||||||
KScopedSchedulerLockAndSleep lock(kernel, event_handle, this, nanoseconds);
|
KScopedSchedulerLockAndSleep lock(kernel, event_handle, this, nanoseconds);
|
||||||
SetStatus(ThreadStatus::WaitSleep);
|
SetState(ThreadStatus::WaitSleep);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event_handle != InvalidHandle) {
|
if (event_handle != InvalidHandle) {
|
||||||
|
@ -407,7 +379,7 @@ ResultCode Thread::Sleep(s64 nanoseconds) {
|
||||||
void Thread::AddSchedulingFlag(ThreadSchedFlags flag) {
|
void Thread::AddSchedulingFlag(ThreadSchedFlags flag) {
|
||||||
const u32 old_state = scheduling_state;
|
const u32 old_state = scheduling_state;
|
||||||
pausing_state |= static_cast<u32>(flag);
|
pausing_state |= static_cast<u32>(flag);
|
||||||
const u32 base_scheduling = static_cast<u32>(GetSchedulingStatus());
|
const u32 base_scheduling = static_cast<u32>(GetState());
|
||||||
scheduling_state = base_scheduling | pausing_state;
|
scheduling_state = base_scheduling | pausing_state;
|
||||||
KScheduler::OnThreadStateChanged(kernel, this, old_state);
|
KScheduler::OnThreadStateChanged(kernel, this, old_state);
|
||||||
}
|
}
|
||||||
|
@ -415,7 +387,7 @@ void Thread::AddSchedulingFlag(ThreadSchedFlags flag) {
|
||||||
void Thread::RemoveSchedulingFlag(ThreadSchedFlags flag) {
|
void Thread::RemoveSchedulingFlag(ThreadSchedFlags flag) {
|
||||||
const u32 old_state = scheduling_state;
|
const u32 old_state = scheduling_state;
|
||||||
pausing_state &= ~static_cast<u32>(flag);
|
pausing_state &= ~static_cast<u32>(flag);
|
||||||
const u32 base_scheduling = static_cast<u32>(GetSchedulingStatus());
|
const u32 base_scheduling = static_cast<u32>(GetState());
|
||||||
scheduling_state = base_scheduling | pausing_state;
|
scheduling_state = base_scheduling | pausing_state;
|
||||||
KScheduler::OnThreadStateChanged(kernel, this, old_state);
|
KScheduler::OnThreadStateChanged(kernel, this, old_state);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,8 @@
|
||||||
#include "common/spin_lock.h"
|
#include "common/spin_lock.h"
|
||||||
#include "core/arm/arm_interface.h"
|
#include "core/arm/arm_interface.h"
|
||||||
#include "core/hle/kernel/k_affinity_mask.h"
|
#include "core/hle/kernel/k_affinity_mask.h"
|
||||||
|
#include "core/hle/kernel/k_synchronization_object.h"
|
||||||
#include "core/hle/kernel/object.h"
|
#include "core/hle/kernel/object.h"
|
||||||
#include "core/hle/kernel/synchronization_object.h"
|
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
@ -117,7 +117,7 @@ enum class ThreadSchedMasks : u32 {
|
||||||
ForcePauseMask = 0x0070,
|
ForcePauseMask = 0x0070,
|
||||||
};
|
};
|
||||||
|
|
||||||
class Thread final : public SynchronizationObject {
|
class Thread final : public KSynchronizationObject {
|
||||||
public:
|
public:
|
||||||
explicit Thread(KernelCore& kernel);
|
explicit Thread(KernelCore& kernel);
|
||||||
~Thread() override;
|
~Thread() override;
|
||||||
|
@ -127,10 +127,6 @@ public:
|
||||||
using ThreadContext32 = Core::ARM_Interface::ThreadContext32;
|
using ThreadContext32 = Core::ARM_Interface::ThreadContext32;
|
||||||
using ThreadContext64 = Core::ARM_Interface::ThreadContext64;
|
using ThreadContext64 = Core::ARM_Interface::ThreadContext64;
|
||||||
|
|
||||||
using ThreadSynchronizationObjects = std::vector<std::shared_ptr<SynchronizationObject>>;
|
|
||||||
|
|
||||||
using HLECallback = std::function<bool(std::shared_ptr<Thread> thread)>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates and returns a new thread. The new thread is immediately scheduled
|
* Creates and returns a new thread. The new thread is immediately scheduled
|
||||||
* @param system The instance of the whole system
|
* @param system The instance of the whole system
|
||||||
|
@ -186,10 +182,6 @@ public:
|
||||||
return HANDLE_TYPE;
|
return HANDLE_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShouldWait(const Thread* thread) const override;
|
|
||||||
void Acquire(Thread* thread) override;
|
|
||||||
bool IsSignaled() const override;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the thread's current priority
|
* Gets the thread's current priority
|
||||||
* @return The current thread's priority
|
* @return The current thread's priority
|
||||||
|
@ -233,12 +225,14 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resumes a thread from waiting
|
/// Resumes a thread from waiting
|
||||||
void ResumeFromWait();
|
void Wakeup();
|
||||||
|
|
||||||
void OnWakeUp();
|
void OnWakeUp();
|
||||||
|
|
||||||
ResultCode Start();
|
ResultCode Start();
|
||||||
|
|
||||||
|
virtual bool IsSignaled() const override;
|
||||||
|
|
||||||
/// Cancels a waiting operation that this thread may or may not be within.
|
/// Cancels a waiting operation that this thread may or may not be within.
|
||||||
///
|
///
|
||||||
/// When the thread is within a waiting state, this will set the thread's
|
/// When the thread is within a waiting state, this will set the thread's
|
||||||
|
@ -247,30 +241,21 @@ public:
|
||||||
///
|
///
|
||||||
void CancelWait();
|
void CancelWait();
|
||||||
|
|
||||||
void SetSynchronizationResults(SynchronizationObject* object, ResultCode result);
|
void SetSynchronizationResults(KSynchronizationObject* object, ResultCode result);
|
||||||
|
|
||||||
SynchronizationObject* GetSignalingObject() const {
|
void SetSyncedObject(KSynchronizationObject* object, ResultCode result) {
|
||||||
return signaling_object;
|
SetSynchronizationResults(object, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode GetWaitResult(KSynchronizationObject** out) const {
|
||||||
|
*out = this->signaling_object;
|
||||||
|
return signaling_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode GetSignalingResult() const {
|
ResultCode GetSignalingResult() const {
|
||||||
return signaling_result;
|
return signaling_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the index that this particular object occupies in the list of objects
|
|
||||||
* that the thread passed to WaitSynchronization, starting the search from the last element.
|
|
||||||
*
|
|
||||||
* It is used to set the output index of WaitSynchronization when the thread is awakened.
|
|
||||||
*
|
|
||||||
* When a thread wakes up due to an object signal, the kernel will use the index of the last
|
|
||||||
* matching object in the wait objects list in case of having multiple instances of the same
|
|
||||||
* object in the list.
|
|
||||||
*
|
|
||||||
* @param object Object to query the index of.
|
|
||||||
*/
|
|
||||||
s32 GetSynchronizationObjectIndex(std::shared_ptr<SynchronizationObject> object) const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops a thread, invalidating it from further use
|
* Stops a thread, invalidating it from further use
|
||||||
*/
|
*/
|
||||||
|
@ -345,7 +330,7 @@ public:
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetStatus(ThreadStatus new_status);
|
void SetState(ThreadStatus new_status);
|
||||||
|
|
||||||
s64 GetLastScheduledTick() const {
|
s64 GetLastScheduledTick() const {
|
||||||
return this->last_scheduled_tick;
|
return this->last_scheduled_tick;
|
||||||
|
@ -387,24 +372,6 @@ public:
|
||||||
return owner_process;
|
return owner_process;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ThreadSynchronizationObjects& GetSynchronizationObjects() const {
|
|
||||||
return *wait_objects;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetSynchronizationObjects(ThreadSynchronizationObjects* objects) {
|
|
||||||
wait_objects = objects;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearSynchronizationObjects() {
|
|
||||||
for (const auto& waiting_object : *wait_objects) {
|
|
||||||
waiting_object->RemoveWaitingThread(SharedFrom(this));
|
|
||||||
}
|
|
||||||
wait_objects->clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Determines whether all the objects this thread is waiting on are ready.
|
|
||||||
bool AllSynchronizationObjectsReady() const;
|
|
||||||
|
|
||||||
const MutexWaitingThreads& GetMutexWaitingThreads() const {
|
const MutexWaitingThreads& GetMutexWaitingThreads() const {
|
||||||
return wait_mutex_threads;
|
return wait_mutex_threads;
|
||||||
}
|
}
|
||||||
|
@ -449,34 +416,14 @@ public:
|
||||||
arb_wait_address = address;
|
arb_wait_address = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasHLECallback() const {
|
|
||||||
return hle_callback != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetHLECallback(HLECallback callback) {
|
|
||||||
hle_callback = std::move(callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetHLETimeEvent(Handle time_event) {
|
void SetHLETimeEvent(Handle time_event) {
|
||||||
hle_time_event = time_event;
|
hle_time_event = time_event;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetHLESyncObject(SynchronizationObject* object) {
|
|
||||||
hle_object = object;
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle GetHLETimeEvent() const {
|
Handle GetHLETimeEvent() const {
|
||||||
return hle_time_event;
|
return hle_time_event;
|
||||||
}
|
}
|
||||||
|
|
||||||
SynchronizationObject* GetHLESyncObject() const {
|
|
||||||
return hle_object;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InvalidateHLECallback() {
|
|
||||||
SetHLECallback(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool InvokeHLECallback(std::shared_ptr<Thread> thread);
|
bool InvokeHLECallback(std::shared_ptr<Thread> thread);
|
||||||
|
|
||||||
u32 GetIdealCore() const {
|
u32 GetIdealCore() const {
|
||||||
|
@ -500,7 +447,7 @@ public:
|
||||||
this->schedule_count = count;
|
this->schedule_count = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadSchedStatus GetSchedulingStatus() const {
|
ThreadSchedStatus GetState() const {
|
||||||
return static_cast<ThreadSchedStatus>(scheduling_state &
|
return static_cast<ThreadSchedStatus>(scheduling_state &
|
||||||
static_cast<u32>(ThreadSchedMasks::LowMask));
|
static_cast<u32>(ThreadSchedMasks::LowMask));
|
||||||
}
|
}
|
||||||
|
@ -517,12 +464,12 @@ public:
|
||||||
is_running = value;
|
is_running = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsSyncCancelled() const {
|
bool IsWaitCancelled() const {
|
||||||
return is_sync_cancelled;
|
return is_sync_cancelled;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetSyncCancelled(bool value) {
|
void ClearWaitCancelled() {
|
||||||
is_sync_cancelled = value;
|
is_sync_cancelled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle GetGlobalHandle() const {
|
Handle GetGlobalHandle() const {
|
||||||
|
@ -537,16 +484,20 @@ public:
|
||||||
waiting_for_arbitration = set;
|
waiting_for_arbitration = set;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsWaitingSync() const {
|
bool IsCancellable() const {
|
||||||
return is_waiting_on_sync;
|
return is_cancellable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetWaitingSync(bool is_waiting) {
|
void SetCancellable() {
|
||||||
is_waiting_on_sync = is_waiting;
|
is_cancellable = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsPendingTermination() const {
|
void ClearCancellable() {
|
||||||
return will_be_terminated || GetSchedulingStatus() == ThreadSchedStatus::Exited;
|
is_cancellable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsTerminationRequested() const {
|
||||||
|
return will_be_terminated || GetState() == ThreadSchedStatus::Exited;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsPaused() const {
|
bool IsPaused() const {
|
||||||
|
@ -622,6 +573,18 @@ public:
|
||||||
disable_count--;
|
disable_count--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetWaitObjectsForDebugging(KSynchronizationObject** objects, s32 num_objects) {
|
||||||
|
wait_objects_for_debugging.clear();
|
||||||
|
wait_objects_for_debugging.reserve(num_objects);
|
||||||
|
for (auto i = 0; i < num_objects; ++i) {
|
||||||
|
wait_objects_for_debugging.emplace_back(objects[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<KSynchronizationObject*>& GetWaitObjectsForDebugging() const {
|
||||||
|
return wait_objects_for_debugging;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class GlobalSchedulerContext;
|
friend class GlobalSchedulerContext;
|
||||||
friend class KScheduler;
|
friend class KScheduler;
|
||||||
|
@ -630,7 +593,6 @@ private:
|
||||||
void SetSchedulingStatus(ThreadSchedStatus new_status);
|
void SetSchedulingStatus(ThreadSchedStatus new_status);
|
||||||
void AddSchedulingFlag(ThreadSchedFlags flag);
|
void AddSchedulingFlag(ThreadSchedFlags flag);
|
||||||
void RemoveSchedulingFlag(ThreadSchedFlags flag);
|
void RemoveSchedulingFlag(ThreadSchedFlags flag);
|
||||||
|
|
||||||
void SetCurrentPriority(u32 new_priority);
|
void SetCurrentPriority(u32 new_priority);
|
||||||
|
|
||||||
Common::SpinLock context_guard{};
|
Common::SpinLock context_guard{};
|
||||||
|
@ -671,10 +633,10 @@ private:
|
||||||
Process* owner_process;
|
Process* owner_process;
|
||||||
|
|
||||||
/// Objects that the thread is waiting on, in the same order as they were
|
/// Objects that the thread is waiting on, in the same order as they were
|
||||||
/// passed to WaitSynchronization.
|
/// passed to WaitSynchronization. This is used for debugging only.
|
||||||
ThreadSynchronizationObjects* wait_objects;
|
std::vector<KSynchronizationObject*> wait_objects_for_debugging;
|
||||||
|
|
||||||
SynchronizationObject* signaling_object;
|
KSynchronizationObject* signaling_object;
|
||||||
ResultCode signaling_result{RESULT_SUCCESS};
|
ResultCode signaling_result{RESULT_SUCCESS};
|
||||||
|
|
||||||
/// List of threads that are waiting for a mutex that is held by this thread.
|
/// List of threads that are waiting for a mutex that is held by this thread.
|
||||||
|
@ -697,10 +659,7 @@ private:
|
||||||
/// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
|
/// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
|
||||||
Handle global_handle = 0;
|
Handle global_handle = 0;
|
||||||
|
|
||||||
/// Callback for HLE Events
|
|
||||||
HLECallback hle_callback;
|
|
||||||
Handle hle_time_event;
|
Handle hle_time_event;
|
||||||
SynchronizationObject* hle_object;
|
|
||||||
|
|
||||||
KScheduler* scheduler = nullptr;
|
KScheduler* scheduler = nullptr;
|
||||||
|
|
||||||
|
@ -714,7 +673,7 @@ private:
|
||||||
|
|
||||||
u32 pausing_state = 0;
|
u32 pausing_state = 0;
|
||||||
bool is_running = false;
|
bool is_running = false;
|
||||||
bool is_waiting_on_sync = false;
|
bool is_cancellable = false;
|
||||||
bool is_sync_cancelled = false;
|
bool is_sync_cancelled = false;
|
||||||
|
|
||||||
bool is_continuous_on_svc = false;
|
bool is_continuous_on_svc = false;
|
||||||
|
@ -725,6 +684,8 @@ private:
|
||||||
|
|
||||||
bool was_running = false;
|
bool was_running = false;
|
||||||
|
|
||||||
|
bool signaled{};
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -139,9 +139,6 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {
|
||||||
server_port->AppendPendingSession(server);
|
server_port->AppendPendingSession(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wake the threads waiting on the ServerPort
|
|
||||||
server_port->Signal();
|
|
||||||
|
|
||||||
LOG_DEBUG(Service_SM, "called service={} -> session={}", name, client->GetObjectId());
|
LOG_DEBUG(Service_SM, "called service={} -> session={}", name, client->GetObjectId());
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
|
|
@ -14,10 +14,10 @@
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
#include "core/hle/kernel/handle_table.h"
|
||||||
#include "core/hle/kernel/k_scheduler.h"
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
|
#include "core/hle/kernel/k_synchronization_object.h"
|
||||||
#include "core/hle/kernel/mutex.h"
|
#include "core/hle/kernel/mutex.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/readable_event.h"
|
#include "core/hle/kernel/readable_event.h"
|
||||||
#include "core/hle/kernel/synchronization_object.h"
|
|
||||||
#include "core/hle/kernel/thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
|
||||||
|
@ -169,7 +169,8 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() cons
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
WaitTreeSynchronizationObject::WaitTreeSynchronizationObject(const Kernel::SynchronizationObject& o)
|
WaitTreeSynchronizationObject::WaitTreeSynchronizationObject(
|
||||||
|
const Kernel::KSynchronizationObject& o)
|
||||||
: object(o) {}
|
: object(o) {}
|
||||||
WaitTreeSynchronizationObject::~WaitTreeSynchronizationObject() = default;
|
WaitTreeSynchronizationObject::~WaitTreeSynchronizationObject() = default;
|
||||||
|
|
||||||
|
@ -188,7 +189,7 @@ QString WaitTreeSynchronizationObject::GetText() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<WaitTreeSynchronizationObject> WaitTreeSynchronizationObject::make(
|
std::unique_ptr<WaitTreeSynchronizationObject> WaitTreeSynchronizationObject::make(
|
||||||
const Kernel::SynchronizationObject& object) {
|
const Kernel::KSynchronizationObject& object) {
|
||||||
switch (object.GetHandleType()) {
|
switch (object.GetHandleType()) {
|
||||||
case Kernel::HandleType::ReadableEvent:
|
case Kernel::HandleType::ReadableEvent:
|
||||||
return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::ReadableEvent&>(object));
|
return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::ReadableEvent&>(object));
|
||||||
|
@ -202,7 +203,7 @@ std::unique_ptr<WaitTreeSynchronizationObject> WaitTreeSynchronizationObject::ma
|
||||||
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeSynchronizationObject::GetChildren() const {
|
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeSynchronizationObject::GetChildren() const {
|
||||||
std::vector<std::unique_ptr<WaitTreeItem>> list;
|
std::vector<std::unique_ptr<WaitTreeItem>> list;
|
||||||
|
|
||||||
const auto& threads = object.GetWaitingThreads();
|
const auto& threads = object.GetWaitingThreadsForDebugging();
|
||||||
if (threads.empty()) {
|
if (threads.empty()) {
|
||||||
list.push_back(std::make_unique<WaitTreeText>(tr("waited by no thread")));
|
list.push_back(std::make_unique<WaitTreeText>(tr("waited by no thread")));
|
||||||
} else {
|
} else {
|
||||||
|
@ -211,8 +212,8 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeSynchronizationObject::GetChi
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
WaitTreeObjectList::WaitTreeObjectList(
|
WaitTreeObjectList::WaitTreeObjectList(const std::vector<Kernel::KSynchronizationObject*>& list,
|
||||||
const std::vector<std::shared_ptr<Kernel::SynchronizationObject>>& list, bool w_all)
|
bool w_all)
|
||||||
: object_list(list), wait_all(w_all) {}
|
: object_list(list), wait_all(w_all) {}
|
||||||
|
|
||||||
WaitTreeObjectList::~WaitTreeObjectList() = default;
|
WaitTreeObjectList::~WaitTreeObjectList() = default;
|
||||||
|
@ -367,8 +368,8 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (thread.GetStatus() == Kernel::ThreadStatus::WaitSynch) {
|
if (thread.GetStatus() == Kernel::ThreadStatus::WaitSynch) {
|
||||||
list.push_back(std::make_unique<WaitTreeObjectList>(thread.GetSynchronizationObjects(),
|
list.push_back(std::make_unique<WaitTreeObjectList>(thread.GetWaitObjectsForDebugging(),
|
||||||
thread.IsWaitingSync()));
|
thread.IsCancellable()));
|
||||||
}
|
}
|
||||||
|
|
||||||
list.push_back(std::make_unique<WaitTreeCallstack>(thread));
|
list.push_back(std::make_unique<WaitTreeCallstack>(thread));
|
||||||
|
@ -380,7 +381,7 @@ WaitTreeEvent::WaitTreeEvent(const Kernel::ReadableEvent& object)
|
||||||
: WaitTreeSynchronizationObject(object) {}
|
: WaitTreeSynchronizationObject(object) {}
|
||||||
WaitTreeEvent::~WaitTreeEvent() = default;
|
WaitTreeEvent::~WaitTreeEvent() = default;
|
||||||
|
|
||||||
WaitTreeThreadList::WaitTreeThreadList(const std::vector<std::shared_ptr<Kernel::Thread>>& list)
|
WaitTreeThreadList::WaitTreeThreadList(const std::vector<Kernel::Thread*>& list)
|
||||||
: thread_list(list) {}
|
: thread_list(list) {}
|
||||||
WaitTreeThreadList::~WaitTreeThreadList() = default;
|
WaitTreeThreadList::~WaitTreeThreadList() = default;
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,8 @@ class EmuThread;
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
class HandleTable;
|
class HandleTable;
|
||||||
|
class KSynchronizationObject;
|
||||||
class ReadableEvent;
|
class ReadableEvent;
|
||||||
class SynchronizationObject;
|
|
||||||
class Thread;
|
class Thread;
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
||||||
|
@ -102,30 +102,29 @@ private:
|
||||||
class WaitTreeSynchronizationObject : public WaitTreeExpandableItem {
|
class WaitTreeSynchronizationObject : public WaitTreeExpandableItem {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit WaitTreeSynchronizationObject(const Kernel::SynchronizationObject& object);
|
explicit WaitTreeSynchronizationObject(const Kernel::KSynchronizationObject& object);
|
||||||
~WaitTreeSynchronizationObject() override;
|
~WaitTreeSynchronizationObject() override;
|
||||||
|
|
||||||
static std::unique_ptr<WaitTreeSynchronizationObject> make(
|
static std::unique_ptr<WaitTreeSynchronizationObject> make(
|
||||||
const Kernel::SynchronizationObject& object);
|
const Kernel::KSynchronizationObject& object);
|
||||||
QString GetText() const override;
|
QString GetText() const override;
|
||||||
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
|
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const Kernel::SynchronizationObject& object;
|
const Kernel::KSynchronizationObject& object;
|
||||||
};
|
};
|
||||||
|
|
||||||
class WaitTreeObjectList : public WaitTreeExpandableItem {
|
class WaitTreeObjectList : public WaitTreeExpandableItem {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
WaitTreeObjectList(const std::vector<std::shared_ptr<Kernel::SynchronizationObject>>& list,
|
WaitTreeObjectList(const std::vector<Kernel::KSynchronizationObject*>& list, bool wait_all);
|
||||||
bool wait_all);
|
|
||||||
~WaitTreeObjectList() override;
|
~WaitTreeObjectList() override;
|
||||||
|
|
||||||
QString GetText() const override;
|
QString GetText() const override;
|
||||||
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
|
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::vector<std::shared_ptr<Kernel::SynchronizationObject>>& object_list;
|
const std::vector<Kernel::KSynchronizationObject*>& object_list;
|
||||||
bool wait_all;
|
bool wait_all;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -150,14 +149,14 @@ public:
|
||||||
class WaitTreeThreadList : public WaitTreeExpandableItem {
|
class WaitTreeThreadList : public WaitTreeExpandableItem {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit WaitTreeThreadList(const std::vector<std::shared_ptr<Kernel::Thread>>& list);
|
explicit WaitTreeThreadList(const std::vector<Kernel::Thread*>& list);
|
||||||
~WaitTreeThreadList() override;
|
~WaitTreeThreadList() override;
|
||||||
|
|
||||||
QString GetText() const override;
|
QString GetText() const override;
|
||||||
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
|
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::vector<std::shared_ptr<Kernel::Thread>>& thread_list;
|
const std::vector<Kernel::Thread*>& thread_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
class WaitTreeModel : public QAbstractItemModel {
|
class WaitTreeModel : public QAbstractItemModel {
|
||||||
|
|
Loading…
Reference in a new issue