#pragma once #include #include #include #include #include #include #include #include #include #include #include "KingSystem/Utils/HeapUtil.h" #include "KingSystem/Utils/Thread/Event.h" #include "KingSystem/Utils/Thread/ManagedTask.h" #include "KingSystem/Utils/Types.h" namespace ksys::util { class ManagedTaskHandle; class TaskRequest; struct TaskMgrRequest; using ManagedTaskFactory = sead::IDelegate1; struct TaskMgrRequest { /// Optional. If null, a task from the internal buffer will be used. ManagedTask* task = nullptr; /// Must not be null. TaskRequest* request = nullptr; /// Optional. ManagedTaskHandle* handle = nullptr; }; KSYS_CHECK_SIZE_NX150(TaskMgrRequest, 0x18); class TaskMgr { SEAD_RTTI_BASE(TaskMgr) public: explicit TaskMgr(sead::Heap* heap); virtual ~TaskMgr(); void init(s32 num_tasks, sead::Heap* heap, ManagedTaskFactory& factory); template void init(s32 num_tasks, sead::Heap* heap) { initImpl_(num_tasks, heap); } template void initAndCheckType(s32 num_tasks, sead::Heap* heap) { initImpl_(num_tasks, heap); if (hasTasks()) { Task* task = mFreeTaskLists[0].front(); const bool is_derived_from_managed_task = sead::IsDerivedFrom(task); SEAD_ASSERT(is_derived_from_managed_task); } } void finalize(); void submitRequest(TaskMgrRequest& request); bool trySubmitRequest(TaskMgrRequest& request); bool hasTasks() const; void freeTask(ManagedTask* task); protected: enum class Flag { HeapIsFreeable = 0x1, }; bool fetchIdleTaskForRequest_(TaskMgrRequest& request, bool retry_until_success); ManagedTask* fetchIdleTask_(bool retry_until_success); u8 getListIndex_() const { return mListIndex; } u8 getListIndex2_() const { return ~mListIndex & 1; } void swapLists_() { auto lock = sead::makeScopedLock(mCS2); mListIndex = getListIndex2_(); mNewFreeTaskEvent.resetSignal(); } bool tryFetchTaskForRequest_(TaskMgrRequest& request, bool b) { if (!mTasksCS.tryLock()) return false; const bool ret = fetchIdleTaskForRequest_(request, b); mTasksCS.unlock(); return ret; } template void makeTaskType_(ManagedTask** task) { *task = new TaskType(getCurrentHeap()); } template void initImpl_(s32 num_tasks, sead::Heap* heap) { sead::Delegate1 factory{this, &TaskMgr::makeTaskType_}; init(num_tasks, heap, factory); } sead::TypedBitFlag mFlags; u8 mListIndex = 0; ManagedTask* mTask = nullptr; sead::CriticalSection mTasksCS; sead::CriticalSection mCS2; Event mNewFreeTaskEvent; Event mEvent2; sead::SafeArray, 2> mFreeTaskLists; sead::Buffer mTasks; }; KSYS_CHECK_SIZE_NX150(TaskMgr, 0x158); } // namespace ksys::util