core: hle: kernel: Update KSynchronizationObject.

master
bunnei 2020-12-21 22:36:53 +07:00
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);
} }
} }

@ -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

@ -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,25 +343,14 @@ 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, &param_1, Param(system, 1), static_cast<u32>(Param(system, 2)), const u32 retval = func(system, &param_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), &param_1) Param32(system, 3), &param_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 {