diff options
| author | Yuri Kunde Schlesner <yuriks@yuriks.net> | 2017-05-29 15:45:30 -0700 | 
|---|---|---|
| committer | Yuri Kunde Schlesner <yuriks@yuriks.net> | 2017-05-29 16:16:46 -0700 | 
| commit | 64ecf81a3cf6d6e0a4e4e915e1da2f0bcf2f1cb4 (patch) | |
| tree | f34182d882d614273dd709f0029039743bc58c21 | |
| parent | 9453223075e100a94b274613f1da0c47f747edf5 (diff) | |
Kernel: Move WaitObject to a separate file
Now that HandleTable doesn't directly depend on WaitObject anymore, this
can be separated from the main kernel.h header.
| -rw-r--r-- | src/citra_qt/debugger/wait_tree.cpp | 1 | ||||
| -rw-r--r-- | src/citra_qt/debugger/wait_tree.h | 4 | ||||
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/event.h | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 79 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 53 | ||||
| -rw-r--r-- | src/core/hle/kernel/mutex.h | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/semaphore.h | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/server_port.h | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/server_session.h | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.h | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/timer.h | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/wait_object.cpp | 99 | ||||
| -rw-r--r-- | src/core/hle/kernel/wait_object.h | 67 | ||||
| -rw-r--r-- | src/core/hle/svc.cpp | 1 | 
15 files changed, 178 insertions, 135 deletions
diff --git a/src/citra_qt/debugger/wait_tree.cpp b/src/citra_qt/debugger/wait_tree.cpp index b6ecf3819..8c244b6b2 100644 --- a/src/citra_qt/debugger/wait_tree.cpp +++ b/src/citra_qt/debugger/wait_tree.cpp @@ -10,6 +10,7 @@  #include "core/hle/kernel/semaphore.h"  #include "core/hle/kernel/thread.h"  #include "core/hle/kernel/timer.h" +#include "core/hle/kernel/wait_object.h"  WaitTreeItem::~WaitTreeItem() {} diff --git a/src/citra_qt/debugger/wait_tree.h b/src/citra_qt/debugger/wait_tree.h index ee9708fc1..06ef58ea7 100644 --- a/src/citra_qt/debugger/wait_tree.h +++ b/src/citra_qt/debugger/wait_tree.h @@ -4,12 +4,10 @@  #pragma once -#include <boost/container/flat_set.hpp> -  #include <QAbstractItemModel>  #include <QDockWidget>  #include <QTreeView> - +#include <boost/container/flat_set.hpp>  #include "core/core.h"  #include "core/hle/kernel/kernel.h" diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 7aa81e885..ba24a6e02 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -57,6 +57,7 @@ set(SRCS              hle/kernel/thread.cpp              hle/kernel/timer.cpp              hle/kernel/vm_manager.cpp +            hle/kernel/wait_object.cpp              hle/service/ac/ac.cpp              hle/service/ac/ac_i.cpp              hle/service/ac/ac_u.cpp @@ -249,6 +250,7 @@ set(HEADERS              hle/kernel/thread.h              hle/kernel/timer.h              hle/kernel/vm_manager.h +            hle/kernel/wait_object.h              hle/result.h              hle/service/ac/ac.h              hle/service/ac/ac_i.h diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h index 3e3673508..cc41abb85 100644 --- a/src/core/hle/kernel/event.h +++ b/src/core/hle/kernel/event.h @@ -6,6 +6,7 @@  #include "common/common_types.h"  #include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/wait_object.h"  namespace Kernel { diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 7f84e01aa..b0af5b9b8 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -20,85 +20,6 @@ namespace Kernel {  unsigned int Object::next_object_id;  HandleTable g_handle_table; -void WaitObject::AddWaitingThread(SharedPtr<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) { -    auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); -    // If a thread passed multiple handles to the same object, -    // the kernel might attempt to remove the thread from the object's -    // waiting threads list multiple times. -    if (itr != waiting_threads.end()) -        waiting_threads.erase(itr); -} - -SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() { -    Thread* candidate = nullptr; -    s32 candidate_priority = THREADPRIO_LOWEST + 1; - -    for (const auto& thread : waiting_threads) { -        // The list of waiting threads must not contain threads that are not waiting to be awakened. -        ASSERT_MSG(thread->status == THREADSTATUS_WAIT_SYNCH_ANY || -                       thread->status == THREADSTATUS_WAIT_SYNCH_ALL, -                   "Inconsistent thread statuses in waiting_threads"); - -        if (thread->current_priority >= candidate_priority) -            continue; - -        if (ShouldWait(thread.get())) -            continue; - -        // A thread is ready to run if it's either in THREADSTATUS_WAIT_SYNCH_ANY or -        // in THREADSTATUS_WAIT_SYNCH_ALL and the rest of the objects it is waiting on are ready. -        bool ready_to_run = true; -        if (thread->status == THREADSTATUS_WAIT_SYNCH_ALL) { -            ready_to_run = std::none_of(thread->wait_objects.begin(), thread->wait_objects.end(), -                                        [&thread](const SharedPtr<WaitObject>& object) { -                                            return object->ShouldWait(thread.get()); -                                        }); -        } - -        if (ready_to_run) { -            candidate = thread.get(); -            candidate_priority = thread->current_priority; -        } -    } - -    return candidate; -} - -void WaitObject::WakeupAllWaitingThreads() { -    while (auto thread = GetHighestPriorityReadyThread()) { -        if (!thread->IsSleepingOnWaitAll()) { -            Acquire(thread.get()); -            // Set the output index of the WaitSynchronizationN call to the index of this object. -            if (thread->wait_set_output) { -                thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(this)); -                thread->wait_set_output = false; -            } -        } else { -            for (auto& object : thread->wait_objects) { -                object->Acquire(thread.get()); -            } -            // Note: This case doesn't update the output index of WaitSynchronizationN. -        } - -        for (auto& object : thread->wait_objects) -            object->RemoveWaitingThread(thread.get()); -        thread->wait_objects.clear(); - -        thread->SetWaitSynchronizationResult(RESULT_SUCCESS); -        thread->ResumeFromWait(); -    } -} - -const std::vector<SharedPtr<Thread>>& WaitObject::GetWaitingThreads() const { -    return waiting_threads; -} -  HandleTable::HandleTable() {      next_generation = 1;      Clear(); diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 4344264dc..5335a961d 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -17,8 +17,6 @@ namespace Kernel {  using Handle = u32; -class Thread; -  enum KernelHandle : Handle {      CurrentThread = 0xFFFF8000,      CurrentProcess = 0xFFFF8001, @@ -133,57 +131,6 @@ inline SharedPtr<T> DynamicObjectCast(SharedPtr<Object> object) {      return nullptr;  } -/// Class that represents a Kernel object that a thread can be waiting on -class WaitObject : public Object { -public: -    /** -     * Check if the specified thread should wait until the object is available -     * @param thread The thread about which we're deciding. -     * @return True if the current thread should wait due to this object being unavailable -     */ -    virtual bool ShouldWait(Thread* thread) const = 0; - -    /// Acquire/lock the object for the specified thread if it is available -    virtual void Acquire(Thread* thread) = 0; - -    /** -     * Add a thread to wait on this object -     * @param thread Pointer to thread to add -     */ -    virtual void AddWaitingThread(SharedPtr<Thread> thread); - -    /** -     * Removes a thread from waiting on this object (e.g. if it was resumed already) -     * @param thread Pointer to thread to remove -     */ -    virtual void RemoveWaitingThread(Thread* thread); - -    /** -     * Wake up all threads waiting on this object that can be awoken, in priority order, -     * and set the synchronization result and output of the thread. -     */ -    virtual void WakeupAllWaitingThreads(); - -    /// Obtains the highest priority thread that is ready to run from this object's waiting list. -    SharedPtr<Thread> GetHighestPriorityReadyThread(); - -    /// Get a const reference to the waiting threads list for debug use -    const std::vector<SharedPtr<Thread>>& GetWaitingThreads() const; - -private: -    /// Threads waiting for this object to become available -    std::vector<SharedPtr<Thread>> waiting_threads; -}; - -// Specialization of DynamicObjectCast for WaitObjects -template <> -inline SharedPtr<WaitObject> DynamicObjectCast<WaitObject>(SharedPtr<Object> object) { -    if (object != nullptr && object->IsWaitable()) { -        return boost::static_pointer_cast<WaitObject>(std::move(object)); -    } -    return nullptr; -} -  /**   * This class allows the creation of Handles, which are references to objects that can be tested   * for validity and looked up. Here they are used to pass references to kernel objects to/from the diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h index c57adf400..bacacd690 100644 --- a/src/core/hle/kernel/mutex.h +++ b/src/core/hle/kernel/mutex.h @@ -7,6 +7,7 @@  #include <string>  #include "common/common_types.h"  #include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/wait_object.h"  namespace Kernel { diff --git a/src/core/hle/kernel/semaphore.h b/src/core/hle/kernel/semaphore.h index cde94f7cc..ca6f908aa 100644 --- a/src/core/hle/kernel/semaphore.h +++ b/src/core/hle/kernel/semaphore.h @@ -8,6 +8,7 @@  #include <string>  #include "common/common_types.h"  #include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/wait_object.h"  namespace Kernel { diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h index 6f8bdb6a9..2a24d8412 100644 --- a/src/core/hle/kernel/server_port.h +++ b/src/core/hle/kernel/server_port.h @@ -9,6 +9,7 @@  #include <tuple>  #include "common/common_types.h"  #include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/wait_object.h"  namespace Service {  class SessionRequestHandler; diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index c907d487c..315b80d14 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h @@ -11,6 +11,7 @@  #include "core/hle/kernel/kernel.h"  #include "core/hle/kernel/session.h"  #include "core/hle/kernel/thread.h" +#include "core/hle/kernel/wait_object.h"  #include "core/hle/result.h"  #include "core/hle/service/service.h"  #include "core/memory.h" diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 7b5169cfc..6a3566f15 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -12,6 +12,7 @@  #include "common/common_types.h"  #include "core/arm/arm_interface.h"  #include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/wait_object.h"  #include "core/hle/result.h"  enum ThreadPriority : s32 { diff --git a/src/core/hle/kernel/timer.h b/src/core/hle/kernel/timer.h index b0f818933..82552372d 100644 --- a/src/core/hle/kernel/timer.h +++ b/src/core/hle/kernel/timer.h @@ -6,6 +6,7 @@  #include "common/common_types.h"  #include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/wait_object.h"  namespace Kernel { diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp new file mode 100644 index 000000000..f245eda6c --- /dev/null +++ b/src/core/hle/kernel/wait_object.cpp @@ -0,0 +1,99 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <algorithm> +#include "common/assert.h" +#include "common/logging/log.h" +#include "core/hle/config_mem.h" +#include "core/hle/kernel/errors.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/memory.h" +#include "core/hle/kernel/process.h" +#include "core/hle/kernel/resource_limit.h" +#include "core/hle/kernel/thread.h" +#include "core/hle/kernel/timer.h" +#include "core/hle/shared_page.h" + +namespace Kernel { + +void WaitObject::AddWaitingThread(SharedPtr<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) { +    auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); +    // If a thread passed multiple handles to the same object, +    // the kernel might attempt to remove the thread from the object's +    // waiting threads list multiple times. +    if (itr != waiting_threads.end()) +        waiting_threads.erase(itr); +} + +SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() { +    Thread* candidate = nullptr; +    s32 candidate_priority = THREADPRIO_LOWEST + 1; + +    for (const auto& thread : waiting_threads) { +        // The list of waiting threads must not contain threads that are not waiting to be awakened. +        ASSERT_MSG(thread->status == THREADSTATUS_WAIT_SYNCH_ANY || +                       thread->status == THREADSTATUS_WAIT_SYNCH_ALL, +                   "Inconsistent thread statuses in waiting_threads"); + +        if (thread->current_priority >= candidate_priority) +            continue; + +        if (ShouldWait(thread.get())) +            continue; + +        // A thread is ready to run if it's either in THREADSTATUS_WAIT_SYNCH_ANY or +        // in THREADSTATUS_WAIT_SYNCH_ALL and the rest of the objects it is waiting on are ready. +        bool ready_to_run = true; +        if (thread->status == THREADSTATUS_WAIT_SYNCH_ALL) { +            ready_to_run = std::none_of(thread->wait_objects.begin(), thread->wait_objects.end(), +                                        [&thread](const SharedPtr<WaitObject>& object) { +                                            return object->ShouldWait(thread.get()); +                                        }); +        } + +        if (ready_to_run) { +            candidate = thread.get(); +            candidate_priority = thread->current_priority; +        } +    } + +    return candidate; +} + +void WaitObject::WakeupAllWaitingThreads() { +    while (auto thread = GetHighestPriorityReadyThread()) { +        if (!thread->IsSleepingOnWaitAll()) { +            Acquire(thread.get()); +            // Set the output index of the WaitSynchronizationN call to the index of this object. +            if (thread->wait_set_output) { +                thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(this)); +                thread->wait_set_output = false; +            } +        } else { +            for (auto& object : thread->wait_objects) { +                object->Acquire(thread.get()); +            } +            // Note: This case doesn't update the output index of WaitSynchronizationN. +        } + +        for (auto& object : thread->wait_objects) +            object->RemoveWaitingThread(thread.get()); +        thread->wait_objects.clear(); + +        thread->SetWaitSynchronizationResult(RESULT_SUCCESS); +        thread->ResumeFromWait(); +    } +} + +const std::vector<SharedPtr<Thread>>& WaitObject::GetWaitingThreads() const { +    return waiting_threads; +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/wait_object.h b/src/core/hle/kernel/wait_object.h new file mode 100644 index 000000000..861578186 --- /dev/null +++ b/src/core/hle/kernel/wait_object.h @@ -0,0 +1,67 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <vector> +#include <boost/smart_ptr/intrusive_ptr.hpp> +#include "common/common_types.h" +#include "core/hle/kernel/kernel.h" + +namespace Kernel { + +class Thread; + +/// Class that represents a Kernel object that a thread can be waiting on +class WaitObject : public Object { +public: +    /** +     * Check if the specified thread should wait until the object is available +     * @param thread The thread about which we're deciding. +     * @return True if the current thread should wait due to this object being unavailable +     */ +    virtual bool ShouldWait(Thread* thread) const = 0; + +    /// Acquire/lock the object for the specified thread if it is available +    virtual void Acquire(Thread* thread) = 0; + +    /** +     * Add a thread to wait on this object +     * @param thread Pointer to thread to add +     */ +    virtual void AddWaitingThread(SharedPtr<Thread> thread); + +    /** +     * Removes a thread from waiting on this object (e.g. if it was resumed already) +     * @param thread Pointer to thread to remove +     */ +    virtual void RemoveWaitingThread(Thread* thread); + +    /** +     * Wake up all threads waiting on this object that can be awoken, in priority order, +     * and set the synchronization result and output of the thread. +     */ +    virtual void WakeupAllWaitingThreads(); + +    /// Obtains the highest priority thread that is ready to run from this object's waiting list. +    SharedPtr<Thread> GetHighestPriorityReadyThread(); + +    /// Get a const reference to the waiting threads list for debug use +    const std::vector<SharedPtr<Thread>>& GetWaitingThreads() const; + +private: +    /// Threads waiting for this object to become available +    std::vector<SharedPtr<Thread>> waiting_threads; +}; + +// Specialization of DynamicObjectCast for WaitObjects +template <> +inline SharedPtr<WaitObject> DynamicObjectCast<WaitObject>(SharedPtr<Object> object) { +    if (object != nullptr && object->IsWaitable()) { +        return boost::static_pointer_cast<WaitObject>(std::move(object)); +    } +    return nullptr; +} + +} // namespace Kernel diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 243c54c6e..83767677f 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -27,6 +27,7 @@  #include "core/hle/kernel/thread.h"  #include "core/hle/kernel/timer.h"  #include "core/hle/kernel/vm_manager.h" +#include "core/hle/kernel/wait_object.h"  #include "core/hle/result.h"  #include "core/hle/service/service.h"  | 
