diff options
Diffstat (limited to '')
39 files changed, 672 insertions, 489 deletions
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index de0a9064e..98d07fa5b 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -21,7 +21,7 @@ namespace Kernel { namespace { // Wake up num_to_wake (or all) threads in a vector. -void WakeThreads(const std::vector<SharedPtr<Thread>>& waiting_threads, s32 num_to_wake) { +void WakeThreads(const std::vector<std::shared_ptr<Thread>>& waiting_threads, s32 num_to_wake) { auto& system = Core::System::GetInstance(); // Only process up to 'target' threads, unless 'target' is <= 0, in which case process // them all. @@ -59,35 +59,41 @@ ResultCode AddressArbiter::SignalToAddress(VAddr address, SignalType type, s32 v } ResultCode AddressArbiter::SignalToAddressOnly(VAddr address, s32 num_to_wake) { - const std::vector<SharedPtr<Thread>> waiting_threads = GetThreadsWaitingOnAddress(address); + const std::vector<std::shared_ptr<Thread>> waiting_threads = + GetThreadsWaitingOnAddress(address); WakeThreads(waiting_threads, num_to_wake); return RESULT_SUCCESS; } ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake) { + auto& memory = system.Memory(); + // Ensure that we can write to the address. - if (!Memory::IsValidVirtualAddress(address)) { + if (!memory.IsValidVirtualAddress(address)) { return ERR_INVALID_ADDRESS_STATE; } - if (static_cast<s32>(Memory::Read32(address)) != value) { + if (static_cast<s32>(memory.Read32(address)) != value) { return ERR_INVALID_STATE; } - Memory::Write32(address, static_cast<u32>(value + 1)); + memory.Write32(address, static_cast<u32>(value + 1)); return SignalToAddressOnly(address, num_to_wake); } ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake) { + auto& memory = system.Memory(); + // Ensure that we can write to the address. - if (!Memory::IsValidVirtualAddress(address)) { + if (!memory.IsValidVirtualAddress(address)) { return ERR_INVALID_ADDRESS_STATE; } // Get threads waiting on the address. - const std::vector<SharedPtr<Thread>> waiting_threads = GetThreadsWaitingOnAddress(address); + const std::vector<std::shared_ptr<Thread>> waiting_threads = + GetThreadsWaitingOnAddress(address); // Determine the modified value depending on the waiting count. s32 updated_value; @@ -107,11 +113,11 @@ ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr a } } - if (static_cast<s32>(Memory::Read32(address)) != value) { + if (static_cast<s32>(memory.Read32(address)) != value) { return ERR_INVALID_STATE; } - Memory::Write32(address, static_cast<u32>(updated_value)); + memory.Write32(address, static_cast<u32>(updated_value)); WakeThreads(waiting_threads, num_to_wake); return RESULT_SUCCESS; } @@ -132,18 +138,20 @@ ResultCode AddressArbiter::WaitForAddress(VAddr address, ArbitrationType type, s ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool should_decrement) { + auto& memory = system.Memory(); + // Ensure that we can read the address. - if (!Memory::IsValidVirtualAddress(address)) { + if (!memory.IsValidVirtualAddress(address)) { return ERR_INVALID_ADDRESS_STATE; } - const s32 cur_value = static_cast<s32>(Memory::Read32(address)); + const s32 cur_value = static_cast<s32>(memory.Read32(address)); if (cur_value >= value) { return ERR_INVALID_STATE; } if (should_decrement) { - Memory::Write32(address, static_cast<u32>(cur_value - 1)); + memory.Write32(address, static_cast<u32>(cur_value - 1)); } // Short-circuit without rescheduling, if timeout is zero. @@ -155,15 +163,19 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6 } ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) { + auto& memory = system.Memory(); + // Ensure that we can read the address. - if (!Memory::IsValidVirtualAddress(address)) { + if (!memory.IsValidVirtualAddress(address)) { return ERR_INVALID_ADDRESS_STATE; } + // Only wait for the address if equal. - if (static_cast<s32>(Memory::Read32(address)) != value) { + if (static_cast<s32>(memory.Read32(address)) != value) { return ERR_INVALID_STATE; } - // Short-circuit without rescheduling, if timeout is zero. + + // Short-circuit without rescheduling if timeout is zero. if (timeout == 0) { return RESULT_TIMEOUT; } @@ -172,21 +184,21 @@ ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 t } ResultCode AddressArbiter::WaitForAddressImpl(VAddr address, s64 timeout) { - SharedPtr<Thread> current_thread = system.CurrentScheduler().GetCurrentThread(); + Thread* current_thread = system.CurrentScheduler().GetCurrentThread(); current_thread->SetArbiterWaitAddress(address); current_thread->SetStatus(ThreadStatus::WaitArb); current_thread->InvalidateWakeupCallback(); - current_thread->WakeAfterDelay(timeout); system.PrepareReschedule(current_thread->GetProcessorID()); return RESULT_TIMEOUT; } -std::vector<SharedPtr<Thread>> AddressArbiter::GetThreadsWaitingOnAddress(VAddr address) const { +std::vector<std::shared_ptr<Thread>> AddressArbiter::GetThreadsWaitingOnAddress( + VAddr address) const { // Retrieve all threads that are waiting for this address. - std::vector<SharedPtr<Thread>> threads; + std::vector<std::shared_ptr<Thread>> threads; const auto& scheduler = system.GlobalScheduler(); const auto& thread_list = scheduler.GetThreadList(); @@ -198,7 +210,7 @@ std::vector<SharedPtr<Thread>> AddressArbiter::GetThreadsWaitingOnAddress(VAddr // Sort them by priority, such that the highest priority ones come first. std::sort(threads.begin(), threads.end(), - [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) { + [](const std::shared_ptr<Thread>& lhs, const std::shared_ptr<Thread>& rhs) { return lhs->GetPriority() < rhs->GetPriority(); }); diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h index ed0d0e69f..608918de5 100644 --- a/src/core/hle/kernel/address_arbiter.h +++ b/src/core/hle/kernel/address_arbiter.h @@ -72,7 +72,7 @@ private: ResultCode WaitForAddressImpl(VAddr address, s64 timeout); // Gets the threads waiting on an address. - std::vector<SharedPtr<Thread>> GetThreadsWaitingOnAddress(VAddr address) const; + std::vector<std::shared_ptr<Thread>> GetThreadsWaitingOnAddress(VAddr address) const; Core::System& system; }; diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index 744b1697d..00bb939a0 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp @@ -9,38 +9,35 @@ #include "core/hle/kernel/object.h" #include "core/hle/kernel/server_port.h" #include "core/hle/kernel/server_session.h" +#include "core/hle/kernel/session.h" namespace Kernel { ClientPort::ClientPort(KernelCore& kernel) : Object{kernel} {} ClientPort::~ClientPort() = default; -SharedPtr<ServerPort> ClientPort::GetServerPort() const { +std::shared_ptr<ServerPort> ClientPort::GetServerPort() const { return server_port; } -ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() { - // Note: Threads do not wait for the server endpoint to call - // AcceptSession before returning from this call. - +ResultVal<std::shared_ptr<ClientSession>> ClientPort::Connect() { if (active_sessions >= max_sessions) { return ERR_MAX_CONNECTIONS_REACHED; } active_sessions++; - // Create a new session pair, let the created sessions inherit the parent port's HLE handler. - auto [server, client] = ServerSession::CreateSessionPair(kernel, server_port->GetName(), this); + auto [client, server] = Kernel::Session::Create(kernel, name); if (server_port->HasHLEHandler()) { - server_port->GetHLEHandler()->ClientConnected(server); + server_port->GetHLEHandler()->ClientConnected(std::move(server)); } else { - server_port->AppendPendingSession(server); + server_port->AppendPendingSession(std::move(server)); } // Wake the threads waiting on the ServerPort server_port->WakeupAllWaitingThreads(); - return MakeResult(client); + return MakeResult(std::move(client)); } void ClientPort::ConnectionClosed() { diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h index 4921ad4f0..715edd18c 100644 --- a/src/core/hle/kernel/client_port.h +++ b/src/core/hle/kernel/client_port.h @@ -17,6 +17,9 @@ class ServerPort; class ClientPort final : public Object { public: + explicit ClientPort(KernelCore& kernel); + ~ClientPort() override; + friend class ServerPort; std::string GetTypeName() const override { return "ClientPort"; @@ -30,7 +33,7 @@ public: return HANDLE_TYPE; } - SharedPtr<ServerPort> GetServerPort() const; + std::shared_ptr<ServerPort> GetServerPort() const; /** * Creates a new Session pair, adds the created ServerSession to the associated ServerPort's @@ -38,7 +41,7 @@ public: * waiting on it to awake. * @returns ClientSession The client endpoint of the created Session pair, or error code. */ - ResultVal<SharedPtr<ClientSession>> Connect(); + ResultVal<std::shared_ptr<ClientSession>> Connect(); /** * Signifies that a previously active connection has been closed, @@ -47,10 +50,7 @@ public: void ConnectionClosed(); private: - explicit ClientPort(KernelCore& kernel); - ~ClientPort() override; - - SharedPtr<ServerPort> server_port; ///< ServerPort associated with this client port. + std::shared_ptr<ServerPort> server_port; ///< ServerPort associated with this client port. u32 max_sessions = 0; ///< Maximum number of simultaneous sessions the port can have u32 active_sessions = 0; ///< Number of currently open sessions to this port std::string name; ///< Name of client port (optional) diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index c17baa50a..4669a14ad 100644 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp @@ -1,4 +1,4 @@ -// Copyright 2016 Citra Emulator Project +// Copyright 2019 yuzu emulator team // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -12,29 +12,44 @@ namespace Kernel { -ClientSession::ClientSession(KernelCore& kernel) : Object{kernel} {} +ClientSession::ClientSession(KernelCore& kernel) : WaitObject{kernel} {} + ClientSession::~ClientSession() { // This destructor will be called automatically when the last ClientSession handle is closed by // the emulated application. - - // A local reference to the ServerSession is necessary to guarantee it - // will be kept alive until after ClientDisconnected() returns. - SharedPtr<ServerSession> server = parent->server; - if (server) { - server->ClientDisconnected(); + if (parent->Server()) { + parent->Server()->ClientDisconnected(); } +} + +bool ClientSession::ShouldWait(const Thread* thread) const { + UNIMPLEMENTED(); + return {}; +} - parent->client = nullptr; +void ClientSession::Acquire(Thread* thread) { + UNIMPLEMENTED(); } -ResultCode ClientSession::SendSyncRequest(SharedPtr<Thread> thread) { +ResultVal<std::shared_ptr<ClientSession>> ClientSession::Create(KernelCore& kernel, + std::shared_ptr<Session> parent, + std::string name) { + std::shared_ptr<ClientSession> client_session{std::make_shared<ClientSession>(kernel)}; + + client_session->name = std::move(name); + client_session->parent = std::move(parent); + + return MakeResult(std::move(client_session)); +} + +ResultCode ClientSession::SendSyncRequest(std::shared_ptr<Thread> thread, Memory::Memory& memory) { // Keep ServerSession alive until we're done working with it. - SharedPtr<ServerSession> server = parent->server; - if (server == nullptr) + if (!parent->Server()) { return ERR_SESSION_CLOSED_BY_REMOTE; + } // Signal the server session that new data is available - return server->HandleSyncRequest(std::move(thread)); + return parent->Server()->HandleSyncRequest(std::move(thread), memory); } } // namespace Kernel diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h index 09cdff588..b4289a9a8 100644 --- a/src/core/hle/kernel/client_session.h +++ b/src/core/hle/kernel/client_session.h @@ -1,4 +1,4 @@ -// Copyright 2016 Citra Emulator Project +// Copyright 2019 yuzu emulator team // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -6,20 +6,28 @@ #include <memory> #include <string> -#include "core/hle/kernel/object.h" + +#include "core/hle/kernel/wait_object.h" +#include "core/hle/result.h" union ResultCode; +namespace Memory { +class Memory; +} + namespace Kernel { class KernelCore; class Session; -class ServerSession; class Thread; -class ClientSession final : public Object { +class ClientSession final : public WaitObject { public: - friend class ServerSession; + explicit ClientSession(KernelCore& kernel); + ~ClientSession() override; + + friend class Session; std::string GetTypeName() const override { return "ClientSession"; @@ -34,11 +42,16 @@ public: return HANDLE_TYPE; } - ResultCode SendSyncRequest(SharedPtr<Thread> thread); + ResultCode SendSyncRequest(std::shared_ptr<Thread> thread, Memory::Memory& memory); + + bool ShouldWait(const Thread* thread) const override; + + void Acquire(Thread* thread) override; private: - explicit ClientSession(KernelCore& kernel); - ~ClientSession() override; + static ResultVal<std::shared_ptr<ClientSession>> Create(KernelCore& kernel, + std::shared_ptr<Session> parent, + std::string name = "Unknown"); /// The parent session, which links to the server endpoint. std::shared_ptr<Session> parent; diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index 2cc5d536b..e441a27fc 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp @@ -44,7 +44,7 @@ ResultCode HandleTable::SetSize(s32 handle_table_size) { return RESULT_SUCCESS; } -ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) { +ResultVal<Handle> HandleTable::Create(std::shared_ptr<Object> obj) { DEBUG_ASSERT(obj != nullptr); const u16 slot = next_free_slot; @@ -70,7 +70,7 @@ ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) { } ResultVal<Handle> HandleTable::Duplicate(Handle handle) { - SharedPtr<Object> object = GetGeneric(handle); + std::shared_ptr<Object> object = GetGeneric(handle); if (object == nullptr) { LOG_ERROR(Kernel, "Tried to duplicate invalid handle: {:08X}", handle); return ERR_INVALID_HANDLE; @@ -99,11 +99,11 @@ bool HandleTable::IsValid(Handle handle) const { return slot < table_size && objects[slot] != nullptr && generations[slot] == generation; } -SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const { +std::shared_ptr<Object> HandleTable::GetGeneric(Handle handle) const { if (handle == CurrentThread) { - return GetCurrentThread(); + return SharedFrom(GetCurrentThread()); } else if (handle == CurrentProcess) { - return Core::System::GetInstance().CurrentProcess(); + return SharedFrom(Core::System::GetInstance().CurrentProcess()); } if (!IsValid(handle)) { diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h index 44901391b..9fcb4cc15 100644 --- a/src/core/hle/kernel/handle_table.h +++ b/src/core/hle/kernel/handle_table.h @@ -68,7 +68,7 @@ public: * @return The created Handle or one of the following errors: * - `ERR_HANDLE_TABLE_FULL`: the maximum number of handles has been exceeded. */ - ResultVal<Handle> Create(SharedPtr<Object> obj); + ResultVal<Handle> Create(std::shared_ptr<Object> obj); /** * Returns a new handle that points to the same object as the passed in handle. @@ -92,7 +92,7 @@ public: * Looks up a handle. * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid. */ - SharedPtr<Object> GetGeneric(Handle handle) const; + std::shared_ptr<Object> GetGeneric(Handle handle) const; /** * Looks up a handle while verifying its type. @@ -100,7 +100,7 @@ public: * type differs from the requested one. */ template <class T> - SharedPtr<T> Get(Handle handle) const { + std::shared_ptr<T> Get(Handle handle) const { return DynamicObjectCast<T>(GetGeneric(handle)); } @@ -109,7 +109,7 @@ public: private: /// Stores the Object referenced by the handle or null if the slot is empty. - std::array<SharedPtr<Object>, MAX_COUNT> objects; + std::array<std::shared_ptr<Object>, MAX_COUNT> objects; /** * The value of `next_generation` when the handle was created, used to check for validity. For diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index a7b5849b0..2db28dcf0 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -32,23 +32,25 @@ SessionRequestHandler::SessionRequestHandler() = default; SessionRequestHandler::~SessionRequestHandler() = default; -void SessionRequestHandler::ClientConnected(SharedPtr<ServerSession> server_session) { +void SessionRequestHandler::ClientConnected(std::shared_ptr<ServerSession> server_session) { server_session->SetHleHandler(shared_from_this()); connected_sessions.push_back(std::move(server_session)); } -void SessionRequestHandler::ClientDisconnected(const SharedPtr<ServerSession>& server_session) { +void SessionRequestHandler::ClientDisconnected( + const std::shared_ptr<ServerSession>& server_session) { server_session->SetHleHandler(nullptr); boost::range::remove_erase(connected_sessions, server_session); } -SharedPtr<WritableEvent> HLERequestContext::SleepClientThread( +std::shared_ptr<WritableEvent> HLERequestContext::SleepClientThread( const std::string& reason, u64 timeout, WakeupCallback&& callback, - SharedPtr<WritableEvent> writable_event) { + std::shared_ptr<WritableEvent> writable_event) { // Put the client thread to sleep until the wait event is signaled or the timeout expires. - thread->SetWakeupCallback([context = *this, callback]( - ThreadWakeupReason reason, SharedPtr<Thread> thread, - SharedPtr<WaitObject> object, std::size_t index) mutable -> bool { + thread->SetWakeupCallback([context = *this, callback](ThreadWakeupReason reason, + std::shared_ptr<Thread> thread, + std::shared_ptr<WaitObject> object, + std::size_t index) mutable -> bool { ASSERT(thread->GetStatus() == ThreadStatus::WaitHLEEvent); callback(thread, context, reason); context.WriteToOutgoingCommandBuffer(*thread); @@ -72,11 +74,13 @@ SharedPtr<WritableEvent> HLERequestContext::SleepClientThread( thread->WakeAfterDelay(timeout); } + is_thread_waiting = true; + return writable_event; } -HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_session, - SharedPtr<Thread> thread) +HLERequestContext::HLERequestContext(std::shared_ptr<Kernel::ServerSession> server_session, + std::shared_ptr<Thread> thread) : server_session(std::move(server_session)), thread(std::move(thread)) { cmd_buf[0] = 0; } @@ -212,10 +216,11 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const HandleTabl ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) { auto& owner_process = *thread.GetOwnerProcess(); auto& handle_table = owner_process.GetHandleTable(); + auto& memory = Core::System::GetInstance().Memory(); std::array<u32, IPC::COMMAND_BUFFER_LENGTH> dst_cmdbuf; - Memory::ReadBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(), - dst_cmdbuf.size() * sizeof(u32)); + memory.ReadBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(), + dst_cmdbuf.size() * sizeof(u32)); // The header was already built in the internal command buffer. Attempt to parse it to verify // the integrity and then copy it over to the target command buffer. @@ -271,8 +276,8 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) { } // Copy the translated command buffer back into the thread's command buffer area. - Memory::WriteBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(), - dst_cmdbuf.size() * sizeof(u32)); + memory.WriteBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(), + dst_cmdbuf.size() * sizeof(u32)); return RESULT_SUCCESS; } @@ -280,15 +285,14 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) { std::vector<u8> HLERequestContext::ReadBuffer(int buffer_index) const { std::vector<u8> buffer; const bool is_buffer_a{BufferDescriptorA().size() && BufferDescriptorA()[buffer_index].Size()}; + auto& memory = Core::System::GetInstance().Memory(); if (is_buffer_a) { buffer.resize(BufferDescriptorA()[buffer_index].Size()); - Memory::ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), - buffer.size()); + memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), buffer.size()); } else { buffer.resize(BufferDescriptorX()[buffer_index].Size()); - Memory::ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), - buffer.size()); + memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), buffer.size()); } return buffer; @@ -309,10 +313,11 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size, size = buffer_size; // TODO(bunnei): This needs to be HW tested } + auto& memory = Core::System::GetInstance().Memory(); if (is_buffer_b) { - Memory::WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size); + memory.WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size); } else { - Memory::WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size); + memory.WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size); } return size; diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index ccf5e56aa..050ad8fd7 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -5,6 +5,7 @@ #pragma once #include <array> +#include <functional> #include <memory> #include <optional> #include <string> @@ -60,20 +61,20 @@ public: * associated ServerSession alive for the duration of the connection. * @param server_session Owning pointer to the ServerSession associated with the connection. */ - void ClientConnected(SharedPtr<ServerSession> server_session); + void ClientConnected(std::shared_ptr<ServerSession> server_session); /** * Signals that a client has just disconnected from this HLE handler and releases the * associated ServerSession. * @param server_session ServerSession associated with the connection. */ - void ClientDisconnected(const SharedPtr<ServerSession>& server_session); + void ClientDisconnected(const std::shared_ptr<ServerSession>& server_session); protected: /// List of sessions that are connected to this handler. /// A ServerSession whose server endpoint is an HLE implementation is kept alive by this list /// for the duration of the connection. - std::vector<SharedPtr<ServerSession>> connected_sessions; + std::vector<std::shared_ptr<ServerSession>> connected_sessions; }; /** @@ -97,7 +98,8 @@ protected: */ class HLERequestContext { public: - explicit HLERequestContext(SharedPtr<ServerSession> session, SharedPtr<Thread> thread); + explicit HLERequestContext(std::shared_ptr<ServerSession> session, + std::shared_ptr<Thread> thread); ~HLERequestContext(); /// Returns a pointer to the IPC command buffer for this request. @@ -109,12 +111,12 @@ public: * Returns the session through which this request was made. This can be used as a map key to * access per-client data on services. */ - const SharedPtr<Kernel::ServerSession>& Session() const { + const std::shared_ptr<Kernel::ServerSession>& Session() const { return server_session; } - using WakeupCallback = std::function<void(SharedPtr<Thread> thread, HLERequestContext& context, - ThreadWakeupReason reason)>; + using WakeupCallback = std::function<void( + std::shared_ptr<Thread> thread, HLERequestContext& context, ThreadWakeupReason reason)>; /** * Puts the specified guest thread to sleep until the returned event is signaled or until the @@ -129,9 +131,9 @@ public: * created. * @returns Event that when signaled will resume the thread and call the callback function. */ - SharedPtr<WritableEvent> SleepClientThread(const std::string& reason, u64 timeout, - WakeupCallback&& callback, - SharedPtr<WritableEvent> writable_event = nullptr); + std::shared_ptr<WritableEvent> SleepClientThread( + const std::string& reason, u64 timeout, WakeupCallback&& callback, + std::shared_ptr<WritableEvent> writable_event = nullptr); /// Populates this context with data from the requesting process/thread. ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table, @@ -209,20 +211,20 @@ public: std::size_t GetWriteBufferSize(int buffer_index = 0) const; template <typename T> - SharedPtr<T> GetCopyObject(std::size_t index) { + std::shared_ptr<T> GetCopyObject(std::size_t index) { return DynamicObjectCast<T>(copy_objects.at(index)); } template <typename T> - SharedPtr<T> GetMoveObject(std::size_t index) { + std::shared_ptr<T> GetMoveObject(std::size_t index) { return DynamicObjectCast<T>(move_objects.at(index)); } - void AddMoveObject(SharedPtr<Object> object) { + void AddMoveObject(std::shared_ptr<Object> object) { move_objects.emplace_back(std::move(object)); } - void AddCopyObject(SharedPtr<Object> object) { + void AddCopyObject(std::shared_ptr<Object> object) { copy_objects.emplace_back(std::move(object)); } @@ -262,15 +264,27 @@ public: std::string Description() const; + Thread& GetThread() { + return *thread; + } + + const Thread& GetThread() const { + return *thread; + } + + bool IsThreadWaiting() const { + return is_thread_waiting; + } + private: void ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, bool incoming); std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; - SharedPtr<Kernel::ServerSession> server_session; - SharedPtr<Thread> thread; + std::shared_ptr<Kernel::ServerSession> server_session; + std::shared_ptr<Thread> thread; // TODO(yuriks): Check common usage of this and optimize size accordingly - boost::container::small_vector<SharedPtr<Object>, 8> move_objects; - boost::container::small_vector<SharedPtr<Object>, 8> copy_objects; + boost::container::small_vector<std::shared_ptr<Object>, 8> move_objects; + boost::container::small_vector<std::shared_ptr<Object>, 8> copy_objects; boost::container::small_vector<std::shared_ptr<SessionRequestHandler>, 8> domain_objects; std::optional<IPC::CommandHeader> command_header; @@ -288,6 +302,7 @@ private: u32_le command{}; std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers; + bool is_thread_waiting{}; }; } // namespace Kernel diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index f94ac150d..1c90546a4 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -40,7 +40,7 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_ // Lock the global kernel mutex when we enter the kernel HLE. std::lock_guard lock{HLE::g_hle_lock}; - SharedPtr<Thread> thread = + std::shared_ptr<Thread> thread = system.Kernel().RetrieveThreadFromWakeupCallbackHandleTable(proper_handle); if (thread == nullptr) { LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", proper_handle); @@ -53,7 +53,7 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_ thread->GetStatus() == ThreadStatus::WaitHLEEvent) { // Remove the thread from each of its waiting objects' waitlists for (const auto& object : thread->GetWaitObjects()) { - object->RemoveWaitingThread(thread.get()); + object->RemoveWaitingThread(thread); } thread->ClearWaitObjects(); @@ -64,8 +64,11 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_ } else if (thread->GetStatus() == ThreadStatus::WaitMutex || thread->GetStatus() == ThreadStatus::WaitCondVar) { thread->SetMutexWaitAddress(0); - thread->SetCondVarWaitAddress(0); thread->SetWaitHandle(0); + if (thread->GetStatus() == ThreadStatus::WaitCondVar) { + thread->GetOwnerProcess()->RemoveConditionVariableThread(thread); + thread->SetCondVarWaitAddress(0); + } auto* const lock_owner = thread->GetLockOwner(); // Threads waking up by timeout from WaitProcessWideKey do not perform priority inheritance @@ -136,12 +139,12 @@ struct KernelCore::Impl { void InitializeThreads() { thread_wakeup_event_type = - system.CoreTiming().RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback); + Core::Timing::CreateEvent("ThreadWakeupCallback", ThreadWakeupCallback); } void InitializePreemption() { - preemption_event = system.CoreTiming().RegisterEvent( - "PreemptionCallback", [this](u64 userdata, s64 cycles_late) { + preemption_event = + Core::Timing::CreateEvent("PreemptionCallback", [this](u64 userdata, s64 cycles_late) { global_scheduler.PreemptThreads(); s64 time_interval = Core::Timing::msToCycles(std::chrono::milliseconds(10)); system.CoreTiming().ScheduleEvent(time_interval, preemption_event); @@ -151,20 +154,31 @@ struct KernelCore::Impl { system.CoreTiming().ScheduleEvent(time_interval, preemption_event); } + void MakeCurrentProcess(Process* process) { + current_process = process; + + if (process == nullptr) { + return; + } + + system.Memory().SetCurrentPageTable(*process); + } + std::atomic<u32> next_object_id{0}; std::atomic<u64> next_kernel_process_id{Process::InitialKIPIDMin}; std::atomic<u64> next_user_process_id{Process::ProcessIDMin}; std::atomic<u64> next_thread_id{1}; // Lists all processes that exist in the current session. - std::vector<SharedPtr<Process>> process_list; + std::vector<std::shared_ptr<Process>> process_list; Process* current_process = nullptr; Kernel::GlobalScheduler global_scheduler; - SharedPtr<ResourceLimit> system_resource_limit; + std::shared_ptr<ResourceLimit> system_resource_limit; + + std::shared_ptr<Core::Timing::EventType> thread_wakeup_event_type; + std::shared_ptr<Core::Timing::EventType> preemption_event; - Core::Timing::EventType* thread_wakeup_event_type = nullptr; - Core::Timing::EventType* preemption_event = nullptr; // TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, // allowing us to simply use a pool index or similar. Kernel::HandleTable thread_wakeup_callback_handle_table; @@ -190,26 +204,21 @@ void KernelCore::Shutdown() { impl->Shutdown(); } -SharedPtr<ResourceLimit> KernelCore::GetSystemResourceLimit() const { +std::shared_ptr<ResourceLimit> KernelCore::GetSystemResourceLimit() const { return impl->system_resource_limit; } -SharedPtr<Thread> KernelCore::RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const { +std::shared_ptr<Thread> KernelCore::RetrieveThreadFromWakeupCallbackHandleTable( + Handle handle) const { return impl->thread_wakeup_callback_handle_table.Get<Thread>(handle); } -void KernelCore::AppendNewProcess(SharedPtr<Process> process) { +void KernelCore::AppendNewProcess(std::shared_ptr<Process> process) { impl->process_list.push_back(std::move(process)); } void KernelCore::MakeCurrentProcess(Process* process) { - impl->current_process = process; - - if (process == nullptr) { - return; - } - - Memory::SetCurrentPageTable(*process); + impl->MakeCurrentProcess(process); } Process* KernelCore::CurrentProcess() { @@ -220,7 +229,7 @@ const Process* KernelCore::CurrentProcess() const { return impl->current_process; } -const std::vector<SharedPtr<Process>>& KernelCore::GetProcessList() const { +const std::vector<std::shared_ptr<Process>>& KernelCore::GetProcessList() const { return impl->process_list; } @@ -232,7 +241,7 @@ const Kernel::GlobalScheduler& KernelCore::GlobalScheduler() const { return impl->global_scheduler; } -void KernelCore::AddNamedPort(std::string name, SharedPtr<ClientPort> port) { +void KernelCore::AddNamedPort(std::string name, std::shared_ptr<ClientPort> port) { impl->named_ports.emplace(std::move(name), std::move(port)); } @@ -265,7 +274,7 @@ u64 KernelCore::CreateNewUserProcessID() { return impl->next_user_process_id++; } -Core::Timing::EventType* KernelCore::ThreadWakeupCallbackEventType() const { +const std::shared_ptr<Core::Timing::EventType>& KernelCore::ThreadWakeupCallbackEventType() const { return impl->thread_wakeup_event_type; } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index c4397fc77..babb531c6 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -6,6 +6,7 @@ #include <string> #include <unordered_map> +#include <vector> #include "core/hle/kernel/object.h" namespace Core { @@ -30,7 +31,7 @@ class Thread; /// Represents a single instance of the kernel. class KernelCore { private: - using NamedPortTable = std::unordered_map<std::string, SharedPtr<ClientPort>>; + using NamedPortTable = std::unordered_map<std::string, std::shared_ptr<ClientPort>>; public: /// Constructs an instance of the kernel using the given System @@ -56,13 +57,13 @@ public: void Shutdown(); /// Retrieves a shared pointer to the system resource limit instance. - SharedPtr<ResourceLimit> GetSystemResourceLimit() const; + std::shared_ptr<ResourceLimit> GetSystemResourceLimit() const; /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table. - SharedPtr<Thread> RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const; + std::shared_ptr<Thread> RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const; /// Adds the given shared pointer to an internal list of active processes. - void AppendNewProcess(SharedPtr<Process> process); + void AppendNewProcess(std::shared_ptr<Process> process); /// Makes the given process the new current process. void MakeCurrentProcess(Process* process); @@ -74,7 +75,7 @@ public: const Process* CurrentProcess() const; /// Retrieves the list of processes. - const std::vector<SharedPtr<Process>>& GetProcessList() const; + const std::vector<std::shared_ptr<Process>>& GetProcessList() const; /// Gets the sole instance of the global scheduler Kernel::GlobalScheduler& GlobalScheduler(); @@ -83,7 +84,7 @@ public: const Kernel::GlobalScheduler& GlobalScheduler() const; /// Adds a port to the named port table - void AddNamedPort(std::string name, SharedPtr<ClientPort> port); + void AddNamedPort(std::string name, std::shared_ptr<ClientPort> port); /// Finds a port within the named port table with the given name. NamedPortTable::iterator FindNamedPort(const std::string& name); @@ -112,7 +113,7 @@ private: u64 CreateNewThreadID(); /// Retrieves the event type used for thread wakeup callbacks. - Core::Timing::EventType* ThreadWakeupCallbackEventType() const; + const std::shared_ptr<Core::Timing::EventType>& ThreadWakeupCallbackEventType() const; /// Provides a reference to the thread wakeup callback handle table. Kernel::HandleTable& ThreadWakeupCallbackHandleTable(); diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 663d0f4b6..061e9bcb0 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -22,10 +22,10 @@ namespace Kernel { /// Returns the number of threads that are waiting for a mutex, and the highest priority one among /// those. -static std::pair<SharedPtr<Thread>, u32> GetHighestPriorityMutexWaitingThread( - const SharedPtr<Thread>& current_thread, VAddr mutex_addr) { +static std::pair<std::shared_ptr<Thread>, u32> GetHighestPriorityMutexWaitingThread( + const std::shared_ptr<Thread>& current_thread, VAddr mutex_addr) { - SharedPtr<Thread> highest_priority_thread; + std::shared_ptr<Thread> highest_priority_thread; u32 num_waiters = 0; for (const auto& thread : current_thread->GetMutexWaitingThreads()) { @@ -45,14 +45,14 @@ static std::pair<SharedPtr<Thread>, u32> GetHighestPriorityMutexWaitingThread( } /// Update the mutex owner field of all threads waiting on the mutex to point to the new owner. -static void TransferMutexOwnership(VAddr mutex_addr, SharedPtr<Thread> current_thread, - SharedPtr<Thread> new_owner) { +static void TransferMutexOwnership(VAddr mutex_addr, std::shared_ptr<Thread> current_thread, + std::shared_ptr<Thread> new_owner) { const auto threads = current_thread->GetMutexWaitingThreads(); for (const auto& thread : threads) { if (thread->GetMutexWaitAddress() != mutex_addr) continue; - ASSERT(thread->GetLockOwner() == current_thread); + ASSERT(thread->GetLockOwner() == current_thread.get()); current_thread->RemoveMutexWaiter(thread); if (new_owner != thread) new_owner->AddMutexWaiter(thread); @@ -70,15 +70,16 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle, } const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - Thread* const current_thread = system.CurrentScheduler().GetCurrentThread(); - SharedPtr<Thread> holding_thread = handle_table.Get<Thread>(holding_thread_handle); - SharedPtr<Thread> requesting_thread = handle_table.Get<Thread>(requesting_thread_handle); + std::shared_ptr<Thread> current_thread = + SharedFrom(system.CurrentScheduler().GetCurrentThread()); + std::shared_ptr<Thread> holding_thread = handle_table.Get<Thread>(holding_thread_handle); + std::shared_ptr<Thread> requesting_thread = handle_table.Get<Thread>(requesting_thread_handle); // TODO(Subv): It is currently unknown if it is possible to lock a mutex in behalf of another // thread. ASSERT(requesting_thread == current_thread); - const u32 addr_value = Memory::Read32(address); + const u32 addr_value = system.Memory().Read32(address); // If the mutex isn't being held, just return success. if (addr_value != (holding_thread_handle | Mutex::MutexHasWaitersFlag)) { @@ -110,12 +111,13 @@ ResultCode Mutex::Release(VAddr address) { return ERR_INVALID_ADDRESS; } - auto* const current_thread = system.CurrentScheduler().GetCurrentThread(); + std::shared_ptr<Thread> current_thread = + SharedFrom(system.CurrentScheduler().GetCurrentThread()); auto [thread, num_waiters] = GetHighestPriorityMutexWaitingThread(current_thread, address); // There are no more threads waiting for the mutex, release it completely. if (thread == nullptr) { - Memory::Write32(address, 0); + system.Memory().Write32(address, 0); return RESULT_SUCCESS; } @@ -130,7 +132,7 @@ ResultCode Mutex::Release(VAddr address) { } // Grant the mutex to the next waiting thread and resume it. - Memory::Write32(address, mutex_value); + system.Memory().Write32(address, mutex_value); ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex); thread->ResumeFromWait(); diff --git a/src/core/hle/kernel/object.cpp b/src/core/hle/kernel/object.cpp index 10431e94c..2c571792b 100644 --- a/src/core/hle/kernel/object.cpp +++ b/src/core/hle/kernel/object.cpp @@ -27,6 +27,7 @@ bool Object::IsWaitable() const { case HandleType::ResourceLimit: case HandleType::ClientPort: case HandleType::ClientSession: + case HandleType::Session: return false; } diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h index a6faeb83b..e3391e2af 100644 --- a/src/core/hle/kernel/object.h +++ b/src/core/hle/kernel/object.h @@ -5,10 +5,9 @@ #pragma once #include <atomic> +#include <memory> #include <string> -#include <boost/smart_ptr/intrusive_ptr.hpp> - #include "common/common_types.h" namespace Kernel { @@ -30,9 +29,10 @@ enum class HandleType : u32 { ServerPort, ClientSession, ServerSession, + Session, }; -class Object : NonCopyable { +class Object : NonCopyable, public std::enable_shared_from_this<Object> { public: explicit Object(KernelCore& kernel); virtual ~Object(); @@ -61,35 +61,24 @@ protected: KernelCore& kernel; private: - friend void intrusive_ptr_add_ref(Object*); - friend void intrusive_ptr_release(Object*); - - std::atomic<u32> ref_count{0}; std::atomic<u32> object_id{0}; }; -// Special functions used by boost::instrusive_ptr to do automatic ref-counting -inline void intrusive_ptr_add_ref(Object* object) { - object->ref_count.fetch_add(1, std::memory_order_relaxed); -} - -inline void intrusive_ptr_release(Object* object) { - if (object->ref_count.fetch_sub(1, std::memory_order_acq_rel) == 1) { - delete object; - } -} - template <typename T> -using SharedPtr = boost::intrusive_ptr<T>; +std::shared_ptr<T> SharedFrom(T* raw) { + if (raw == nullptr) + return nullptr; + return std::static_pointer_cast<T>(raw->shared_from_this()); +} /** * Attempts to downcast the given Object pointer to a pointer to T. * @return Derived pointer to the object, or `nullptr` if `object` isn't of type T. */ template <typename T> -inline SharedPtr<T> DynamicObjectCast(SharedPtr<Object> object) { +inline std::shared_ptr<T> DynamicObjectCast(std::shared_ptr<Object> object) { if (object != nullptr && object->GetHandleType() == T::HANDLE_TYPE) { - return boost::static_pointer_cast<T>(object); + return std::static_pointer_cast<T>(object); } return nullptr; } diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 12a900bcc..12ea4ebe3 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -38,7 +38,7 @@ void SetupMainThread(Process& owner_process, KernelCore& kernel, u32 priority) { auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, owner_process.GetIdealCore(), stack_top, owner_process); - SharedPtr<Thread> thread = std::move(thread_res).Unwrap(); + std::shared_ptr<Thread> thread = std::move(thread_res).Unwrap(); // Register 1 must be a handle to the main thread const Handle thread_handle = owner_process.GetHandleTable().Create(thread).Unwrap(); @@ -100,10 +100,10 @@ private: std::bitset<num_slot_entries> is_slot_used; }; -SharedPtr<Process> Process::Create(Core::System& system, std::string name, ProcessType type) { +std::shared_ptr<Process> Process::Create(Core::System& system, std::string name, ProcessType type) { auto& kernel = system.Kernel(); - SharedPtr<Process> process(new Process(system)); + std::shared_ptr<Process> process = std::make_shared<Process>(system); process->name = std::move(name); process->resource_limit = kernel.GetSystemResourceLimit(); process->status = ProcessStatus::Created; @@ -121,7 +121,7 @@ SharedPtr<Process> Process::Create(Core::System& system, std::string name, Proce return process; } -SharedPtr<ResourceLimit> Process::GetResourceLimit() const { +std::shared_ptr<ResourceLimit> Process::GetResourceLimit() const { return resource_limit; } @@ -142,6 +142,49 @@ u64 Process::GetTotalPhysicalMemoryUsedWithoutSystemResource() const { return GetTotalPhysicalMemoryUsed() - GetSystemResourceUsage(); } +void Process::InsertConditionVariableThread(std::shared_ptr<Thread> thread) { + VAddr cond_var_addr = thread->GetCondVarWaitAddress(); + std::list<std::shared_ptr<Thread>>& thread_list = cond_var_threads[cond_var_addr]; + auto it = thread_list.begin(); + while (it != thread_list.end()) { + const std::shared_ptr<Thread> current_thread = *it; + if (current_thread->GetPriority() > thread->GetPriority()) { + thread_list.insert(it, thread); + return; + } + ++it; + } + thread_list.push_back(thread); +} + +void Process::RemoveConditionVariableThread(std::shared_ptr<Thread> thread) { + VAddr cond_var_addr = thread->GetCondVarWaitAddress(); + std::list<std::shared_ptr<Thread>>& thread_list = cond_var_threads[cond_var_addr]; + auto it = thread_list.begin(); + while (it != thread_list.end()) { + const std::shared_ptr<Thread> current_thread = *it; + if (current_thread.get() == thread.get()) { + thread_list.erase(it); + return; + } + ++it; + } + UNREACHABLE(); +} + +std::vector<std::shared_ptr<Thread>> Process::GetConditionVariableThreads( + const VAddr cond_var_addr) { + std::vector<std::shared_ptr<Thread>> result{}; + std::list<std::shared_ptr<Thread>>& thread_list = cond_var_threads[cond_var_addr]; + auto it = thread_list.begin(); + while (it != thread_list.end()) { + std::shared_ptr<Thread> current_thread = *it; + result.push_back(current_thread); + ++it; + } + return result; +} + void Process::RegisterThread(const Thread* thread) { thread_list.push_back(thread); } @@ -197,12 +240,12 @@ void Process::Run(s32 main_thread_priority, u64 stack_size) { void Process::PrepareForTermination() { ChangeStatus(ProcessStatus::Exiting); - const auto stop_threads = [this](const std::vector<SharedPtr<Thread>>& thread_list) { + const auto stop_threads = [this](const std::vector<std::shared_ptr<Thread>>& thread_list) { for (auto& thread : thread_list) { if (thread->GetOwnerProcess() != this) continue; - if (thread == system.CurrentScheduler().GetCurrentThread()) + if (thread.get() == system.CurrentScheduler().GetCurrentThread()) continue; // TODO(Subv): When are the other running/ready threads terminated? diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index c2df451f3..3483fa19d 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -8,6 +8,7 @@ #include <cstddef> #include <list> #include <string> +#include <unordered_map> #include <vector> #include "common/common_types.h" #include "core/hle/kernel/address_arbiter.h" @@ -61,6 +62,9 @@ enum class ProcessStatus { class Process final : public WaitObject { public: + explicit Process(Core::System& system); + ~Process() override; + enum : u64 { /// Lowest allowed process ID for a kernel initial process. InitialKIPIDMin = 1, @@ -81,7 +85,8 @@ public: static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4; - static SharedPtr<Process> Create(Core::System& system, std::string name, ProcessType type); + static std::shared_ptr<Process> Create(Core::System& system, std::string name, + ProcessType type); std::string GetTypeName() const override { return "Process"; @@ -156,7 +161,7 @@ public: } /// Gets the resource limit descriptor for this process - SharedPtr<ResourceLimit> GetResourceLimit() const; + std::shared_ptr<ResourceLimit> GetResourceLimit() const; /// Gets the ideal CPU core ID for this process u8 GetIdealCore() const { @@ -232,6 +237,15 @@ public: return thread_list; } + /// Insert a thread into the condition variable wait container + void InsertConditionVariableThread(std::shared_ptr<Thread> thread); + + /// Remove a thread from the condition variable wait container + void RemoveConditionVariableThread(std::shared_ptr<Thread> thread); + + /// Obtain all condition variable threads waiting for some address + std::vector<std::shared_ptr<Thread>> GetConditionVariableThreads(VAddr cond_var_addr); + /// Registers a thread as being created under this process, /// adding it to this process' thread list. void RegisterThread(const Thread* thread); @@ -287,9 +301,6 @@ public: void FreeTLSRegion(VAddr tls_address); private: - explicit Process(Core::System& system); - ~Process() override; - /// Checks if the specified thread should wait until this process is available. bool ShouldWait(const Thread* thread) const override; @@ -328,7 +339,7 @@ private: u32 system_resource_size = 0; /// Resource limit descriptor for this process - SharedPtr<ResourceLimit> resource_limit; + std::shared_ptr<ResourceLimit> resource_limit; /// The ideal CPU core for this process, threads are scheduled on this core by default. u8 ideal_core = 0; @@ -375,6 +386,9 @@ private: /// List of threads that are running with this process as their owner. std::list<const Thread*> thread_list; + /// List of threads waiting for a condition variable + std::unordered_map<VAddr, std::list<std::shared_ptr<Thread>>> cond_var_threads; + /// System context Core::System& system; diff --git a/src/core/hle/kernel/resource_limit.cpp b/src/core/hle/kernel/resource_limit.cpp index 173f69915..b53423462 100644 --- a/src/core/hle/kernel/resource_limit.cpp +++ b/src/core/hle/kernel/resource_limit.cpp @@ -16,8 +16,8 @@ constexpr std::size_t ResourceTypeToIndex(ResourceType type) { ResourceLimit::ResourceLimit(KernelCore& kernel) : Object{kernel} {} ResourceLimit::~ResourceLimit() = default; -SharedPtr<ResourceLimit> ResourceLimit::Create(KernelCore& kernel) { - return new ResourceLimit(kernel); +std::shared_ptr<ResourceLimit> ResourceLimit::Create(KernelCore& kernel) { + return std::make_shared<ResourceLimit>(kernel); } s64 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const { diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h index 2613a6bb5..b5534620d 100644 --- a/src/core/hle/kernel/resource_limit.h +++ b/src/core/hle/kernel/resource_limit.h @@ -31,8 +31,11 @@ constexpr bool IsValidResourceType(ResourceType type) { class ResourceLimit final : public Object { public: + explicit ResourceLimit(KernelCore& kernel); + ~ResourceLimit() override; + /// Creates a resource limit object. - static SharedPtr<ResourceLimit> Create(KernelCore& kernel); + static std::shared_ptr<ResourceLimit> Create(KernelCore& kernel); std::string GetTypeName() const override { return "ResourceLimit"; @@ -76,9 +79,6 @@ public: ResultCode SetLimitValue(ResourceType resource, s64 value); private: - explicit ResourceLimit(KernelCore& kernel); - ~ResourceLimit() override; - // TODO(Subv): Increment resource limit current values in their respective Kernel::T::Create // functions // diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 16e95381b..3f5192087 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -26,11 +26,11 @@ GlobalScheduler::GlobalScheduler(Core::System& system) : system{system} {} GlobalScheduler::~GlobalScheduler() = default; -void GlobalScheduler::AddThread(SharedPtr<Thread> thread) { +void GlobalScheduler::AddThread(std::shared_ptr<Thread> thread) { thread_list.push_back(std::move(thread)); } -void GlobalScheduler::RemoveThread(const Thread* thread) { +void GlobalScheduler::RemoveThread(std::shared_ptr<Thread> thread) { thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread), thread_list.end()); } @@ -42,11 +42,11 @@ void GlobalScheduler::UnloadThread(std::size_t core) { void GlobalScheduler::SelectThread(std::size_t core) { const auto update_thread = [](Thread* thread, Scheduler& sched) { - if (thread != sched.selected_thread) { + if (thread != sched.selected_thread.get()) { if (thread == nullptr) { ++sched.idle_selection_count; } - sched.selected_thread = thread; + sched.selected_thread = SharedFrom(thread); } sched.is_context_switch_pending = sched.selected_thread != sched.current_thread; std::atomic_thread_fence(std::memory_order_seq_cst); @@ -446,7 +446,7 @@ void Scheduler::SwitchContext() { // Cancel any outstanding wakeup events for this thread new_thread->CancelWakeupTimer(); - current_thread = new_thread; + current_thread = SharedFrom(new_thread); new_thread->SetStatus(ThreadStatus::Running); new_thread->SetIsRunning(true); diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 311849dfb..3c5c21346 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -28,13 +28,13 @@ public: ~GlobalScheduler(); /// Adds a new thread to the scheduler - void AddThread(SharedPtr<Thread> thread); + void AddThread(std::shared_ptr<Thread> thread); /// Removes a thread from the scheduler - void RemoveThread(const Thread* thread); + void RemoveThread(std::shared_ptr<Thread> thread); /// Returns a list of all threads managed by the scheduler - const std::vector<SharedPtr<Thread>>& GetThreadList() const { + const std::vector<std::shared_ptr<Thread>>& GetThreadList() const { return thread_list; } @@ -157,7 +157,7 @@ private: std::array<u32, NUM_CPU_CORES> preemption_priorities = {59, 59, 59, 62}; /// Lists all thread ids that aren't deleted/etc. - std::vector<SharedPtr<Thread>> thread_list; + std::vector<std::shared_ptr<Thread>> thread_list; Core::System& system; }; @@ -213,8 +213,8 @@ private: */ void UpdateLastContextSwitchTime(Thread* thread, Process* process); - SharedPtr<Thread> current_thread = nullptr; - SharedPtr<Thread> selected_thread = nullptr; + std::shared_ptr<Thread> current_thread = nullptr; + std::shared_ptr<Thread> selected_thread = nullptr; Core::System& system; Core::ARM_Interface& cpu_core; diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp index 02e7c60e6..a4ccfa35e 100644 --- a/src/core/hle/kernel/server_port.cpp +++ b/src/core/hle/kernel/server_port.cpp @@ -16,7 +16,7 @@ namespace Kernel { ServerPort::ServerPort(KernelCore& kernel) : WaitObject{kernel} {} ServerPort::~ServerPort() = default; -ResultVal<SharedPtr<ServerSession>> ServerPort::Accept() { +ResultVal<std::shared_ptr<ServerSession>> ServerPort::Accept() { if (pending_sessions.empty()) { return ERR_NOT_FOUND; } @@ -26,7 +26,7 @@ ResultVal<SharedPtr<ServerSession>> ServerPort::Accept() { return MakeResult(std::move(session)); } -void ServerPort::AppendPendingSession(SharedPtr<ServerSession> pending_session) { +void ServerPort::AppendPendingSession(std::shared_ptr<ServerSession> pending_session) { pending_sessions.push_back(std::move(pending_session)); } @@ -41,8 +41,8 @@ void ServerPort::Acquire(Thread* thread) { ServerPort::PortPair ServerPort::CreatePortPair(KernelCore& kernel, u32 max_sessions, std::string name) { - SharedPtr<ServerPort> server_port(new ServerPort(kernel)); - SharedPtr<ClientPort> client_port(new ClientPort(kernel)); + std::shared_ptr<ServerPort> server_port = std::make_shared<ServerPort>(kernel); + std::shared_ptr<ClientPort> client_port = std::make_shared<ClientPort>(kernel); server_port->name = name + "_Server"; client_port->name = name + "_Client"; diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h index dc88a1ebd..8be8a75ea 100644 --- a/src/core/hle/kernel/server_port.h +++ b/src/core/hle/kernel/server_port.h @@ -22,8 +22,11 @@ class SessionRequestHandler; class ServerPort final : public WaitObject { public: + explicit ServerPort(KernelCore& kernel); + ~ServerPort() override; + using HLEHandler = std::shared_ptr<SessionRequestHandler>; - using PortPair = std::pair<SharedPtr<ServerPort>, SharedPtr<ClientPort>>; + using PortPair = std::pair<std::shared_ptr<ServerPort>, std::shared_ptr<ClientPort>>; /** * Creates a pair of ServerPort and an associated ClientPort. @@ -52,7 +55,7 @@ public: * Accepts a pending incoming connection on this port. If there are no pending sessions, will * return ERR_NO_PENDING_SESSIONS. */ - ResultVal<SharedPtr<ServerSession>> Accept(); + ResultVal<std::shared_ptr<ServerSession>> Accept(); /// Whether or not this server port has an HLE handler available. bool HasHLEHandler() const { @@ -74,17 +77,14 @@ public: /// Appends a ServerSession to the collection of ServerSessions /// waiting to be accepted by this port. - void AppendPendingSession(SharedPtr<ServerSession> pending_session); + void AppendPendingSession(std::shared_ptr<ServerSession> pending_session); bool ShouldWait(const Thread* thread) const override; void Acquire(Thread* thread) override; private: - explicit ServerPort(KernelCore& kernel); - ~ServerPort() override; - /// ServerSessions waiting to be accepted by the port - std::vector<SharedPtr<ServerSession>> pending_sessions; + std::vector<std::shared_ptr<ServerSession>> pending_sessions; /// This session's HLE request handler template (optional) /// ServerSessions created from this port inherit a reference to this handler. diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 30b2bfb5a..7825e1ec4 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -1,4 +1,4 @@ -// Copyright 2016 Citra Emulator Project +// Copyright 2019 yuzu emulator team // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -9,6 +9,7 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "core/core.h" +#include "core/core_timing.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/client_session.h" @@ -19,35 +20,32 @@ #include "core/hle/kernel/server_session.h" #include "core/hle/kernel/session.h" #include "core/hle/kernel/thread.h" +#include "core/memory.h" namespace Kernel { ServerSession::ServerSession(KernelCore& kernel) : WaitObject{kernel} {} -ServerSession::~ServerSession() { - // This destructor will be called automatically when the last ServerSession handle is closed by - // the emulated application. +ServerSession::~ServerSession() = default; - // Decrease the port's connection count. - if (parent->port) { - parent->port->ConnectionClosed(); - } - - parent->server = nullptr; -} +ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel, + std::shared_ptr<Session> parent, + std::string name) { + std::shared_ptr<ServerSession> session{std::make_shared<ServerSession>(kernel)}; -ResultVal<SharedPtr<ServerSession>> ServerSession::Create(KernelCore& kernel, std::string name) { - SharedPtr<ServerSession> server_session(new ServerSession(kernel)); + session->request_event = Core::Timing::CreateEvent( + name, [session](u64 userdata, s64 cycles_late) { session->CompleteSyncRequest(); }); + session->name = std::move(name); + session->parent = std::move(parent); - server_session->name = std::move(name); - server_session->parent = nullptr; - - return MakeResult(std::move(server_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 == nullptr) + 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; } @@ -69,7 +67,7 @@ void ServerSession::ClientDisconnected() { if (handler) { // Note that after this returns, this server session's hle_handler is // invalidated (set to null). - handler->ClientDisconnected(this); + handler->ClientDisconnected(SharedFrom(this)); } // Clean up the list of client threads with pending requests, they are unneeded now that the @@ -126,13 +124,21 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con return RESULT_SUCCESS; } -ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) { - // The ServerSession received a sync request, this means that there's new data available - // from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or - // similar. - Kernel::HLERequestContext context(this, thread); - u32* cmd_buf = (u32*)Memory::GetPointer(thread->GetTLSAddress()); - context.PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); +ResultCode ServerSession::QueueSyncRequest(std::shared_ptr<Thread> thread, Memory::Memory& memory) { + u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(thread->GetTLSAddress()))}; + std::shared_ptr<Kernel::HLERequestContext> context{ + std::make_shared<Kernel::HLERequestContext>(SharedFrom(this), std::move(thread))}; + + context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); + request_queue.Push(std::move(context)); + + return RESULT_SUCCESS; +} + +ResultCode ServerSession::CompleteSyncRequest() { + ASSERT(!request_queue.Empty()); + + auto& context = *request_queue.Front(); ResultCode result = RESULT_SUCCESS; // If the session has been converted to a domain, handle the domain request @@ -144,61 +150,27 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) { result = hle_handler->HandleSyncRequest(context); } - if (thread->GetStatus() == ThreadStatus::Running) { - // Put the thread to sleep until the server replies, it will be awoken in - // svcReplyAndReceive for LLE servers. - thread->SetStatus(ThreadStatus::WaitIPC); - - if (hle_handler != nullptr) { - // For HLE services, we put the request threads to sleep for a short duration to - // simulate IPC overhead, but only if the HLE handler didn't put the thread to sleep for - // other reasons like an async callback. The IPC overhead is needed to prevent - // starvation when a thread only does sync requests to HLE services while a - // lower-priority thread is waiting to run. - - // This delay was approximated in a homebrew application by measuring the average time - // it takes for svcSendSyncRequest to return when performing the SetLcdForceBlack IPC - // request to the GSP:GPU service in a n3DS with firmware 11.6. The measured values have - // a high variance and vary between models. - static constexpr u64 IPCDelayNanoseconds = 39000; - thread->WakeAfterDelay(IPCDelayNanoseconds); - } else { - // Add the thread to the list of threads that have issued a sync request with this - // server. - pending_requesting_threads.push_back(std::move(thread)); - } - } - - // If this ServerSession does not have an HLE implementation, just wake up the threads waiting - // on it. - WakeupAllWaitingThreads(); - - // Handle scenario when ConvertToDomain command was issued, as we must do the conversion at the - // end of the command such that only commands following this one are handled as domains if (convert_to_domain) { ASSERT_MSG(IsSession(), "ServerSession is already a domain instance."); domain_request_handlers = {hle_handler}; convert_to_domain = false; } - return result; -} - -ServerSession::SessionPair ServerSession::CreateSessionPair(KernelCore& kernel, - const std::string& name, - SharedPtr<ClientPort> port) { - auto server_session = ServerSession::Create(kernel, name + "_Server").Unwrap(); - SharedPtr<ClientSession> client_session(new ClientSession(kernel)); - client_session->name = name + "_Client"; + // Some service requests require the thread to block + if (!context.IsThreadWaiting()) { + context.GetThread().ResumeFromWait(); + context.GetThread().SetWaitSynchronizationResult(result); + } - std::shared_ptr<Session> parent(new Session); - parent->client = client_session.get(); - parent->server = server_session.get(); - parent->port = std::move(port); + request_queue.Pop(); - client_session->parent = parent; - server_session->parent = parent; + return result; +} - return std::make_pair(std::move(server_session), std::move(client_session)); +ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread, + Memory::Memory& memory) { + Core::System::GetInstance().CoreTiming().ScheduleEvent(20000, request_event, {}); + return QueueSyncRequest(std::move(thread), memory); } + } // namespace Kernel diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index 738df30f8..d6e48109e 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright 2019 yuzu emulator team // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -9,17 +9,22 @@ #include <utility> #include <vector> -#include "core/hle/kernel/object.h" +#include "common/threadsafe_queue.h" #include "core/hle/kernel/wait_object.h" #include "core/hle/result.h" +namespace Memory { +class Memory; +} + +namespace Core::Timing { +struct EventType; +} + namespace Kernel { -class ClientPort; -class ClientSession; class HLERequestContext; class KernelCore; -class ServerSession; class Session; class SessionRequestHandler; class Thread; @@ -38,6 +43,15 @@ class Thread; */ class ServerSession final : public WaitObject { public: + explicit ServerSession(KernelCore& kernel); + ~ServerSession() override; + + friend class Session; + + static ResultVal<std::shared_ptr<ServerSession>> Create(KernelCore& kernel, + std::shared_ptr<Session> parent, + std::string name = "Unknown"); + std::string GetTypeName() const override { return "ServerSession"; } @@ -59,18 +73,6 @@ public: return parent.get(); } - using SessionPair = std::pair<SharedPtr<ServerSession>, SharedPtr<ClientSession>>; - - /** - * Creates a pair of ServerSession and an associated ClientSession. - * @param kernel The kernal instance to create the session pair under. - * @param name Optional name of the ports. - * @param client_port Optional The ClientPort that spawned this session. - * @return The created session tuple - */ - static SessionPair CreateSessionPair(KernelCore& kernel, const std::string& name = "Unknown", - SharedPtr<ClientPort> client_port = nullptr); - /** * 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 @@ -82,10 +84,13 @@ public: /** * Handle a sync request from the emulated application. + * * @param thread Thread that initiated the request. + * @param memory Memory context to handle the sync request under. + * * @returns ResultCode from the operation. */ - ResultCode HandleSyncRequest(SharedPtr<Thread> thread); + ResultCode HandleSyncRequest(std::shared_ptr<Thread> thread, Memory::Memory& memory); bool ShouldWait(const Thread* thread) const override; @@ -118,18 +123,11 @@ public: } private: - explicit ServerSession(KernelCore& kernel); - ~ServerSession() override; + /// Queues a sync request from the emulated application. + ResultCode QueueSyncRequest(std::shared_ptr<Thread> thread, Memory::Memory& memory); - /** - * Creates a server session. The server session can have an optional HLE handler, - * which will be invoked to handle the IPC requests that this session receives. - * @param kernel The kernel instance to create this server session under. - * @param name Optional name of the server session. - * @return The created server session - */ - static ResultVal<SharedPtr<ServerSession>> Create(KernelCore& kernel, - std::string name = "Unknown"); + /// Completes a sync request from the emulated application. + ResultCode CompleteSyncRequest(); /// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an /// object handle. @@ -147,18 +145,24 @@ private: /// List of threads that are pending a response after a sync request. This list is processed in /// a LIFO manner, thus, the last request will be dispatched first. /// TODO(Subv): Verify if this is indeed processed in LIFO using a hardware test. - std::vector<SharedPtr<Thread>> pending_requesting_threads; + std::vector<std::shared_ptr<Thread>> pending_requesting_threads; /// Thread whose request is currently being handled. A request is considered "handled" when a /// response is sent via svcReplyAndReceive. /// TODO(Subv): Find a better name for this. - SharedPtr<Thread> currently_handling; + std::shared_ptr<Thread> currently_handling; /// When set to True, converts the session to a domain at the end of the command bool convert_to_domain{}; /// The name of this session (optional) std::string name; + + /// Core timing event used to schedule the service request at some point in the future + std::shared_ptr<Core::Timing::EventType> request_event; + + /// Queue of scheduled service requests + Common::MPSCQueue<std::shared_ptr<Kernel::HLERequestContext>> request_queue; }; } // namespace Kernel diff --git a/src/core/hle/kernel/session.cpp b/src/core/hle/kernel/session.cpp index 642914744..dee6e2b72 100644 --- a/src/core/hle/kernel/session.cpp +++ b/src/core/hle/kernel/session.cpp @@ -1,12 +1,36 @@ -// Copyright 2015 Citra Emulator Project +// Copyright 2019 yuzu emulator team // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/assert.h" +#include "core/hle/kernel/client_session.h" +#include "core/hle/kernel/server_session.h" #include "core/hle/kernel/session.h" -#include "core/hle/kernel/thread.h" namespace Kernel { -Session::Session() {} -Session::~Session() {} +Session::Session(KernelCore& kernel) : WaitObject{kernel} {} +Session::~Session() = default; + +Session::SessionPair Session::Create(KernelCore& kernel, std::string name) { + auto session{std::make_shared<Session>(kernel)}; + auto client_session{Kernel::ClientSession::Create(kernel, session, name + "_Client").Unwrap()}; + auto server_session{Kernel::ServerSession::Create(kernel, session, name + "_Server").Unwrap()}; + + session->name = std::move(name); + session->client = client_session; + session->server = server_session; + + return std::make_pair(std::move(client_session), std::move(server_session)); +} + +bool Session::ShouldWait(const Thread* thread) const { + UNIMPLEMENTED(); + return {}; +} + +void Session::Acquire(Thread* thread) { + UNIMPLEMENTED(); +} + } // namespace Kernel diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h index 7a551f5e4..5a9d4e9ad 100644 --- a/src/core/hle/kernel/session.h +++ b/src/core/hle/kernel/session.h @@ -1,27 +1,64 @@ -// Copyright 2018 yuzu emulator team +// Copyright 2019 yuzu emulator team // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once -#include "core/hle/kernel/object.h" +#include <memory> +#include <string> + +#include "core/hle/kernel/wait_object.h" +#include "core/hle/result.h" namespace Kernel { class ClientSession; -class ClientPort; class ServerSession; /** * Parent structure to link the client and server endpoints of a session with their associated - * client port. The client port need not exist, as is the case for portless sessions like the - * FS File and Directory sessions. When one of the endpoints of a session is destroyed, its - * corresponding field in this structure will be set to nullptr. + * client port. */ -class Session final { +class Session final : public WaitObject { public: - ClientSession* client = nullptr; ///< The client endpoint of the session. - ServerSession* server = nullptr; ///< The server endpoint of the session. - SharedPtr<ClientPort> port; ///< The port that this session is associated with (optional). + explicit Session(KernelCore& kernel); + ~Session() override; + + using SessionPair = std::pair<std::shared_ptr<ClientSession>, std::shared_ptr<ServerSession>>; + + static SessionPair Create(KernelCore& kernel, std::string name = "Unknown"); + + std::string GetName() const override { + return name; + } + + static constexpr HandleType HANDLE_TYPE = HandleType::Session; + HandleType GetHandleType() const override { + return HANDLE_TYPE; + } + + bool ShouldWait(const Thread* thread) const override; + + void Acquire(Thread* thread) override; + + std::shared_ptr<ClientSession> Client() { + if (auto result{client.lock()}) { + return result; + } + return {}; + } + + std::shared_ptr<ServerSession> Server() { + if (auto result{server.lock()}) { + return result; + } + return {}; + } + +private: + std::string name; + std::weak_ptr<ClientSession> client; + std::weak_ptr<ServerSession> server; }; + } // namespace Kernel diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index a815c4eea..afb2e3fc2 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -15,11 +15,12 @@ namespace Kernel { SharedMemory::SharedMemory(KernelCore& kernel) : Object{kernel} {} SharedMemory::~SharedMemory() = default; -SharedPtr<SharedMemory> SharedMemory::Create(KernelCore& kernel, Process* owner_process, u64 size, - MemoryPermission permissions, - MemoryPermission other_permissions, VAddr address, - MemoryRegion region, std::string name) { - SharedPtr<SharedMemory> shared_memory(new SharedMemory(kernel)); +std::shared_ptr<SharedMemory> SharedMemory::Create(KernelCore& kernel, Process* owner_process, + u64 size, MemoryPermission permissions, + MemoryPermission other_permissions, + VAddr address, MemoryRegion region, + std::string name) { + std::shared_ptr<SharedMemory> shared_memory = std::make_shared<SharedMemory>(kernel); shared_memory->owner_process = owner_process; shared_memory->name = std::move(name); @@ -58,10 +59,10 @@ SharedPtr<SharedMemory> SharedMemory::Create(KernelCore& kernel, Process* owner_ return shared_memory; } -SharedPtr<SharedMemory> SharedMemory::CreateForApplet( +std::shared_ptr<SharedMemory> SharedMemory::CreateForApplet( KernelCore& kernel, std::shared_ptr<Kernel::PhysicalMemory> heap_block, std::size_t offset, u64 size, MemoryPermission permissions, MemoryPermission other_permissions, std::string name) { - SharedPtr<SharedMemory> shared_memory(new SharedMemory(kernel)); + std::shared_ptr<SharedMemory> shared_memory = std::make_shared<SharedMemory>(kernel); shared_memory->owner_process = nullptr; shared_memory->name = std::move(name); diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h index 01ca6dcd2..18400a5ad 100644 --- a/src/core/hle/kernel/shared_memory.h +++ b/src/core/hle/kernel/shared_memory.h @@ -33,6 +33,9 @@ enum class MemoryPermission : u32 { class SharedMemory final : public Object { public: + explicit SharedMemory(KernelCore& kernel); + ~SharedMemory() override; + /** * Creates a shared memory object. * @param kernel The kernel instance to create a shared memory instance under. @@ -46,11 +49,12 @@ public: * linear heap. * @param name Optional object name, used for debugging purposes. */ - static SharedPtr<SharedMemory> Create(KernelCore& kernel, Process* owner_process, u64 size, - MemoryPermission permissions, - MemoryPermission other_permissions, VAddr address = 0, - MemoryRegion region = MemoryRegion::BASE, - std::string name = "Unknown"); + static std::shared_ptr<SharedMemory> Create(KernelCore& kernel, Process* owner_process, + u64 size, MemoryPermission permissions, + MemoryPermission other_permissions, + VAddr address = 0, + MemoryRegion region = MemoryRegion::BASE, + std::string name = "Unknown"); /** * Creates a shared memory object from a block of memory managed by an HLE applet. @@ -63,7 +67,7 @@ public: * block. * @param name Optional object name, used for debugging purposes. */ - static SharedPtr<SharedMemory> CreateForApplet( + static std::shared_ptr<SharedMemory> CreateForApplet( KernelCore& kernel, std::shared_ptr<Kernel::PhysicalMemory> heap_block, std::size_t offset, u64 size, MemoryPermission permissions, MemoryPermission other_permissions, std::string name = "Unknown Applet"); @@ -130,9 +134,6 @@ public: const u8* GetPointer(std::size_t offset = 0) const; private: - explicit SharedMemory(KernelCore& kernel); - ~SharedMemory() override; - /// Backing memory for this shared memory block. std::shared_ptr<PhysicalMemory> backing_block; /// Offset into the backing block for this shared memory. diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index c63a9ba8b..bd25de478 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -17,6 +17,7 @@ #include "core/core.h" #include "core/core_cpu.h" #include "core/core_timing.h" +#include "core/core_timing_util.h" #include "core/hle/kernel/address_arbiter.h" #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/client_session.h" @@ -331,7 +332,9 @@ static ResultCode UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_ad /// Connect to an OS service given the port name, returns the handle to the port to out static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, VAddr port_name_address) { - if (!Memory::IsValidVirtualAddress(port_name_address)) { + auto& memory = system.Memory(); + + if (!memory.IsValidVirtualAddress(port_name_address)) { LOG_ERROR(Kernel_SVC, "Port Name Address is not a valid virtual address, port_name_address=0x{:016X}", port_name_address); @@ -340,7 +343,7 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, static constexpr std::size_t PortNameMaxLength = 11; // Read 1 char beyond the max allowed port name to detect names that are too long. - std::string port_name = Memory::ReadCString(port_name_address, PortNameMaxLength + 1); + const std::string port_name = memory.ReadCString(port_name_address, PortNameMaxLength + 1); if (port_name.size() > PortNameMaxLength) { LOG_ERROR(Kernel_SVC, "Port name is too long, expected {} but got {}", PortNameMaxLength, port_name.size()); @@ -358,7 +361,7 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, auto client_port = it->second; - SharedPtr<ClientSession> client_session; + std::shared_ptr<ClientSession> client_session; CASCADE_RESULT(client_session, client_port->Connect()); // Return the client session @@ -370,7 +373,7 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, /// Makes a blocking IPC call to an OS service. static ResultCode SendSyncRequest(Core::System& system, Handle handle) { const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - SharedPtr<ClientSession> session = handle_table.Get<ClientSession>(handle); + std::shared_ptr<ClientSession> session = handle_table.Get<ClientSession>(handle); if (!session) { LOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle); return ERR_INVALID_HANDLE; @@ -378,11 +381,12 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); - system.PrepareReschedule(); + auto thread = system.CurrentScheduler().GetCurrentThread(); + thread->InvalidateWakeupCallback(); + thread->SetStatus(ThreadStatus::WaitIPC); + system.PrepareReschedule(thread->GetProcessorID()); - // TODO(Subv): svcSendSyncRequest should put the caller thread to sleep while the server - // responds and cause a reschedule. - return session->SendSyncRequest(system.CurrentScheduler().GetCurrentThread()); + return session->SendSyncRequest(SharedFrom(thread), system.Memory()); } /// Get the ID for the specified thread. @@ -390,7 +394,7 @@ static ResultCode GetThreadId(Core::System& system, u64* thread_id, Handle threa LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); + const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", thread_handle); return ERR_INVALID_HANDLE; @@ -405,13 +409,13 @@ static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle han LOG_DEBUG(Kernel_SVC, "called handle=0x{:08X}", handle); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const SharedPtr<Process> process = handle_table.Get<Process>(handle); + const std::shared_ptr<Process> process = handle_table.Get<Process>(handle); if (process) { *process_id = process->GetProcessID(); return RESULT_SUCCESS; } - const SharedPtr<Thread> thread = handle_table.Get<Thread>(handle); + const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(handle); if (thread) { const Process* const owner_process = thread->GetOwnerProcess(); if (!owner_process) { @@ -430,8 +434,8 @@ static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle han } /// Default thread wakeup callback for WaitSynchronization -static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thread> thread, - SharedPtr<WaitObject> object, std::size_t index) { +static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread, + std::shared_ptr<WaitObject> object, std::size_t index) { ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch); if (reason == ThreadWakeupReason::Timeout) { @@ -451,7 +455,8 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}", handles_address, handle_count, nano_seconds); - if (!Memory::IsValidVirtualAddress(handles_address)) { + auto& memory = system.Memory(); + if (!memory.IsValidVirtualAddress(handles_address)) { LOG_ERROR(Kernel_SVC, "Handle address is not a valid virtual address, handle_address=0x{:016X}", handles_address); @@ -473,7 +478,7 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 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<WaitObject>(handle); if (object == nullptr) { @@ -505,8 +510,13 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr return RESULT_TIMEOUT; } + if (thread->IsSyncCancelled()) { + thread->SetSyncCancelled(false); + return ERR_SYNCHRONIZATION_CANCELED; + } + for (auto& object : objects) { - object->AddWaitingThread(thread); + object->AddWaitingThread(SharedFrom(thread)); } thread->SetWaitObjects(std::move(objects)); @@ -526,7 +536,7 @@ static ResultCode CancelSynchronization(Core::System& system, Handle thread_hand LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); + std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", thread_handle); @@ -610,13 +620,15 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) { return; } + auto& memory = system.Memory(); + // This typically is an error code so we're going to assume this is the case if (sz == sizeof(u32)) { - LOG_CRITICAL(Debug_Emulated, "debug_buffer_err_code={:X}", Memory::Read32(addr)); + LOG_CRITICAL(Debug_Emulated, "debug_buffer_err_code={:X}", memory.Read32(addr)); } else { // We don't know what's in here so we'll hexdump it debug_buffer.resize(sz); - Memory::ReadBlock(addr, debug_buffer.data(), sz); + memory.ReadBlock(addr, debug_buffer.data(), sz); std::string hexdump; for (std::size_t i = 0; i < debug_buffer.size(); i++) { hexdump += fmt::format("{:02X} ", debug_buffer[i]); @@ -706,7 +718,7 @@ static void OutputDebugString([[maybe_unused]] Core::System& system, VAddr addre } std::string str(len, '\0'); - Memory::ReadBlock(address, str.data(), str.size()); + system.Memory().ReadBlock(address, str.data(), str.size()); LOG_DEBUG(Debug_Emulated, "{}", str); } @@ -935,7 +947,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha const auto& core_timing = system.CoreTiming(); const auto& scheduler = system.CurrentScheduler(); const auto* const current_thread = scheduler.GetCurrentThread(); - const bool same_thread = current_thread == thread; + const bool same_thread = current_thread == thread.get(); const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTicks(); u64 out_ticks = 0; @@ -1045,7 +1057,7 @@ static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 act } const auto* current_process = system.Kernel().CurrentProcess(); - const SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); + const std::shared_ptr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); return ERR_INVALID_HANDLE; @@ -1061,7 +1073,7 @@ static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 act return ERR_INVALID_HANDLE; } - if (thread == system.CurrentScheduler().GetCurrentThread()) { + if (thread.get() == system.CurrentScheduler().GetCurrentThread()) { LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread"); return ERR_BUSY; } @@ -1077,7 +1089,7 @@ static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, H LOG_DEBUG(Kernel_SVC, "called, context=0x{:08X}, thread=0x{:X}", thread_context, handle); const auto* current_process = system.Kernel().CurrentProcess(); - const SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); + const std::shared_ptr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); return ERR_INVALID_HANDLE; @@ -1093,7 +1105,7 @@ static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, H return ERR_INVALID_HANDLE; } - if (thread == system.CurrentScheduler().GetCurrentThread()) { + if (thread.get() == system.CurrentScheduler().GetCurrentThread()) { LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread"); return ERR_BUSY; } @@ -1109,7 +1121,7 @@ static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, H std::fill(ctx.vector_registers.begin() + 16, ctx.vector_registers.end(), u128{}); } - Memory::WriteBlock(thread_context, &ctx, sizeof(ctx)); + system.Memory().WriteBlock(thread_context, &ctx, sizeof(ctx)); return RESULT_SUCCESS; } @@ -1118,7 +1130,7 @@ static ResultCode GetThreadPriority(Core::System& system, u32* priority, Handle LOG_TRACE(Kernel_SVC, "called"); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const SharedPtr<Thread> thread = handle_table.Get<Thread>(handle); + const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(handle); if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); return ERR_INVALID_HANDLE; @@ -1142,7 +1154,7 @@ static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 pri const auto* const current_process = system.Kernel().CurrentProcess(); - SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); + std::shared_ptr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); return ERR_INVALID_HANDLE; @@ -1262,27 +1274,28 @@ static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_add VAddr address) { LOG_TRACE(Kernel_SVC, "called process=0x{:08X} address={:X}", process_handle, address); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - SharedPtr<Process> process = handle_table.Get<Process>(process_handle); + std::shared_ptr<Process> process = handle_table.Get<Process>(process_handle); if (!process) { LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}", process_handle); return ERR_INVALID_HANDLE; } + auto& memory = system.Memory(); const auto& vm_manager = process->VMManager(); const MemoryInfo memory_info = vm_manager.QueryMemory(address); - Memory::Write64(memory_info_address, memory_info.base_address); - Memory::Write64(memory_info_address + 8, memory_info.size); - Memory::Write32(memory_info_address + 16, memory_info.state); - Memory::Write32(memory_info_address + 20, memory_info.attributes); - Memory::Write32(memory_info_address + 24, memory_info.permission); - Memory::Write32(memory_info_address + 32, memory_info.ipc_ref_count); - Memory::Write32(memory_info_address + 28, memory_info.device_ref_count); - Memory::Write32(memory_info_address + 36, 0); + memory.Write64(memory_info_address, memory_info.base_address); + memory.Write64(memory_info_address + 8, memory_info.size); + memory.Write32(memory_info_address + 16, memory_info.state); + memory.Write32(memory_info_address + 20, memory_info.attributes); + memory.Write32(memory_info_address + 24, memory_info.permission); + memory.Write32(memory_info_address + 32, memory_info.ipc_ref_count); + memory.Write32(memory_info_address + 28, memory_info.device_ref_count); + memory.Write32(memory_info_address + 36, 0); // Page info appears to be currently unused by the kernel and is always set to zero. - Memory::Write32(page_info_address, 0); + memory.Write32(page_info_address, 0); return RESULT_SUCCESS; } @@ -1490,7 +1503,7 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e } auto& kernel = system.Kernel(); - CASCADE_RESULT(SharedPtr<Thread> thread, + CASCADE_RESULT(std::shared_ptr<Thread> thread, Thread::Create(kernel, "", entry_point, priority, arg, processor_id, stack_top, *current_process)); @@ -1516,7 +1529,7 @@ static ResultCode StartThread(Core::System& system, Handle thread_handle) { LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); + const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", thread_handle); @@ -1540,7 +1553,7 @@ static void ExitThread(Core::System& system) { auto* const current_thread = system.CurrentScheduler().GetCurrentThread(); current_thread->Stop(); - system.GlobalScheduler().RemoveThread(current_thread); + system.GlobalScheduler().RemoveThread(SharedFrom(current_thread)); system.PrepareReschedule(); } @@ -1612,7 +1625,7 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add auto* const current_process = system.Kernel().CurrentProcess(); const auto& handle_table = current_process->GetHandleTable(); - SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); + std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); ASSERT(thread); const auto release_result = current_process->GetMutex().Release(mutex_addr); @@ -1620,12 +1633,13 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add return release_result; } - SharedPtr<Thread> current_thread = system.CurrentScheduler().GetCurrentThread(); + Thread* current_thread = system.CurrentScheduler().GetCurrentThread(); current_thread->SetCondVarWaitAddress(condition_variable_addr); current_thread->SetMutexWaitAddress(mutex_addr); current_thread->SetWaitHandle(thread_handle); current_thread->SetStatus(ThreadStatus::WaitCondVar); current_thread->InvalidateWakeupCallback(); + current_process->InsertConditionVariableThread(SharedFrom(current_thread)); current_thread->WakeAfterDelay(nano_seconds); @@ -1644,42 +1658,28 @@ static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_var ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4)); // Retrieve a list of all threads that are waiting for this condition variable. - std::vector<SharedPtr<Thread>> waiting_threads; - const auto& scheduler = system.GlobalScheduler(); - const auto& thread_list = scheduler.GetThreadList(); - - for (const auto& thread : thread_list) { - if (thread->GetCondVarWaitAddress() == condition_variable_addr) { - waiting_threads.push_back(thread); - } - } - - // Sort them by priority, such that the highest priority ones come first. - std::sort(waiting_threads.begin(), waiting_threads.end(), - [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) { - return lhs->GetPriority() < rhs->GetPriority(); - }); + auto* const current_process = system.Kernel().CurrentProcess(); + std::vector<std::shared_ptr<Thread>> waiting_threads = + current_process->GetConditionVariableThreads(condition_variable_addr); - // Only process up to 'target' threads, unless 'target' is -1, in which case process + // Only process up to 'target' threads, unless 'target' is less equal 0, in which case process // them all. std::size_t last = waiting_threads.size(); - if (target != -1) + if (target > 0) last = std::min(waiting_threads.size(), static_cast<std::size_t>(target)); - // If there are no threads waiting on this condition variable, just exit - if (last == 0) - return RESULT_SUCCESS; - for (std::size_t index = 0; index < last; ++index) { auto& thread = waiting_threads[index]; ASSERT(thread->GetCondVarWaitAddress() == condition_variable_addr); // liberate Cond Var Thread. + current_process->RemoveConditionVariableThread(thread); thread->SetCondVarWaitAddress(0); const std::size_t current_core = system.CurrentCoreIndex(); auto& monitor = system.Monitor(); + auto& memory = system.Memory(); // Atomically read the value of the mutex. u32 mutex_val = 0; @@ -1689,7 +1689,7 @@ static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_var monitor.SetExclusive(current_core, mutex_address); // If the mutex is not yet acquired, acquire it. - mutex_val = Memory::Read32(mutex_address); + mutex_val = memory.Read32(mutex_address); if (mutex_val != 0) { update_val = mutex_val | Mutex::MutexHasWaitersFlag; @@ -1786,7 +1786,9 @@ static u64 GetSystemTick(Core::System& system) { LOG_TRACE(Kernel_SVC, "called"); auto& core_timing = system.CoreTiming(); - const u64 result{core_timing.GetTicks()}; + + // Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick) + const u64 result{Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks())}; // Advance time to defeat dumb games that busy-wait for the frame to end. core_timing.AddTicks(400); @@ -1975,7 +1977,7 @@ static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); + const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", thread_handle); @@ -2034,7 +2036,7 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, } const auto& handle_table = current_process->GetHandleTable(); - const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); + const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", thread_handle); @@ -2290,12 +2292,13 @@ static ResultCode GetProcessList(Core::System& system, u32* out_num_processes, return ERR_INVALID_ADDRESS_STATE; } + auto& memory = system.Memory(); const auto& process_list = kernel.GetProcessList(); const auto num_processes = process_list.size(); const auto copy_amount = std::min(std::size_t{out_process_ids_size}, num_processes); for (std::size_t i = 0; i < copy_amount; ++i) { - Memory::Write64(out_process_ids, process_list[i]->GetProcessID()); + memory.Write64(out_process_ids, process_list[i]->GetProcessID()); out_process_ids += sizeof(u64); } @@ -2329,13 +2332,14 @@ static ResultCode GetThreadList(Core::System& system, u32* out_num_threads, VAdd return ERR_INVALID_ADDRESS_STATE; } + auto& memory = system.Memory(); const auto& thread_list = current_process->GetThreadList(); const auto num_threads = thread_list.size(); const auto copy_amount = std::min(std::size_t{out_thread_ids_size}, num_threads); auto list_iter = thread_list.cbegin(); for (std::size_t i = 0; i < copy_amount; ++i, ++list_iter) { - Memory::Write64(out_thread_ids, (*list_iter)->GetThreadID()); + memory.Write64(out_thread_ids, (*list_iter)->GetThreadID()); out_thread_ids += sizeof(u64); } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index ee7531f2d..e84e5ce0d 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -50,7 +50,7 @@ void Thread::Stop() { // Clean up any dangling references in objects that this thread was waiting for for (auto& wait_object : wait_objects) { - wait_object->RemoveWaitingThread(this); + wait_object->RemoveWaitingThread(SharedFrom(this)); } wait_objects.clear(); @@ -120,8 +120,11 @@ void Thread::ResumeFromWait() { } void Thread::CancelWait() { - ASSERT(GetStatus() == ThreadStatus::WaitSynch); - ClearWaitObjects(); + if (GetSchedulingStatus() != ThreadSchedStatus::Paused) { + is_sync_cancelled = true; + return; + } + is_sync_cancelled = false; SetWaitSynchronizationResult(ERR_SYNCHRONIZATION_CANCELED); ResumeFromWait(); } @@ -144,9 +147,10 @@ static void ResetThreadContext(Core::ARM_Interface::ThreadContext& context, VAdd context.fpcr = 0x03C00000; } -ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name, VAddr entry_point, - u32 priority, u64 arg, s32 processor_id, - VAddr stack_top, Process& owner_process) { +ResultVal<std::shared_ptr<Thread>> Thread::Create(KernelCore& kernel, std::string name, + VAddr entry_point, u32 priority, u64 arg, + s32 processor_id, VAddr stack_top, + Process& owner_process) { // Check if priority is in ranged. Lowest priority -> highest priority id. if (priority > THREADPRIO_LOWEST) { LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority); @@ -158,14 +162,14 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name return ERR_INVALID_PROCESSOR_ID; } - if (!Memory::IsValidVirtualAddress(owner_process, entry_point)) { + auto& system = Core::System::GetInstance(); + if (!system.Memory().IsValidVirtualAddress(owner_process, entry_point)) { LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point); // TODO (bunnei): Find the correct error code to use here return RESULT_UNKNOWN; } - auto& system = Core::System::GetInstance(); - SharedPtr<Thread> thread(new Thread(kernel)); + std::shared_ptr<Thread> thread = std::make_shared<Thread>(kernel); thread->thread_id = kernel.CreateNewThreadID(); thread->status = ThreadStatus::Dormant; @@ -194,7 +198,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name // to initialize the context ResetThreadContext(thread->context, stack_top, entry_point, arg); - return MakeResult<SharedPtr<Thread>>(std::move(thread)); + return MakeResult<std::shared_ptr<Thread>>(std::move(thread)); } void Thread::SetPriority(u32 priority) { @@ -212,7 +216,7 @@ void Thread::SetWaitSynchronizationOutput(s32 output) { context.cpu_registers[1] = output; } -s32 Thread::GetWaitObjectIndex(const WaitObject* object) const { +s32 Thread::GetWaitObjectIndex(std::shared_ptr<WaitObject> 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); @@ -252,8 +256,8 @@ void Thread::SetStatus(ThreadStatus new_status) { status = new_status; } -void Thread::AddMutexWaiter(SharedPtr<Thread> thread) { - if (thread->lock_owner == this) { +void Thread::AddMutexWaiter(std::shared_ptr<Thread> thread) { + if (thread->lock_owner.get() == this) { // If the thread is already waiting for this thread to release the mutex, ensure that the // waiters list is consistent and return without doing anything. const auto iter = std::find(wait_mutex_threads.begin(), wait_mutex_threads.end(), thread); @@ -273,13 +277,13 @@ void Thread::AddMutexWaiter(SharedPtr<Thread> thread) { wait_mutex_threads.begin(), wait_mutex_threads.end(), [&thread](const auto& entry) { return entry->GetPriority() > thread->GetPriority(); }); wait_mutex_threads.insert(insertion_point, thread); - thread->lock_owner = this; + thread->lock_owner = SharedFrom(this); UpdatePriority(); } -void Thread::RemoveMutexWaiter(SharedPtr<Thread> thread) { - ASSERT(thread->lock_owner == this); +void Thread::RemoveMutexWaiter(std::shared_ptr<Thread> thread) { + ASSERT(thread->lock_owner.get() == this); // Ensure that the thread is in the list of mutex waiters const auto iter = std::find(wait_mutex_threads.begin(), wait_mutex_threads.end(), thread); @@ -306,16 +310,24 @@ void Thread::UpdatePriority() { return; } + if (GetStatus() == ThreadStatus::WaitCondVar) { + owner_process->RemoveConditionVariableThread(SharedFrom(this)); + } + SetCurrentPriority(new_priority); + if (GetStatus() == ThreadStatus::WaitCondVar) { + owner_process->InsertConditionVariableThread(SharedFrom(this)); + } + if (!lock_owner) { return; } // Ensure that the thread is within the correct location in the waiting list. auto old_owner = lock_owner; - lock_owner->RemoveMutexWaiter(this); - old_owner->AddMutexWaiter(this); + lock_owner->RemoveMutexWaiter(SharedFrom(this)); + old_owner->AddMutexWaiter(SharedFrom(this)); // Recursively update the priority of the thread that depends on the priority of this one. lock_owner->UpdatePriority(); @@ -328,11 +340,11 @@ void Thread::ChangeCore(u32 core, u64 mask) { bool Thread::AllWaitObjectsReady() const { return std::none_of( wait_objects.begin(), wait_objects.end(), - [this](const SharedPtr<WaitObject>& object) { return object->ShouldWait(this); }); + [this](const std::shared_ptr<WaitObject>& object) { return object->ShouldWait(this); }); } -bool Thread::InvokeWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thread> thread, - SharedPtr<WaitObject> object, std::size_t index) { +bool Thread::InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread, + std::shared_ptr<WaitObject> object, std::size_t index) { ASSERT(wakeup_callback); return wakeup_callback(reason, std::move(thread), std::move(object), index); } diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index c9870873d..3bcf9e137 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -97,14 +97,18 @@ enum class ThreadSchedMasks : u32 { class Thread final : public WaitObject { public: - using MutexWaitingThreads = std::vector<SharedPtr<Thread>>; + explicit Thread(KernelCore& kernel); + ~Thread() override; + + using MutexWaitingThreads = std::vector<std::shared_ptr<Thread>>; using ThreadContext = Core::ARM_Interface::ThreadContext; - using ThreadWaitObjects = std::vector<SharedPtr<WaitObject>>; + using ThreadWaitObjects = std::vector<std::shared_ptr<WaitObject>>; - using WakeupCallback = std::function<bool(ThreadWakeupReason reason, SharedPtr<Thread> thread, - SharedPtr<WaitObject> object, std::size_t index)>; + using WakeupCallback = + std::function<bool(ThreadWakeupReason reason, std::shared_ptr<Thread> thread, + std::shared_ptr<WaitObject> object, std::size_t index)>; /** * Creates and returns a new thread. The new thread is immediately scheduled @@ -118,10 +122,10 @@ public: * @param owner_process The parent process for the thread * @return A shared pointer to the newly created thread */ - static ResultVal<SharedPtr<Thread>> Create(KernelCore& kernel, std::string name, - VAddr entry_point, u32 priority, u64 arg, - s32 processor_id, VAddr stack_top, - Process& owner_process); + static ResultVal<std::shared_ptr<Thread>> Create(KernelCore& kernel, std::string name, + VAddr entry_point, u32 priority, u64 arg, + s32 processor_id, VAddr stack_top, + Process& owner_process); std::string GetName() const override { return name; @@ -166,10 +170,10 @@ public: void SetPriority(u32 priority); /// Adds a thread to the list of threads that are waiting for a lock held by this thread. - void AddMutexWaiter(SharedPtr<Thread> thread); + void AddMutexWaiter(std::shared_ptr<Thread> thread); /// Removes a thread from the list of threads that are waiting for a lock held by this thread. - void RemoveMutexWaiter(SharedPtr<Thread> thread); + void RemoveMutexWaiter(std::shared_ptr<Thread> thread); /// Recalculates the current priority taking into account priority inheritance. void UpdatePriority(); @@ -229,7 +233,7 @@ public: * * @param object Object to query the index of. */ - s32 GetWaitObjectIndex(const WaitObject* object) const; + s32 GetWaitObjectIndex(std::shared_ptr<WaitObject> object) const; /** * Stops a thread, invalidating it from further use @@ -320,7 +324,7 @@ public: void ClearWaitObjects() { for (const auto& waiting_object : wait_objects) { - waiting_object->RemoveWaitingThread(this); + waiting_object->RemoveWaitingThread(SharedFrom(this)); } wait_objects.clear(); } @@ -336,7 +340,7 @@ public: return lock_owner.get(); } - void SetLockOwner(SharedPtr<Thread> owner) { + void SetLockOwner(std::shared_ptr<Thread> owner) { lock_owner = std::move(owner); } @@ -390,8 +394,8 @@ public: * @pre A valid wakeup callback has been set. Violating this precondition * will cause an assertion to trigger. */ - bool InvokeWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thread> thread, - SharedPtr<WaitObject> object, std::size_t index); + bool InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread, + std::shared_ptr<WaitObject> object, std::size_t index); u32 GetIdealCore() const { return ideal_core; @@ -440,10 +444,15 @@ public: is_running = value; } -private: - explicit Thread(KernelCore& kernel); - ~Thread() override; + bool IsSyncCancelled() const { + return is_sync_cancelled; + } + void SetSyncCancelled(bool value) { + is_sync_cancelled = value; + } + +private: void SetSchedulingStatus(ThreadSchedStatus new_status); void SetCurrentPriority(u32 new_priority); ResultCode SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask); @@ -491,7 +500,7 @@ private: MutexWaitingThreads wait_mutex_threads; /// Thread that owns the lock that this thread is waiting for. - SharedPtr<Thread> lock_owner; + std::shared_ptr<Thread> lock_owner; /// If waiting on a ConditionVariable, this is the ConditionVariable address VAddr condvar_wait_address = 0; @@ -524,6 +533,7 @@ private: u32 scheduling_state = 0; bool is_running = false; + bool is_sync_cancelled = false; std::string name; }; diff --git a/src/core/hle/kernel/transfer_memory.cpp b/src/core/hle/kernel/transfer_memory.cpp index 1113c815e..f0e73f57b 100644 --- a/src/core/hle/kernel/transfer_memory.cpp +++ b/src/core/hle/kernel/transfer_memory.cpp @@ -14,9 +14,9 @@ namespace Kernel { TransferMemory::TransferMemory(KernelCore& kernel) : Object{kernel} {} TransferMemory::~TransferMemory() = default; -SharedPtr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr base_address, u64 size, - MemoryPermission permissions) { - SharedPtr<TransferMemory> transfer_memory{new TransferMemory(kernel)}; +std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr base_address, + u64 size, MemoryPermission permissions) { + std::shared_ptr<TransferMemory> transfer_memory{std::make_shared<TransferMemory>(kernel)}; transfer_memory->base_address = base_address; transfer_memory->memory_size = size; diff --git a/src/core/hle/kernel/transfer_memory.h b/src/core/hle/kernel/transfer_memory.h index 6be9dc094..556e6c62b 100644 --- a/src/core/hle/kernel/transfer_memory.h +++ b/src/core/hle/kernel/transfer_memory.h @@ -27,10 +27,13 @@ enum class MemoryPermission : u32; /// class TransferMemory final : public Object { public: + explicit TransferMemory(KernelCore& kernel); + ~TransferMemory() override; + static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory; - static SharedPtr<TransferMemory> Create(KernelCore& kernel, VAddr base_address, u64 size, - MemoryPermission permissions); + static std::shared_ptr<TransferMemory> Create(KernelCore& kernel, VAddr base_address, u64 size, + MemoryPermission permissions); TransferMemory(const TransferMemory&) = delete; TransferMemory& operator=(const TransferMemory&) = delete; @@ -79,9 +82,6 @@ public: ResultCode UnmapMemory(VAddr address, u64 size); private: - explicit TransferMemory(KernelCore& kernel); - ~TransferMemory() override; - /// Memory block backing this instance. std::shared_ptr<PhysicalMemory> backing_block; diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index e6eee09d7..a9a20ef76 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp @@ -16,7 +16,6 @@ #include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/vm_manager.h" #include "core/memory.h" -#include "core/memory_setup.h" namespace Kernel { namespace { @@ -786,19 +785,21 @@ void VMManager::MergeAdjacentVMA(VirtualMemoryArea& left, const VirtualMemoryAre } void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) { + auto& memory = system.Memory(); + switch (vma.type) { case VMAType::Free: - Memory::UnmapRegion(page_table, vma.base, vma.size); + memory.UnmapRegion(page_table, vma.base, vma.size); break; case VMAType::AllocatedMemoryBlock: - Memory::MapMemoryRegion(page_table, vma.base, vma.size, - vma.backing_block->data() + vma.offset); + memory.MapMemoryRegion(page_table, vma.base, vma.size, + vma.backing_block->data() + vma.offset); break; case VMAType::BackingMemory: - Memory::MapMemoryRegion(page_table, vma.base, vma.size, vma.backing_memory); + memory.MapMemoryRegion(page_table, vma.base, vma.size, vma.backing_memory); break; case VMAType::MMIO: - Memory::MapIoRegion(page_table, vma.base, vma.size, vma.mmio_handler); + memory.MapIoRegion(page_table, vma.base, vma.size, vma.mmio_handler); break; } } diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp index c00cef062..745f2c4e8 100644 --- a/src/core/hle/kernel/wait_object.cpp +++ b/src/core/hle/kernel/wait_object.cpp @@ -18,13 +18,13 @@ namespace Kernel { WaitObject::WaitObject(KernelCore& kernel) : Object{kernel} {} WaitObject::~WaitObject() = default; -void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) { +void WaitObject::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 WaitObject::RemoveWaitingThread(Thread* thread) { +void WaitObject::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 @@ -33,7 +33,7 @@ void WaitObject::RemoveWaitingThread(Thread* thread) { waiting_threads.erase(itr); } -SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() const { +std::shared_ptr<Thread> WaitObject::GetHighestPriorityReadyThread() const { Thread* candidate = nullptr; u32 candidate_priority = THREADPRIO_LOWEST + 1; @@ -64,10 +64,10 @@ SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() const { } } - return candidate; + return SharedFrom(candidate); } -void WaitObject::WakeupWaitingThread(SharedPtr<Thread> thread) { +void WaitObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) { ASSERT(!ShouldWait(thread.get())); if (!thread) { @@ -83,7 +83,7 @@ void WaitObject::WakeupWaitingThread(SharedPtr<Thread> thread) { Acquire(thread.get()); } - const std::size_t index = thread->GetWaitObjectIndex(this); + const std::size_t index = thread->GetWaitObjectIndex(SharedFrom(this)); thread->ClearWaitObjects(); @@ -91,7 +91,8 @@ void WaitObject::WakeupWaitingThread(SharedPtr<Thread> thread) { bool resume = true; if (thread->HasWakeupCallback()) { - resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Signal, thread, this, index); + resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Signal, thread, SharedFrom(this), + index); } if (resume) { thread->ResumeFromWait(); @@ -105,7 +106,7 @@ void WaitObject::WakeupAllWaitingThreads() { } } -const std::vector<SharedPtr<Thread>>& WaitObject::GetWaitingThreads() const { +const std::vector<std::shared_ptr<Thread>>& WaitObject::GetWaitingThreads() const { return waiting_threads; } diff --git a/src/core/hle/kernel/wait_object.h b/src/core/hle/kernel/wait_object.h index 3271a30a7..f9d596db9 100644 --- a/src/core/hle/kernel/wait_object.h +++ b/src/core/hle/kernel/wait_object.h @@ -33,13 +33,13 @@ public: * Add a thread to wait on this object * @param thread Pointer to thread to add */ - void AddWaitingThread(SharedPtr<Thread> thread); + 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(Thread* thread); + void RemoveWaitingThread(std::shared_ptr<Thread> thread); /** * Wake up all threads waiting on this object that can be awoken, in priority order, @@ -51,24 +51,24 @@ public: * Wakes up a single thread waiting on this object. * @param thread Thread that is waiting on this object to wakeup. */ - void WakeupWaitingThread(SharedPtr<Thread> thread); + void WakeupWaitingThread(std::shared_ptr<Thread> thread); /// Obtains the highest priority thread that is ready to run from this object's waiting list. - SharedPtr<Thread> GetHighestPriorityReadyThread() const; + std::shared_ptr<Thread> GetHighestPriorityReadyThread() const; /// Get a const reference to the waiting threads list for debug use - const std::vector<SharedPtr<Thread>>& GetWaitingThreads() const; + const std::vector<std::shared_ptr<Thread>>& GetWaitingThreads() const; private: /// Threads waiting for this object to become available - std::vector<SharedPtr<Thread>> waiting_threads; + std::vector<std::shared_ptr<Thread>> waiting_threads; }; // Specialization of DynamicObjectCast for WaitObjects template <> -inline SharedPtr<WaitObject> DynamicObjectCast<WaitObject>(SharedPtr<Object> object) { +inline std::shared_ptr<WaitObject> DynamicObjectCast<WaitObject>(std::shared_ptr<Object> object) { if (object != nullptr && object->IsWaitable()) { - return boost::static_pointer_cast<WaitObject>(object); + return std::static_pointer_cast<WaitObject>(object); } return nullptr; } diff --git a/src/core/hle/kernel/writable_event.cpp b/src/core/hle/kernel/writable_event.cpp index c783a34ee..c9332e3e1 100644 --- a/src/core/hle/kernel/writable_event.cpp +++ b/src/core/hle/kernel/writable_event.cpp @@ -16,8 +16,8 @@ WritableEvent::WritableEvent(KernelCore& kernel) : Object{kernel} {} WritableEvent::~WritableEvent() = default; EventPair WritableEvent::CreateEventPair(KernelCore& kernel, std::string name) { - SharedPtr<WritableEvent> writable_event(new WritableEvent(kernel)); - SharedPtr<ReadableEvent> readable_event(new ReadableEvent(kernel)); + std::shared_ptr<WritableEvent> writable_event(new WritableEvent(kernel)); + std::shared_ptr<ReadableEvent> readable_event(new ReadableEvent(kernel)); writable_event->name = name + ":Writable"; writable_event->readable = readable_event; @@ -27,7 +27,7 @@ EventPair WritableEvent::CreateEventPair(KernelCore& kernel, std::string name) { return {std::move(readable_event), std::move(writable_event)}; } -SharedPtr<ReadableEvent> WritableEvent::GetReadableEvent() const { +std::shared_ptr<ReadableEvent> WritableEvent::GetReadableEvent() const { return readable; } diff --git a/src/core/hle/kernel/writable_event.h b/src/core/hle/kernel/writable_event.h index f46cf1dd8..afe97f3a9 100644 --- a/src/core/hle/kernel/writable_event.h +++ b/src/core/hle/kernel/writable_event.h @@ -13,8 +13,8 @@ class ReadableEvent; class WritableEvent; struct EventPair { - SharedPtr<ReadableEvent> readable; - SharedPtr<WritableEvent> writable; + std::shared_ptr<ReadableEvent> readable; + std::shared_ptr<WritableEvent> writable; }; class WritableEvent final : public Object { @@ -40,7 +40,7 @@ public: return HANDLE_TYPE; } - SharedPtr<ReadableEvent> GetReadableEvent() const; + std::shared_ptr<ReadableEvent> GetReadableEvent() const; void Signal(); void Clear(); @@ -49,7 +49,7 @@ public: private: explicit WritableEvent(KernelCore& kernel); - SharedPtr<ReadableEvent> readable; + std::shared_ptr<ReadableEvent> readable; std::string name; ///< Name of event (optional) }; |