diff --git a/libraries/libmesosphere/include/mesosphere.hpp b/libraries/libmesosphere/include/mesosphere.hpp index ee386030a..fd0a2d345 100644 --- a/libraries/libmesosphere/include/mesosphere.hpp +++ b/libraries/libmesosphere/include/mesosphere.hpp @@ -77,7 +77,6 @@ #include #include #include -#include /* More Miscellaneous objects. */ #include diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_synchronization.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_synchronization.hpp deleted file mode 100644 index 0ad13042f..000000000 --- a/libraries/libmesosphere/include/mesosphere/kern_k_synchronization.hpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2018-2020 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#pragma once -#include -#include -#include -/* - * Copyright (c) 2018-2020 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#pragma once -#include -#include -#include - -namespace ams::kern { - - class KSynchronization { - private: - friend class KSynchronizationObject; - public: - constexpr KSynchronization() { /* ... */ } - - Result Wait(s32 *out_index, KSynchronizationObject **objects, const s32 num_objects, s64 timeout); - private: - void OnAvailable(KSynchronizationObject *object); - void OnAbort(KSynchronizationObject *object, Result abort_reason); - }; - -} diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_synchronization_object.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_synchronization_object.hpp index 31532f9f4..953c2fa4f 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_synchronization_object.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_synchronization_object.hpp @@ -25,28 +25,28 @@ namespace ams::kern { class KSynchronizationObject : public KAutoObjectWithList { MESOSPHERE_AUTOOBJECT_TRAITS(KSynchronizationObject, KAutoObject); public: - using ThreadList = KLinkedList; - using iterator = ThreadList::iterator; + struct ThreadListNode { + ThreadListNode *next; + KThread *thread; + }; private: - ThreadList thread_list; + ThreadListNode *thread_list_root; protected: - constexpr ALWAYS_INLINE explicit KSynchronizationObject() : KAutoObjectWithList(), thread_list() { MESOSPHERE_ASSERT_THIS(); } + constexpr ALWAYS_INLINE explicit KSynchronizationObject() : KAutoObjectWithList(), thread_list_root() { MESOSPHERE_ASSERT_THIS(); } virtual ~KSynchronizationObject() { MESOSPHERE_ASSERT_THIS(); } virtual void OnFinalizeSynchronizationObject() { MESOSPHERE_ASSERT_THIS(); } - void NotifyAvailable(); - void NotifyAbort(Result abort_reason); + void NotifyAvailable(Result result); + void NotifyAvailable() { + return this->NotifyAvailable(ResultSuccess()); + } + public: + static Result Wait(s32 *out_index, KSynchronizationObject **objects, const s32 num_objects, s64 timeout); public: virtual void Finalize() override; virtual bool IsSignaled() const = 0; virtual void DebugWaiters(); - - iterator RegisterWaitingThread(KThread *thread); - iterator UnregisterWaitingThread(iterator it); - - iterator begin(); - iterator end(); }; } diff --git a/libraries/libmesosphere/include/mesosphere/kern_kernel.hpp b/libraries/libmesosphere/include/mesosphere/kern_kernel.hpp index 6e057feb4..3d7fdffe0 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_kernel.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_kernel.hpp @@ -37,7 +37,6 @@ namespace ams::kern { class KPageTableManager; class KMemoryBlockSlabManager; class KBlockInfoManager; - class KSynchronization; class KUnsafeMemory; #if defined(ATMOSPHERE_ARCH_ARM64) @@ -73,7 +72,6 @@ namespace ams::kern { static KMemoryBlockSlabManager s_sys_memory_block_manager; static KBlockInfoManager s_block_info_manager; static KSupervisorPageTable s_supervisor_page_table; - static KSynchronization s_synchronization; static KUnsafeMemory s_unsafe_memory; static KWorkerTaskManager s_worker_task_managers[KWorkerTaskManager::WorkerType_Count]; static KInterruptManager s_interrupt_manager; @@ -144,10 +142,6 @@ namespace ams::kern { return s_supervisor_page_table; } - static ALWAYS_INLINE KSynchronization &GetSynchronization() { - return s_synchronization; - } - static ALWAYS_INLINE KUnsafeMemory &GetUnsafeMemory() { return s_unsafe_memory; } diff --git a/libraries/libmesosphere/source/kern_k_server_session.cpp b/libraries/libmesosphere/source/kern_k_server_session.cpp index 4e6d1a8a5..c48844313 100644 --- a/libraries/libmesosphere/source/kern_k_server_session.cpp +++ b/libraries/libmesosphere/source/kern_k_server_session.cpp @@ -1359,7 +1359,7 @@ namespace ams::kern { } /* Notify. */ - this->NotifyAbort(svc::ResultSessionClosed()); + this->NotifyAvailable(svc::ResultSessionClosed()); } } diff --git a/libraries/libmesosphere/source/kern_k_synchronization.cpp b/libraries/libmesosphere/source/kern_k_synchronization.cpp deleted file mode 100644 index 8f611269d..000000000 --- a/libraries/libmesosphere/source/kern_k_synchronization.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 2018-2020 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#include - -namespace ams::kern { - - Result KSynchronization::Wait(s32 *out_index, KSynchronizationObject **objects, const s32 num_objects, s64 timeout) { - MESOSPHERE_ASSERT_THIS(); - - /* Allocate space on stack for thread iterators. */ - KSynchronizationObject::iterator *thread_iters = static_cast(__builtin_alloca(sizeof(KSynchronizationObject::iterator) * num_objects)); - - /* Prepare for wait. */ - KThread *thread = GetCurrentThreadPointer(); - s32 sync_index = -1; - KHardwareTimer *timer; - - { - /* Setup the scheduling lock and sleep. */ - KScopedSchedulerLockAndSleep slp(std::addressof(timer), thread, timeout); - - /* Check if any of the objects are already signaled. */ - for (auto i = 0; i < num_objects; ++i) { - AMS_ASSERT(objects[i] != nullptr); - - if (objects[i]->IsSignaled()) { - *out_index = i; - slp.CancelSleep(); - return ResultSuccess(); - } - } - - /* Check if the timeout is zero. */ - if (timeout == 0) { - slp.CancelSleep(); - return svc::ResultTimedOut(); - } - - /* Check if the thread should terminate. */ - if (thread->IsTerminationRequested()) { - slp.CancelSleep(); - return svc::ResultTerminationRequested(); - } - - /* Check if waiting was canceled. */ - if (thread->IsWaitCancelled()) { - slp.CancelSleep(); - thread->ClearWaitCancelled(); - return svc::ResultCancelled(); - } - - /* Add the waiters. */ - for (auto i = 0; i < num_objects; ++i) { - thread_iters[i] = objects[i]->RegisterWaitingThread(thread); - } - - /* Mark the thread as waiting. */ - thread->SetCancellable(); - thread->SetSyncedObject(nullptr, svc::ResultTimedOut()); - thread->SetState(KThread::ThreadState_Waiting); - } - - /* The lock/sleep is done, so we should be able to get our result. */ - - /* Thread is no longer cancellable. */ - thread->ClearCancellable(); - - /* Cancel the timer as needed. */ - if (timer != nullptr) { - timer->CancelTask(thread); - } - - /* Get the wait result. */ - Result wait_result; - { - KScopedSchedulerLock lk; - KSynchronizationObject *synced_obj; - wait_result = thread->GetWaitResult(std::addressof(synced_obj)); - - for (auto i = 0; i < num_objects; ++i) { - objects[i]->UnregisterWaitingThread(thread_iters[i]); - if (objects[i] == synced_obj) { - sync_index = i; - } - } - } - - /* Set output. */ - *out_index = sync_index; - return wait_result; - } - - void KSynchronization::OnAvailable(KSynchronizationObject *object) { - MESOSPHERE_ASSERT_THIS(); - - KScopedSchedulerLock sl; - - /* If we're not signaled, we've nothing to notify. */ - if (!object->IsSignaled()) { - return; - } - - /* Iterate over each thread. */ - for (auto &thread : *object) { - if (thread.GetState() == KThread::ThreadState_Waiting) { - thread.SetSyncedObject(object, ResultSuccess()); - thread.SetState(KThread::ThreadState_Runnable); - } - } - } - - void KSynchronization::OnAbort(KSynchronizationObject *object, Result abort_reason) { - MESOSPHERE_ASSERT_THIS(); - - KScopedSchedulerLock sl; - - /* Iterate over each thread. */ - for (auto &thread : *object) { - if (thread.GetState() == KThread::ThreadState_Waiting) { - thread.SetSyncedObject(object, abort_reason); - thread.SetState(KThread::ThreadState_Runnable); - } - } - } - -} diff --git a/libraries/libmesosphere/source/kern_k_synchronization_object.cpp b/libraries/libmesosphere/source/kern_k_synchronization_object.cpp index ce94f95eb..bd5938b8e 100644 --- a/libraries/libmesosphere/source/kern_k_synchronization_object.cpp +++ b/libraries/libmesosphere/source/kern_k_synchronization_object.cpp @@ -17,18 +17,6 @@ namespace ams::kern { - void KSynchronizationObject::NotifyAvailable() { - MESOSPHERE_ASSERT_THIS(); - - Kernel::GetSynchronization().OnAvailable(this); - } - - void KSynchronizationObject::NotifyAbort(Result abort_reason) { - MESOSPHERE_ASSERT_THIS(); - - Kernel::GetSynchronization().OnAbort(this, abort_reason); - } - void KSynchronizationObject::Finalize() { MESOSPHERE_ASSERT_THIS(); @@ -37,9 +25,8 @@ namespace ams::kern { { KScopedSchedulerLock sl; - auto end = this->end(); - for (auto it = this->begin(); it != end; ++it) { - KThread *thread = std::addressof(*it); + for (auto *cur_node = this->thread_list_root; cur_node != nullptr; cur_node = cur_node->next) { + KThread *thread = cur_node->thread; MESOSPHERE_LOG("KSynchronizationObject::Finalize(%p) with %p (id=%ld) waiting.\n", this, thread, thread->GetId()); } } @@ -49,6 +36,118 @@ namespace ams::kern { KAutoObject::Finalize(); } + Result KSynchronizationObject::Wait(s32 *out_index, KSynchronizationObject **objects, const s32 num_objects, s64 timeout) { + /* Allocate space on stack for thread nodes. */ + ThreadListNode *thread_nodes = static_cast(__builtin_alloca(sizeof(ThreadListNode) * num_objects)); + + /* Prepare for wait. */ + KThread *thread = GetCurrentThreadPointer(); + KHardwareTimer *timer; + + { + /* Setup the scheduling lock and sleep. */ + KScopedSchedulerLockAndSleep slp(std::addressof(timer), thread, timeout); + + /* Check if any of the objects are already signaled. */ + for (auto i = 0; i < num_objects; ++i) { + AMS_ASSERT(objects[i] != nullptr); + + if (objects[i]->IsSignaled()) { + *out_index = i; + slp.CancelSleep(); + return ResultSuccess(); + } + } + + /* Check if the timeout is zero. */ + if (timeout == 0) { + slp.CancelSleep(); + return svc::ResultTimedOut(); + } + + /* Check if the thread should terminate. */ + if (thread->IsTerminationRequested()) { + slp.CancelSleep(); + return svc::ResultTerminationRequested(); + } + + /* Check if waiting was canceled. */ + if (thread->IsWaitCancelled()) { + slp.CancelSleep(); + thread->ClearWaitCancelled(); + return svc::ResultCancelled(); + } + + /* Add the waiters. */ + for (auto i = 0; i < num_objects; ++i) { + thread_nodes[i].thread = thread; + thread_nodes[i].next = objects[i]->thread_list_root; + objects[i]->thread_list_root = std::addressof(thread_nodes[i]); + } + + /* Mark the thread as waiting. */ + thread->SetCancellable(); + thread->SetSyncedObject(nullptr, svc::ResultTimedOut()); + thread->SetState(KThread::ThreadState_Waiting); + } + + /* The lock/sleep is done, so we should be able to get our result. */ + + /* Thread is no longer cancellable. */ + thread->ClearCancellable(); + + /* Cancel the timer as needed. */ + if (timer != nullptr) { + timer->CancelTask(thread); + } + + /* Get the wait result. */ + Result wait_result; + s32 sync_index = -1; + { + KScopedSchedulerLock lk; + KSynchronizationObject *synced_obj; + wait_result = thread->GetWaitResult(std::addressof(synced_obj)); + + for (auto i = 0; i < num_objects; ++i) { + /* Unlink the object from the list. */ + ThreadListNode **link = std::addressof(objects[i]->thread_list_root); + while (*link != std::addressof(thread_nodes[i])) { + link = std::addressof((*link)->next); + } + *link = thread_nodes[i].next; + + if (objects[i] == synced_obj) { + sync_index = i; + } + } + } + + /* Set output. */ + *out_index = sync_index; + return wait_result; + } + + void KSynchronizationObject::NotifyAvailable(Result result) { + MESOSPHERE_ASSERT_THIS(); + + KScopedSchedulerLock sl; + + /* If we're not signaled, we've nothing to notify. */ + if (!this->IsSignaled()) { + return; + } + + /* Iterate over each thread. */ + for (auto *cur_node = this->thread_list_root; cur_node != nullptr; cur_node = cur_node->next) { + KThread *thread = cur_node->thread; + if (thread->GetState() == KThread::ThreadState_Waiting) { + thread->SetSyncedObject(this, result); + thread->SetState(KThread::ThreadState_Runnable); + } + } + } + void KSynchronizationObject::DebugWaiters() { MESOSPHERE_ASSERT_THIS(); @@ -60,9 +159,8 @@ namespace ams::kern { MESOSPHERE_RELEASE_LOG("Threads waiting on %p:\n", this); bool has_waiters = false; - auto end = this->end(); - for (auto it = this->begin(); it != end; ++it) { - KThread *thread = std::addressof(*it); + for (auto *cur_node = this->thread_list_root; cur_node != nullptr; cur_node = cur_node->next) { + KThread *thread = cur_node->thread; if (KProcess *process = thread->GetOwnerProcess(); process != nullptr) { MESOSPHERE_RELEASE_LOG(" %p tid=%ld pid=%ld (%s)\n", thread, thread->GetId(), process->GetId(), process->GetName()); @@ -81,28 +179,4 @@ namespace ams::kern { #endif } - KSynchronizationObject::iterator KSynchronizationObject::RegisterWaitingThread(KThread *thread) { - MESOSPHERE_ASSERT_THIS(); - - return this->thread_list.insert(this->thread_list.end(), *thread); - } - - KSynchronizationObject::iterator KSynchronizationObject::UnregisterWaitingThread(KSynchronizationObject::iterator it) { - MESOSPHERE_ASSERT_THIS(); - - return this->thread_list.erase(it); - } - - KSynchronizationObject::iterator KSynchronizationObject::begin() { - MESOSPHERE_ASSERT_THIS(); - - return this->thread_list.begin(); - } - - KSynchronizationObject::iterator KSynchronizationObject::end() { - MESOSPHERE_ASSERT_THIS(); - - return this->thread_list.end(); - } - } diff --git a/libraries/libmesosphere/source/kern_k_thread.cpp b/libraries/libmesosphere/source/kern_k_thread.cpp index 1564c93fe..25c81bc68 100644 --- a/libraries/libmesosphere/source/kern_k_thread.cpp +++ b/libraries/libmesosphere/source/kern_k_thread.cpp @@ -1089,7 +1089,7 @@ namespace ams::kern { /* If the thread isn't terminated, wait for it to terminate. */ s32 index; KSynchronizationObject *objects[] = { this }; - Kernel::GetSynchronization().Wait(std::addressof(index), objects, 1, ams::svc::WaitInfinite); + KSynchronizationObject::Wait(std::addressof(index), objects, 1, ams::svc::WaitInfinite); } } diff --git a/libraries/libmesosphere/source/svc/kern_svc_ipc.cpp b/libraries/libmesosphere/source/svc/kern_svc_ipc.cpp index ac95372d6..2d0dc1c6e 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_ipc.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_ipc.cpp @@ -72,7 +72,7 @@ namespace ams::kern::svc { /* Wait for a message. */ while (true) { s32 index; - Result result = Kernel::GetSynchronization().Wait(std::addressof(index), objs, num_objects, timeout); + Result result = KSynchronizationObject::Wait(std::addressof(index), objs, num_objects, timeout); if (svc::ResultTimedOut::Includes(result)) { return result; } diff --git a/libraries/libmesosphere/source/svc/kern_svc_synchronization.cpp b/libraries/libmesosphere/source/svc/kern_svc_synchronization.cpp index 7c4b8c8e3..a9f44e3e2 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_synchronization.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_synchronization.cpp @@ -63,7 +63,7 @@ namespace ams::kern::svc { timeout = timeout_ns; } - return Kernel::GetSynchronization().Wait(out_index, objs, num_handles, timeout); + return KSynchronizationObject::Wait(out_index, objs, num_handles, timeout); } Result WaitSynchronization(int32_t *out_index, KUserPointer user_handles, int32_t num_handles, int64_t timeout_ns) { diff --git a/mesosphere/kernel/source/kern_kernel_instantiations.cpp b/mesosphere/kernel/source/kern_kernel_instantiations.cpp index e120b26f6..d64901947 100644 --- a/mesosphere/kernel/source/kern_kernel_instantiations.cpp +++ b/mesosphere/kernel/source/kern_kernel_instantiations.cpp @@ -26,7 +26,6 @@ namespace ams::kern { constinit KMemoryBlockSlabManager Kernel::s_sys_memory_block_manager; constinit KBlockInfoManager Kernel::s_block_info_manager; constinit KSupervisorPageTable Kernel::s_supervisor_page_table; - constinit KSynchronization Kernel::s_synchronization; constinit KUnsafeMemory Kernel::s_unsafe_memory; constinit KWorkerTaskManager Kernel::s_worker_task_managers[KWorkerTaskManager::WorkerType_Count]; constinit KInterruptManager Kernel::s_interrupt_manager;