diff --git a/CMakeLists.txt b/CMakeLists.txt index 042301a0..47de3964 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,6 +76,16 @@ add_executable(uking src/KingSystem/Utils/Thread/Event.cpp src/KingSystem/Utils/Thread/Event.h + src/KingSystem/Utils/Thread/Task.cpp + src/KingSystem/Utils/Thread/Task.h + src/KingSystem/Utils/Thread/TaskQueueBase.cpp + src/KingSystem/Utils/Thread/TaskQueueBase.h + src/KingSystem/Utils/Thread/TaskQueue.cpp + src/KingSystem/Utils/Thread/TaskQueue.h + src/KingSystem/Utils/Thread/TaskQueueLock.cpp + src/KingSystem/Utils/Thread/TaskQueueLock.h + src/KingSystem/Utils/Thread/TaskThread.cpp + src/KingSystem/Utils/Thread/TaskThread.h src/KingSystem/Utils/Byaml.cpp src/KingSystem/Utils/Byaml.h src/KingSystem/Utils/ByamlLocal.cpp diff --git a/data/uking_functions.csv b/data/uking_functions.csv index e8a8dcd0..716d3c00 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -86769,44 +86769,45 @@ 0x00000071010c0c5c,Event::setSignal,52,_ZN4ksys4util5Event9setSignalEv 0x00000071010c0c90,Event::resetSignal,64,_ZN4ksys4util5Event11resetSignalEv 0x00000071010c0ce0,sub_71010C0CE0,32, -0x00000071010c0d00,ThreadD0Base::ctor,96, -0x00000071010c0d60,sub_71010C0D60,136, -0x00000071010c0de8,sub_71010C0DE8,524, -0x00000071010c0ff4,sub_71010C0FF4,144, -0x00000071010c1084,ThreadD0::init,308, -0x00000071010c11b8,ThreadD0::b,156, -0x00000071010c1254,ThreadD0::somethingOnDtor,168, -0x00000071010c12fc,sub_71010C12FC,8, -0x00000071010c1304,ThreadD0::x,228, -0x00000071010c13e8,ThreadD0::x_0,188, -0x00000071010c1574,ThreadD0::c,212, -0x00000071010c1648,ThreadD0::b_0,796, -0x00000071010c1964,ThreadD0::stop,192, -0x00000071010c1a24,sub_71010C1A24,416, -0x00000071010c1bc4,sub_71010C1BC4,52, -0x00000071010c1bf8,ThreadD0::a_2,464, -0x00000071010c1dc8,ThreadD0::threadPeekAtMessageQueueStuffConditional,48, -0x00000071010c1df8,ThreadD0::u,16, -0x00000071010c1e08,ThreadD0::a_0,184, -0x00000071010c1ec0,ThreadD0::x_4,52, -0x00000071010c1ef4,ThreadD0::x_2,72, -0x00000071010c1f3c,ThreadD0::x_1,16, -0x00000071010c1f4c,ThreadD0::x_3,32, -0x00000071010c1f6c,ThreadD0::threadPeekAtMessageQueueStuff,384, -0x00000071010c20ec,ThreadD0::a_1,412, -0x00000071010c2288,sub_71010C2288,364, -0x00000071010c23f4,nullsub_4511,4, -0x00000071010c23f8,nullsub_4512,4, -0x00000071010c23fc,sub_71010C23FC,860, -0x00000071010c2758,sub_71010C2758,112, -0x00000071010c27c8,sub_71010C27C8,92, +0x00000071010c0d00,ThreadD0Base::ctor,96,_ZN4ksys4util13TaskQueueBaseC1EPN4sead4HeapE +0x00000071010c0d60,sub_71010C0D60,136,_ZN4ksys4util13TaskQueueBaseD1Ev +0x00000071010c0de8,sub_71010C0DE8,524,_ZN4ksys4util13TaskQueueBase5clearEv +0x00000071010c0ff4,sub_71010C0FF4,144,_ZN4ksys4util13TaskQueueBaseD0Ev +0x00000071010c1084,ThreadD0::init,308,_ZN4ksys4util13TaskQueueBase4initERKNS1_7InitArgE +0x00000071010c11b8,ThreadD0::b,156,_ZN4ksys4util13TaskQueueBase9addThreadEPNS0_10TaskThreadE +0x00000071010c1254,ThreadD0::somethingOnDtor,168,_ZN4ksys4util13TaskQueueBase12removeThreadEPNS0_10TaskThreadE +0x00000071010c12fc,sub_71010C12FC,8,_ZNK4ksys4util13TaskQueueBase17getNumActiveTasksEv +0x00000071010c1304,ThreadD0::x,228,_ZNK4ksys4util13TaskQueueBase16countTasksInLaneEt +0x00000071010c13e8,ThreadD0::x_0,188,_ZNK4ksys4util13TaskQueueBase16areNoThreadsBusyEv +0x00000071010c14a4,_ZN4ksys4util13TaskQueueBase3x_aEv,0xd0,_ZN4ksys4util13TaskQueueBase19waitForQueueToEmptyEv +0x00000071010c1574,ThreadD0::c,212,_ZN4ksys4util13TaskQueueBase18waitForLaneToEmptyEh +0x00000071010c1648,ThreadD0::b_0,796,_ZN4ksys4util13TaskQueueBase11cancelTasksEh +0x00000071010c1964,ThreadD0::stop,192,_ZNK4ksys4util13TaskQueueBase16isProcessingTaskEh +0x00000071010c1a24,sub_71010C1A24,416,_ZN4ksys4util13TaskQueueBase25signalEmptyEventsIfNeededEv +0x00000071010c1bc4,sub_71010C1BC4,52,_ZN4ksys4util13TaskQueueBase10blockTasksEh +0x00000071010c1bf8,ThreadD0::a_2,464,_ZN4ksys4util13TaskQueueBase26blockTasksAndReloadThreadsEh! +0x00000071010c1dc8,ThreadD0::threadPeekAtMessageQueueStuffConditional,48,_ZN4ksys4util13TaskQueueBase12unblockTasksEh +0x00000071010c1df8,ThreadD0::u,16,_ZN4ksys4util13TaskQueueBase4lockEPNS0_13TaskQueueLockE +0x00000071010c1e08,ThreadD0::a_0,184,_ZNK4ksys4util13TaskQueueBase16getCurrentThreadEv +0x00000071010c1ec0,ThreadD0::x_4,52,_ZN4ksys4util13TaskQueueBase16activeTasksBeginEPNS0_13TaskQueueLockE +0x00000071010c1ef4,ThreadD0::x_2,72,_ZN4ksys4util13TaskQueueBase22activeTasksRobustBeginEPNS0_13TaskQueueLockE +0x00000071010c1f3c,ThreadD0::x_1,16,_ZNK4ksys4util13TaskQueueBase14activeTasksEndEv +0x00000071010c1f4c,ThreadD0::x_3,32,_ZNK4ksys4util13TaskQueueBase20activeTasksRobustEndEv +0x00000071010c1f6c,ThreadD0::threadPeekAtMessageQueueStuff,384,_ZN4ksys4util13TaskQueueBase24notifyThreadsForNewTasksEv? +0x00000071010c20ec,ThreadD0::a_1,412,_ZN4ksys4util13TaskQueueBase4pushERKNS1_7PushArgE? +0x00000071010c2288,sub_71010C2288,364,_ZN4ksys4util13TaskQueueBase10removeTaskEPNS0_4TaskEb +0x00000071010c23f4,nullsub_4511,4,_ZNK4ksys4util13TaskQueueBase4lockEv +0x00000071010c23f8,nullsub_4512,4,_ZNK4ksys4util13TaskQueueBase6unlockEv +0x00000071010c23fc,sub_71010C23FC,860,_ZN4ksys4util13TaskQueueBase9fetchTaskEPPNS0_4TaskE? +0x00000071010c2758,sub_71010C2758,112,_ZNK4ksys4util13TaskQueueBase27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE +0x00000071010c27c8,sub_71010C27C8,92,_ZNK4ksys4util13TaskQueueBase18getRuntimeTypeInfoEv 0x00000071010c2824,sub_71010C2824,100, -0x00000071010c2888,ctor_1,20, -0x00000071010c289c,dtor_1,68, -0x00000071010c28e0,sub_71010C28E0,68, -0x00000071010c2924,sub_71010C2924,32, -0x00000071010c2944,sub_71010C2944,112, -0x00000071010c29b4,sub_71010C29B4,92, +0x00000071010c2888,ctor_1,20,_ZN4ksys4util13TaskQueueLockC1Ev +0x00000071010c289c,dtor_1,68,_ZN4ksys4util13TaskQueueLockD1Ev +0x00000071010c28e0,sub_71010C28E0,68,_ZN4ksys4util13TaskQueueLockD0Ev +0x00000071010c2924,sub_71010C2924,32,_ZN4ksys4util13TaskQueueLock4lockEPNS0_13TaskQueueBaseE +0x00000071010c2944,sub_71010C2944,112,_ZNK4ksys4util13TaskQueueLock27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE +0x00000071010c29b4,sub_71010C29B4,92,_ZNK4ksys4util13TaskQueueLock18getRuntimeTypeInfoEv 0x00000071010c2a10,sub_71010C2A10,8, 0x00000071010c2a18,nullsub_4513,4, 0x00000071010c2a1c,sub_71010C2A1C,24, @@ -90459,34 +90460,35 @@ 0x00000071011f67b0,sub_71011F67B0,8, 0x00000071011f67b8,sub_71011F67B8,204, 0x00000071011f6884,sub_71011F6884,92, -0x00000071011f68e0,Thread::ctor,108, -0x00000071011f694c,Thread::dtor,120, -0x00000071011f69c4,Thread::dtorDelete,128, -0x00000071011f6a44,Thread::init,224, -0x00000071011f6b24,sub_71011F6B24,8, -0x00000071011f6b2c,Thread::z,8, -0x00000071011f6b34,Thread::x,8, -0x00000071011f6b44,sub_71011F6B44,8, -0x00000071011f6b4c,Thread::peekMessage,64, -0x00000071011f6b8c,Thread::y,12, -0x00000071011f6b98,Thread::peekIs1,36, -0x00000071011f6bbc,Thread::waitResetSignalAndJam2,128, -0x00000071011f6c3c,Thread::waitResetSignalAndJam2AndEvent,156, -0x00000071011f6cd8,Thread::waitResetSignalAndJam3,128, -0x00000071011f6d58,Thread::jamMessageQueueAndWait,156, -0x00000071011f6df4,sub_71011F6DF4,16, -0x00000071011f6e04,sub_71011F6E04,12, -0x00000071011f6e10,Thread::calc_,624, -0x00000071011f7080,nullsub_4674,4, -0x00000071011f7084,Thread::peekIs2,36, -0x00000071011f70a8,Thread::peekIs3,36, -0x00000071011f70cc,Thread::peekIsShutdownMessage,48, -0x00000071011f70fc,sub_71011F70FC,76, -0x00000071011f7148,Thread::rtti1,112, -0x00000071011f71b8,Thread::rtti2,92, -0x00000071011f7214,sub_71011F7214,112, -0x00000071011f7284,sub_71011F7284,92, -0x00000071011f72e0,j__ZdlPv_1226,4, +0x00000071011f68e0,Thread::ctor,108,_ZN4ksys4util10TaskThreadC1ERKN4sead14SafeStringBaseIcEEPNS2_4HeapEiNS2_12MessageQueue9BlockTypeElii +0x00000071011f694c,Thread::dtor,120,_ZN4ksys4util10TaskThreadD1Ev +0x00000071011f69c4,Thread::dtorDelete,128,_ZN4ksys4util10TaskThreadD0Ev +0x00000071011f6a44,Thread::init,224,_ZN4ksys4util10TaskThread4initERKNS1_7InitArgE +0x00000071011f6b24,sub_71011F6B24,8,_ZNK4ksys4util10TaskThread17getNumActiveTasksEv +0x00000071011f6b2c,Thread::z,8,_ZN4ksys4util10TaskThread19waitForQueueToEmptyEv +0x00000071011f6b34,Thread::x,8,_ZN4ksys4util10TaskThread11cancelTasksEh +0x00000071011f6b44,sub_71011F6B44,8,_ZN4ksys4util10TaskThread4lockEPNS0_13TaskQueueLockE +0x00000071011f6b3c,_ZN4ksys4util10TaskThread10clearQueueEv,8,_ZN4ksys4util10TaskThread10clearQueueEv +0x00000071011f6b4c,Thread::peekMessage,64,_ZNK4ksys4util10TaskThread33isActiveAndReceivedQueueUpdateMsgEv +0x00000071011f6b8c,Thread::y,12,_ZNK4ksys4util10TaskThread8isPausedEv +0x00000071011f6b98,Thread::peekIs1,36,_ZNK4ksys4util10TaskThread23receivedQueueUpdatedMsgEv +0x00000071011f6bbc,Thread::waitResetSignalAndJam2,128,_ZN4ksys4util10TaskThread5pauseEv +0x00000071011f6c3c,Thread::waitResetSignalAndJam2AndEvent,156,_ZN4ksys4util10TaskThread18pauseAndWaitForAckEv +0x00000071011f6cd8,Thread::waitResetSignalAndJam3,128,_ZN4ksys4util10TaskThread6resumeEv +0x00000071011f6d58,Thread::jamMessageQueueAndWait,156,_ZN4ksys4util10TaskThread19resumeAndWaitForAckEv +0x00000071011f6df4,sub_71011F6DF4,16,_ZNK4ksys4util10TaskThread20isBusyProcessingTaskEv +0x00000071011f6e04,sub_71011F6E04,12,_ZNK4ksys4util10TaskThread16isLookingForTaskEv +0x00000071011f6e10,Thread::calc_,624,_ZN4ksys4util10TaskThread5calc_El? +0x00000071011f7080,nullsub_4674,4,_ZN4ksys4util17TaskPostRunResultD2Ev +0x00000071011f7084,Thread::peekIs2,36,_ZNK4ksys4util10TaskThread16receivedPauseMsgEv +0x00000071011f70a8,Thread::peekIs3,36,_ZNK4ksys4util10TaskThread17receivedResumeMsgEv +0x00000071011f70cc,Thread::peekIsShutdownMessage,48,_ZNK4ksys4util10TaskThread15receivedQuitMsgEv +0x00000071011f70fc,sub_71011F70FC,76,_ZN4ksys4util10TaskThread17cancelCurrentTaskEv +0x00000071011f7148,Thread::rtti1,112,_ZNK4ksys4util10TaskThread27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE +0x00000071011f71b8,Thread::rtti2,92,_ZNK4ksys4util10TaskThread18getRuntimeTypeInfoEv +0x00000071011f7214,sub_71011F7214,112,_ZNK4ksys4util17TaskPostRunResult27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE +0x00000071011f7284,sub_71011F7284,92,_ZNK4ksys4util17TaskPostRunResult18getRuntimeTypeInfoEv +0x00000071011f72e0,j__ZdlPv_1226,4,_ZN4ksys4util17TaskPostRunResultD0Ev 0x00000071011f72e4,sub_71011F72E4,44, 0x00000071011f7310,EventPlusStringDerived::ctor,60, 0x00000071011f734c,sub_71011F734C,72, @@ -90516,57 +90518,57 @@ 0x00000071011f78cc,sub_71011F78CC,204, 0x00000071011f7998,sub_71011F7998,92, 0x00000071011f79f4,sub_71011F79F4,140, -0x00000071011f7a80,SetMainInvokerClass::ctor,20, -0x00000071011f7a94,SetMainInvokerClass::dtor,4, -0x00000071011f7a98,j__ZdlPv_1227,4, -0x00000071011f7a9c,sub_71011F7A9C,8, -0x00000071011f7aa4,EventPlusString::ctor,120, -0x00000071011f7b1c,EventPlusString::ctor2,120, -0x00000071011f7b94,EventPlusString::dtor,132, -0x00000071011f7c18,EventPlusStringDerived::calledFromDtor,112, -0x00000071011f7c88,EventPlusString::dtorDelete,140, -0x00000071011f7d14,EventPlusString::setMainInvoker,36, -0x00000071011f7d38,EventPlusString::submitRequest,544, -0x00000071011f7f58,EventPlusString::u,124, -0x00000071011f8034,EventPlusString::v,360, -0x00000071011f819c,EventPlusString::p,28, -0x00000071011f81b8,sub_71011F81B8,28, -0x00000071011f81d4,EventPlusString::wait,28, -0x00000071011f81f0,EventPlusString::waitTimed,12, -0x00000071011f81fc,sub_71011F81FC,8, -0x00000071011f8204,EventPlusString::w,40, -0x00000071011f822c,EventPlusString::o,40, -0x00000071011f8254,sub_71011F8254,12, -0x00000071011f8260,sub_71011F8260,8, -0x00000071011f8268,sub_71011F8268,48, -0x00000071011f8298,sub_71011F8298,12, -0x00000071011f82a4,sub_71011F82A4,100, -0x00000071011f8308,sub_71011F8308,100, -0x00000071011f836c,EventPlusString::return1,8, -0x00000071011f8374,EventPlusString::null1,4, -0x00000071011f8378,EventPlusString::b,60, -0x00000071011f83b4,EventPlusString::null2,4, -0x00000071011f83b8,EventPlusString::null2_0,4, -0x00000071011f83bc,EventPlusString::null2_1,4, -0x00000071011f83c0,EventPlusString::null2_2,4, -0x00000071011f83c4,EventPlusString::null2_3,4, -0x00000071011f83c8,sub_71011F83C8,8, -0x00000071011f83d0,sub_71011F83D0,52, -0x00000071011f8404,sub_71011F8404,192, -0x00000071011f84c4,nullsub_4686,4, -0x00000071011f84c8,nullsub_4687,4, -0x00000071011f84cc,sub_71011F84CC,12, -0x00000071011f84d8,sub_71011F84D8,8, -0x00000071011f84e0,sub_71011F84E0,112, -0x00000071011f8550,sub_71011F8550,92, -0x00000071011f85ac,EventPlusString::rtti1,112, -0x00000071011f861c,EventPlusString::rtti2,92, -0x00000071011f8678,sub_71011F8678,112, -0x00000071011f86e8,sub_71011F86E8,92, -0x00000071011f8744,j__ZdlPv_1228,4, -0x00000071011f8748,sub_71011F8748,112, -0x00000071011f87b8,sub_71011F87B8,92, -0x00000071011f8814,j__ZdlPv_1229,4, +0x00000071011f7a80,SetMainInvokerClass::ctor,20,_ZN4ksys4util18TaskDelegateSetterC1Ev +0x00000071011f7a94,SetMainInvokerClass::dtor,4,_ZN4ksys4util18TaskDelegateSetterD1Ev +0x00000071011f7a98,j__ZdlPv_1227,4,_ZN4ksys4util18TaskDelegateSetterD0Ev +0x00000071011f7a9c,sub_71011F7A9C,8,_ZN4ksys4util18TaskDelegateSetter11setDelegateEPN4sead13AnyDelegate1RIPvbEE +0x00000071011f7aa4,EventPlusString::ctor,120,_ZN4ksys4util4TaskC1EPN4sead4HeapE +0x00000071011f7b1c,EventPlusString::ctor2,120,_ZN4ksys4util4TaskC1EPN4sead4HeapENS2_9IDisposer14HeapNullOptionE +0x00000071011f7b94,EventPlusString::dtor,132,_ZN4ksys4util4TaskD1Ev? +0x00000071011f7c18,EventPlusStringDerived::calledFromDtor,112,_ZN4ksys4util4Task9finalize_Ev? +0x00000071011f7c88,EventPlusString::dtorDelete,140,_ZN4ksys4util4TaskD0Ev? +0x00000071011f7d14,EventPlusString::setMainInvoker,36,_ZN4ksys4util4Task11setDelegateERKNS0_18TaskDelegateSetterE +0x00000071011f7d38,EventPlusString::submitRequest,544,_ZN4ksys4util4Task13submitRequestERNS0_11TaskRequestE? +0x00000071011f7f58,EventPlusString::u,124,_ZNK4ksys4util4Task16canSubmitRequestEv +0x00000071011f8034,EventPlusString::v,360,_ZN4ksys4util4Task30processOnCurrentThreadDirectlyEPNS0_10TaskThreadE +0x00000071011f819c,EventPlusString::p,28,_ZN4ksys4util4Task15removeFromQueueEv +0x00000071011f81b8,sub_71011F81B8,28,_ZN4ksys4util4Task16removeFromQueue2Ev +0x00000071011f81d4,EventPlusString::wait,28,_ZN4ksys4util4Task4waitEv +0x00000071011f81f0,EventPlusString::waitTimed,12,_ZN4ksys4util4Task4waitERKN4sead8TickSpanE +0x00000071011f81fc,sub_71011F81FC,8,_ZNK4ksys4util4Task9getLaneIdEv +0x00000071011f8204,EventPlusString::w,40,_ZNK4ksys4util4Task9isSuccessEv +0x00000071011f822c,EventPlusString::o,40,_ZNK4ksys4util4Task10isInactiveEv +0x00000071011f8254,sub_71011F8254,12,_ZN4ksys4util4Task15setStatusPushedEv +0x00000071011f8260,sub_71011F8260,8,_ZN4ksys4util4Task9setThreadEPNS0_10TaskThreadE +0x00000071011f8268,sub_71011F8268,48,_ZN4ksys4util4Task3runEv +0x00000071011f8298,sub_71011F8298,12,_ZN4ksys4util4Task13onRunFinishedEv +0x00000071011f82a4,sub_71011F82A4,100,_ZN4ksys4util4Task21invokePostRunCallbackEPNS0_17TaskPostRunResultE +0x00000071011f8308,sub_71011F8308,100,_ZN4ksys4util4Task6finishEv +0x00000071011f836c,EventPlusString::return1,8,_ZN4ksys4util4Task14onSetDelegate_ERKNS0_18TaskDelegateSetterE +0x00000071011f8374,EventPlusString::null1,4,_ZN4ksys4util4Task8prepare_EPNS0_11TaskRequestE +0x00000071011f8378,EventPlusString::b,60,_ZN4ksys4util4Task4run_Ev +0x00000071011f83b4,EventPlusString::null2,4,_ZN4ksys4util4Task14onRunFinished_Ev +0x00000071011f83b8,EventPlusString::null2_0,4,_ZN4ksys4util4Task9onFinish_Ev +0x00000071011f83bc,EventPlusString::null2_1,4,_ZN4ksys4util4Task13onPostFinish_Ev +0x00000071011f83c0,EventPlusString::null2_2,4,_ZN4ksys4util4Task10preRemove_Ev +0x00000071011f83c4,EventPlusString::null2_3,4,_ZN4ksys4util4Task11postRemove_Ev +0x00000071011f83c8,sub_71011F83C8,8,_ZNK4ksys4util4Task11getUserDataEv +0x00000071011f83d0,sub_71011F83D0,52,_ZN4ksys4util4Task6cancelEv +0x00000071011f8404,sub_71011F8404,192,_ZN4ksys4util4Task8onRemoveEv +0x00000071011f84c4,nullsub_4686,4,_ZN4ksys4util25TaskRemoveCallbackContextD2Ev +0x00000071011f84c8,nullsub_4687,4,_ZN4ksys4util18TaskPostRunContextD2Ev +0x00000071011f84cc,sub_71011F84CC,12,_ZN4ksys4util4Task16setStatusFetchedEv +0x00000071011f84d8,sub_71011F84D8,8,_ZN4ksys4util4Task9setLaneIdEh +0x00000071011f84e0,sub_71011F84E0,112,_ZNK4ksys4util18TaskDelegateSetter27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE +0x00000071011f8550,sub_71011F8550,92,_ZNK4ksys4util18TaskDelegateSetter18getRuntimeTypeInfoEv +0x00000071011f85ac,EventPlusString::rtti1,112,_ZNK4ksys4util4Task27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE +0x00000071011f861c,EventPlusString::rtti2,92,_ZNK4ksys4util4Task18getRuntimeTypeInfoEv +0x00000071011f8678,sub_71011F8678,112,_ZNK4ksys4util25TaskRemoveCallbackContext27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE +0x00000071011f86e8,sub_71011F86E8,92,_ZNK4ksys4util25TaskRemoveCallbackContext18getRuntimeTypeInfoEv +0x00000071011f8744,j__ZdlPv_1228,4,_ZN4ksys4util25TaskRemoveCallbackContextD0Ev +0x00000071011f8748,sub_71011F8748,112,_ZNK4ksys4util18TaskPostRunContext27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE +0x00000071011f87b8,sub_71011F87B8,92,_ZNK4ksys4util18TaskPostRunContext18getRuntimeTypeInfoEv +0x00000071011f8814,j__ZdlPv_1229,4,_ZN4ksys4util18TaskPostRunContextD0Ev 0x00000071011f8818,WorkerThread::ctor,172, 0x00000071011f88c4,WorkerThread::dtor,80, 0x00000071011f8914,WorkerThread::deleteElements,196, @@ -94426,14 +94428,14 @@ 0x00000071012fd5f0,nullsub_4849,4, 0x00000071012fd5f4,j__ZdlPv_1323,4, 0x00000071012fd5f8,sub_71012FD5F8,532, -0x00000071012fd80c,ThreadD0::ctor,60, -0x00000071012fd848,sub_71012FD848,52, -0x00000071012fd87c,sub_71012FD87C,60, -0x00000071012fd8b8,sub_71012FD8B8,8, -0x00000071012fd8c0,_ZN4sead15DrawLockContext6unlockEv,8, -0x00000071012fd8c8,sub_71012FD8C8,204, -0x00000071012fd994,sub_71012FD994,92, -0x00000071012fd9f0,sub_71012FD9F0,140, +0x00000071012fd80c,ThreadD0::ctor,60,_ZN4ksys4util9TaskQueueC1EPN4sead4HeapE +0x00000071012fd848,sub_71012FD848,52,_ZN4ksys4util9TaskQueueD2Ev +0x00000071012fd87c,sub_71012FD87C,60,_ZN4ksys4util9TaskQueueD0Ev +0x00000071012fd8b8,sub_71012FD8B8,8,_ZNK4ksys4util9TaskQueue4lockEv +0x00000071012fd8c0,_ZNK4ksys4util9TaskQueue6unlockEv,8,_ZNK4ksys4util9TaskQueue6unlockEv +0x00000071012fd8c8,sub_71012FD8C8,204,_ZNK4ksys4util9TaskQueue27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE +0x00000071012fd994,sub_71012FD994,92,_ZNK4ksys4util9TaskQueue18getRuntimeTypeInfoEv +0x00000071012fd9f0,sub_71012FD9F0,140,_ZNK4sead15RuntimeTypeInfo6DeriveIN4ksys4util13TaskQueueBaseEE9isDerivedEPKNS0_9InterfaceE 0x00000071012fda7c,sub_71012FDA7C,488, 0x00000071012fdc64,sub_71012FDC64,528, 0x00000071012fde74,sub_71012FDE74,72, diff --git a/lib/sead b/lib/sead index 9e500212..26b88aa2 160000 --- a/lib/sead +++ b/lib/sead @@ -1 +1 @@ -Subproject commit 9e500212341ace1ecd1d970581d4e37b858bea57 +Subproject commit 26b88aa2275b7c39d8b0898f0c77567b37ad6c11 diff --git a/src/KingSystem/Utils/Thread/Task.cpp b/src/KingSystem/Utils/Thread/Task.cpp new file mode 100644 index 00000000..7ab00b55 --- /dev/null +++ b/src/KingSystem/Utils/Thread/Task.cpp @@ -0,0 +1,277 @@ +#include "KingSystem/Utils/Thread/Task.h" +#include +#include "KingSystem/Utils/Thread/TaskQueueBase.h" +#include "KingSystem/Utils/Thread/TaskQueueLock.h" +#include "KingSystem/Utils/Thread/TaskThread.h" + +namespace ksys::util { + +TaskDelegateSetter::TaskDelegateSetter() = default; + +TaskDelegateSetter::~TaskDelegateSetter() = default; + +void TaskDelegateSetter::setDelegate(TaskDelegate* delegate) { + mDelegate = delegate; +} + +Task::Task(sead::Heap* heap) : mEvent(heap, true) { + mEvent.setSignal(); +} + +Task::Task(sead::Heap* heap, sead::IDisposer::HeapNullOption heap_null_option) + : mEvent(heap, heap_null_option, true) { + mEvent.setSignal(); +} + +Task::~Task() { + finalize_(); +} + +void Task::deleteDelegate_() { + if (mDelegate && mFlags.isOn(Flag::DeleteDelegate) && mFlags.isOff(Flag::DoNotDeleteDelegate)) { + delete mDelegate; + mDelegate = nullptr; + } +} + +// NON_MATCHING: mDelegate2 = nullptr store +void Task::finalize_() { + if (mStatus == Status::Finalized) + return; + + removeFromQueue(); + deleteDelegate_(); + mUserData = nullptr; + mQueue = nullptr; + mPostRunCallback = nullptr; + mRemoveCallback = nullptr; + mStatus = Status::Finalized; +} + +bool Task::setDelegate(const TaskDelegateSetter& setter) { + mDelegate = setter.getDelegate(); + mFlags.reset(Flag::DeleteDelegate); + mFlags.reset(Flag::DoNotDeleteDelegate); + mFlags.set(Flag::DoNotDeleteDelegate); + return onSetDelegate_(setter); +} + +// NON_MATCHING: branching +bool Task::submitRequest(TaskRequest& request) { + // Processing this request is impossible if there is no thread *and* no queue! + if (request.mThread == nullptr && request.mQueue == nullptr) + return false; + + if (!canSubmitRequest()) + return false; + + if (request.mSynchronous || request.mHasHandle) + mFlags.set(Flag::NeedsToSignalEvent); + else + mFlags.reset(Flag::NeedsToSignalEvent); + + mFlags.change(Flag::SynchronousRequest, request.mSynchronous); + + if (mListNode.isLinked()) + return false; + + if (mFlags.isOn(Flag::NeedsToSignalEvent)) + mEvent.resetSignal(); + + mQueue = request.mQueue; + if (!mQueue) { + mQueue = request.mThread->getTaskQueue(); + request.mQueue = mQueue; + } + mUserData = request.mUserData; + if (auto* delegate = request.mDelegate) { + deleteDelegate_(); + mFlags.set(Flag::DoNotDeleteDelegate); + mDelegate = delegate; + } + mRemoveCallback = request.mRemoveCallback; + mPostRunCallback = request.mPostRunCallback; + mName = request.mName; + + prepare_(&request); + + if (request.mSynchronous) { + auto* thread = mQueue->getCurrentThread(); + if (thread) { + processOnCurrentThreadDirectly(thread); + return true; + } + } + + TaskQueueBase::PushArg arg; + arg.lane_id = request.mLaneId; + arg.task = this; + const bool push_ok = mQueue->push(arg); + bool b; + if (push_ok) { + if (request.mSynchronous) + mEvent.wait(); + b = true; + } else { + b = false; + } + return push_ok || b; +} + +bool Task::canSubmitRequest() const { + const bool run_finished_on_current_thread = + mThread && mStatus == Status::RunFinished && + mThread == sead::ThreadMgr::instance()->getCurrentThread(); + const bool cond2 = isInactive(); + return run_finished_on_current_thread || cond2; +} + +void Task::processOnCurrentThreadDirectly(TaskThread* thread) { + { + TaskQueueLock lock{thread}; + mThread = thread; + mStatus = Status::Pushed; + } + + run(); + + { + TaskQueueLock lock{thread}; + onRunFinished(); + } + + TaskPostRunResult result; + invokePostRunCallback(&result); + + { + TaskQueueLock lock{thread}; + if (!result.getResult()) + finish(); + } +} + +void Task::removeFromQueue() { + if (mQueue) + mQueue->removeTask(this, true); +} + +void Task::removeFromQueue2() { + // TODO: how does this differ from removeFromQueue? + removeFromQueue(); +} + +void Task::run_() { + if (mDelegate) + mDelegateResult = (*mDelegate)(mUserData); +} + +bool Task::wait() { + mEvent.wait(); + return true; +} + +bool Task::wait(const sead::TickSpan& span) { + return mEvent.wait(span); +} + +u8 Task::getLaneId() const { + return mLaneId; +} + +bool Task::isSuccess() const { + return (mStatus == Status::PreFinishCallback || mStatus == Status::RunFinished || + mStatus == Status::PostFinishCallback) && + mDelegateResult; +} + +bool Task::isInactive() const { + return mStatus == Status::Uninitialized || mStatus == Status::RemovedFromQueue || + mStatus == Status::PostFinishCallback; +} + +void Task::setStatusPushed() { + mStatus = Status::Pushed; +} + +void Task::setThread(TaskThread* thread) { + mThread = thread; +} + +void Task::run() { + run_(); + mStatus = Status::RunFinished; +} + +void Task::onRunFinished() { + onRunFinished_(); +} + +void Task::invokePostRunCallback(TaskPostRunResult* result) { + mRemoveCallback = nullptr; + TaskPostRunContext context; + context.mCancelled = mFlags.isOn(Flag::Cancelled); + context.mTask = this; + context.mUserData = mUserData; + if (auto* delegate = mPostRunCallback) { + mPostRunCallback = nullptr; + delegate->invoke(result, context); + } +} + +void Task::finish() { + mStatus = Status::PreFinishCallback; + onFinish_(); + mStatus = Status::PostFinishCallback; + + mThread = nullptr; + signalEvent(); + + onPostFinish_(); +} + +void* Task::getUserData() const { + return mUserData; +} + +void Task::cancel() { + mEvent.resetSignal(); + mFlags.set(Flag::Cancelled); + mFlags.set(Flag::NeedsToSignalEvent); +} + +void Task::onRemove() { + invokeRemoveCallback_(); + + TaskQueueLock lock; + mQueue->lock(&lock); + + preRemove_(); + + mStatus = Status::RemovedFromQueue; + mThread = nullptr; + signalEvent(); + + postRemove_(); +} + +void Task::invokeRemoveCallback_() { + mPostRunCallback = nullptr; + TaskRemoveCallbackContext context; + context.mTask = this; + context.mUserData = mUserData; + + if (auto* delegate = mRemoveCallback) { + mRemoveCallback = nullptr; + delegate->invoke(context); + } +} + +void Task::setStatusFetched() { + mStatus = Status::Fetched; +} + +void Task::setLaneId(u8 id) { + mLaneId = id; +} + +} // namespace ksys::util diff --git a/src/KingSystem/Utils/Thread/Task.h b/src/KingSystem/Utils/Thread/Task.h new file mode 100644 index 00000000..df54db8e --- /dev/null +++ b/src/KingSystem/Utils/Thread/Task.h @@ -0,0 +1,193 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include "KingSystem/Utils/Thread/Event.h" +#include "KingSystem/Utils/Types.h" + +namespace ksys::util { + +class Task; +class TaskQueueBase; +class TaskRequest; +class TaskThread; + +class TaskPostRunResult { + SEAD_RTTI_BASE(TaskPostRunResult) +public: + virtual ~TaskPostRunResult() = default; + + bool getResult() const { return mResult; } + void setResult(bool result) { mResult = result; } + +private: + bool mResult = false; +}; +KSYS_CHECK_SIZE_NX150(TaskPostRunResult, 0x10); + +class TaskPostRunContext { + SEAD_RTTI_BASE(TaskPostRunContext) +public: + virtual ~TaskPostRunContext() = default; + + bool mCancelled; + Task* mTask; + void* mUserData; +}; +KSYS_CHECK_SIZE_NX150(TaskPostRunContext, 0x20); + +class TaskRemoveCallbackContext { + SEAD_RTTI_BASE(TaskRemoveCallbackContext) +public: + virtual ~TaskRemoveCallbackContext() = default; + + Task* mTask; + void* mUserData; +}; +KSYS_CHECK_SIZE_NX150(TaskRemoveCallbackContext, 0x18); + +using TaskDelegate = sead::AnyDelegate1R; +using TaskPostRunCallback = sead::IDelegate2; +using TaskRemoveCallback = sead::IDelegate1; + +class TaskDelegateSetter { + SEAD_RTTI_BASE(TaskDelegateSetter) +public: + TaskDelegateSetter(); + explicit TaskDelegateSetter(TaskDelegate* delegate) : TaskDelegateSetter() { + setDelegate(delegate); + } + virtual ~TaskDelegateSetter(); + TaskDelegate* getDelegate() const { return mDelegate; } + void setDelegate(TaskDelegate* delegate); + +private: + TaskDelegate* mDelegate = nullptr; +}; +KSYS_CHECK_SIZE_NX150(TaskDelegateSetter, 0x10); + +class TaskRequest { + SEAD_RTTI_BASE(TaskRequest) +public: + virtual ~TaskRequest() = default; + + bool mHasHandle; + /// If true, request submissions will block until the request is processed. + bool mSynchronous; + u8 mLaneId; + TaskThread* mThread; + TaskQueueBase* mQueue; + TaskDelegate* mDelegate; + void* mUserData; + TaskRemoveCallback* mRemoveCallback; + TaskPostRunCallback* mPostRunCallback; + sead::SafeString mName; +}; +KSYS_CHECK_SIZE_NX150(TaskRequest, 0x50); + +class Task { + SEAD_RTTI_BASE(Task) +public: + enum class Status { + Uninitialized = 0, + RemovedFromQueue = 1, + Pushed = 2, + Fetched = 3, + PreFinishCallback = 4, + RunFinished = 5, + PostFinishCallback = 6, + Finalized = 7, + }; + + explicit Task(sead::Heap* heap); + Task(sead::Heap* heap, sead::IDisposer::HeapNullOption heap_null_option); + virtual ~Task(); + + bool setDelegate(const TaskDelegateSetter& setter); + bool submitRequest(TaskRequest& request); + bool canSubmitRequest() const; + void processOnCurrentThreadDirectly(TaskThread* thread); + + void removeFromQueue(); + void removeFromQueue2(); + + void cancel(); + bool wait(); + bool wait(const sead::TickSpan& span); + + Status getStatus() const { return mStatus; } + bool isSuccess() const; + bool isInactive() const; + + u8 getLaneId() const; + void* getUserData() const; + TaskQueueBase* getQueue() const { return mQueue; } + +protected: + friend class TaskQueueBase; + friend class TaskThread; + + enum class Flag { + DeleteDelegate = 0x1, + DoNotDeleteDelegate = 0x2, + NeedsToSignalEvent = 0x4, + SynchronousRequest = 0x8, + Cancelled = 0x10, + }; + + static size_t getListNodeOffset() { return offsetof(Task, mListNode); } + + virtual bool onSetDelegate_(const TaskDelegateSetter&) { return true; } + virtual void prepare_(TaskRequest* request); + virtual void run_(); + virtual void onRunFinished_() {} + virtual void onFinish_() {} + virtual void onPostFinish_() {} + virtual void preRemove_() {} + virtual void postRemove_() {} + + void setLaneId(u8 id); + void setThread(TaskThread* thread); + void setStatusPushed(); + void setStatusFetched(); + void run(); + void onRunFinished(); + void invokePostRunCallback(TaskPostRunResult* result); + void finish(); + void onRemove(); + + void finalize_(); + void deleteDelegate_(); + void invokeRemoveCallback_(); + + void signalEvent() { + if (!mFlags.isOn(Flag::NeedsToSignalEvent)) + return; + + mFlags.reset(Flag::Cancelled); + mEvent.setSignal(); + } + + u8 mLaneId = 0; + sead::TypedBitFlag mFlags = Flag::DoNotDeleteDelegate; + bool mDelegateResult = false; + TaskDelegate* mDelegate = nullptr; + void* mUserData = nullptr; + TaskQueueBase* mQueue = nullptr; + TaskThread* mThread = nullptr; + TaskPostRunCallback* mPostRunCallback = nullptr; + TaskRemoveCallback* mRemoveCallback = nullptr; + Status mStatus = Status::Uninitialized; + sead::ListNode mListNode; + Event mEvent; + sead::SafeString mName; +}; +KSYS_CHECK_SIZE_NX150(Task, 0xa8); + +inline void Task::prepare_(TaskRequest*) {} + +} // namespace ksys::util diff --git a/src/KingSystem/Utils/Thread/TaskQueue.cpp b/src/KingSystem/Utils/Thread/TaskQueue.cpp new file mode 100644 index 00000000..cf76c768 --- /dev/null +++ b/src/KingSystem/Utils/Thread/TaskQueue.cpp @@ -0,0 +1,7 @@ +#include "KingSystem/Utils/Thread/TaskQueue.h" + +namespace ksys::util { + +TaskQueue::TaskQueue(sead::Heap* heap) : TaskQueueBase(heap), mCS(heap) {} + +} // namespace ksys::util diff --git a/src/KingSystem/Utils/Thread/TaskQueue.h b/src/KingSystem/Utils/Thread/TaskQueue.h new file mode 100644 index 00000000..6792a783 --- /dev/null +++ b/src/KingSystem/Utils/Thread/TaskQueue.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include "KingSystem/Utils/Thread/TaskQueueBase.h" + +namespace ksys::util { + +class TaskQueue : public TaskQueueBase { + SEAD_RTTI_OVERRIDE(TaskQueue, TaskQueueBase) +public: + explicit TaskQueue(sead::Heap* heap); + +private: + void lock() const override { mCS.lock(); } + void unlock() const override { mCS.unlock(); } + + mutable sead::CriticalSection mCS; +}; +KSYS_CHECK_SIZE_NX150(TaskQueue, 0xd0); + +} // namespace ksys::util diff --git a/src/KingSystem/Utils/Thread/TaskQueueBase.cpp b/src/KingSystem/Utils/Thread/TaskQueueBase.cpp new file mode 100644 index 00000000..430fdbf2 --- /dev/null +++ b/src/KingSystem/Utils/Thread/TaskQueueBase.cpp @@ -0,0 +1,491 @@ +#include "KingSystem/Utils/Thread/TaskQueueBase.h" +#include +#include +#include +#include "KingSystem/Utils/Debug.h" +#include "KingSystem/Utils/Thread/Task.h" +#include "KingSystem/Utils/Thread/TaskQueueLock.h" +#include "KingSystem/Utils/Thread/TaskThread.h" + +namespace ksys::util { + +static const auto cSleepSpan = sead::TickSpan::fromMicroSeconds(10); + +TaskQueueBase::TaskQueueBase(sead::Heap* heap) : mQueueEmptyEvent(heap) { + mActiveTasks.initOffset(Task::getListNodeOffset()); +} + +TaskQueueBase::~TaskQueueBase() { + clear(); + + for (auto& lane : mLanes) { + delete lane.lane_empty_event; + lane.lane_empty_event = nullptr; + } + + mLanes.freeBuffer(); + mThreads.freeBuffer(); +} + +void TaskQueueBase::clear() { + lock(); + + // Clear all tasks. + for (auto it = mActiveTasks.robustBegin(), end = mActiveTasks.robustEnd(); it != end; ++it) { + mActiveTasks.erase(std::addressof(*it)); + it->onRemove(); + } + mActiveTasks.clear(); + + for (auto& lane : mLanes) + lane.head_task = nullptr; + + const bool is_any_thread_busy = isAnyThreadBusy(); + + signalEmptyEventsIfNeeded(); + { + ConditionalScopedLock lock{this}; + ScopedLock lock1{this}; + for (auto& thread : mThreads) { + thread.cancelCurrentTask(); + } + } + + unlock(); + + if (is_any_thread_busy) + mQueueEmptyEvent.wait(); +} + +// NON_MATCHING: swapped operands for a csel. The arg.set_flag1 check looks suspicious. +bool TaskQueueBase::init(const InitArg& arg) { + if (arg.max_num_threads == 0) + return false; + + if (!mThreads.tryAllocBuffer(arg.max_num_threads, arg.heap)) + return false; + + if (!arg.enable_locks) + mFlags.reset(Flag::Lock); + else + mFlags.set(Flag::Lock); + + if (arg.num_lanes <= 0 || arg.num_lanes > 0x100) + return false; + + mLanes.allocBufferAssert(arg.num_lanes, arg.heap); + for (auto& lane : mLanes) { + lane.lane_empty_event = new (arg.heap) Event(arg.heap, true); + lane.lane_empty_event->setSignal(); + } + + mQueueEmptyEvent.initialize(true); + mQueueEmptyEvent.setSignal(); + mTaskSelectionDelegate = arg.task_selection_delegate; + + return true; +} + +bool TaskQueueBase::addThread(TaskThread* thread) { + if (mFlags.isOn(Flag::PreventThreadPoolChanges)) + return false; + + lockIfNeeded(); + + if (mThreads.isFull()) { + unlockIfNeeded(); + return false; + } + + mThreads.pushBack(thread); + unlockIfNeeded(); + return true; +} + +void TaskQueueBase::removeThread(TaskThread* thread) { + if (mFlags.isOn(Flag::PreventThreadPoolChanges)) + return; + + ConditionalScopedLock lock{this}; + mThreads.erase(mThreads.search(thread)); +} + +s32 TaskQueueBase::getNumActiveTasks() const { + return mActiveTasks.size(); +} + +s32 TaskQueueBase::countTasksInLane(u16 id) const { + lock(); + + if (!mLanes[id].head_task) { + unlock(); + return 0; + } + + s32 count = 0; + for (auto i = mActiveTasks.begin(mLanes[id].head_task), end = mActiveTasks.end(); i != end; + ++i) { + if (i->getLaneId() != id) + break; + ++count; + } + unlock(); + return count; +} + +bool TaskQueueBase::areNoThreadsBusy() const { + ScopedLock lock{this}; + + if (!mActiveTasks.isEmpty()) + return false; + return !isAnyThreadBusy(); +} + +bool TaskQueueBase::isAnyThreadBusy() const { + ConditionalScopedLock lock{this}; + return std::any_of(mThreads.begin(), mThreads.end(), + [](const TaskThread& thread) { return thread.isBusyProcessingTask(); }); +} + +bool TaskQueueBase::areAllThreadsPaused() const { + ConditionalScopedLock lock{this}; + return std::all_of(mThreads.begin(), mThreads.end(), + [](const TaskThread& thread) { return thread.isPaused(); }); +} + +void TaskQueueBase::waitForQueueToEmpty() { + if (areAllThreadsPaused()) + return; + + for (const auto& lane : mLanes) { + if (lane.blocked && lane.head_task) + return; + } + + mQueueEmptyEvent.wait(); +} + +void TaskQueueBase::waitForLaneToEmpty(u8 id) { + if (areAllThreadsPaused()) + return; + + const auto& lane = mLanes[id]; + if (!lane.blocked || !lane.head_task) + lane.lane_empty_event->wait(); +} + +void TaskQueueBase::cancelTasks(u8 id) { + lock(); + + if (mLanes[id].head_task) { + for (auto it = mActiveTasks.robustBegin(mLanes[id].head_task), + end = mActiveTasks.robustEnd(); + it != end; ++it) { + if (it->getLaneId() != id) + break; + mActiveTasks.erase(std::addressof(*it)); + it->onRemove(); + } + } + mLanes[id].head_task = nullptr; + + const auto cancel_current_tasks_if_needed = [&] { + ConditionalScopedLock lock{this}; + ScopedLock lock1{this}; + for (auto it = mThreads.begin(), end = mThreads.end(); it != end; ++it) { + if (it->mTask && it->mTask->getLaneId() == id) + it->cancelCurrentTask(); + } + }; + + if (isProcessingTask(id)) { + mLanes[id].lane_empty_event->resetSignal(); + signalEmptyEventsIfNeeded(); + cancel_current_tasks_if_needed(); + unlock(); + mLanes[id].lane_empty_event->wait(); + } else { + signalEmptyEventsIfNeeded(); + cancel_current_tasks_if_needed(); + unlock(); + } +} + +bool TaskQueueBase::isProcessingTask(u8 id) const { + ConditionalScopedLock lock{this}; + ScopedLock lock1{this}; + return std::any_of(mThreads.begin(), mThreads.end(), [id](const TaskThread& thread) { + return thread.mTask && thread.mTask->getLaneId() == id; + }); +} + +void TaskQueueBase::signalEmptyEventsIfNeeded() { + ScopedLock lock{this}; + + const bool is_any_thread_busy = isAnyThreadBusy(); + const bool has_no_tasks = mActiveTasks.isEmpty(); + if (!is_any_thread_busy && has_no_tasks) + mQueueEmptyEvent.setSignal(); + + for (auto it = mLanes.begin(), end = mLanes.end(); it != end; ++it) { + if (!isProcessingTask(it.getIndex()) && it->head_task == nullptr) + it->lane_empty_event->setSignal(); + } +} + +void TaskQueueBase::blockTasks(u8 id) { + if (mLanes[id].blocked != 1) + mLanes[id].blocked = true; +} + +// NON_MATCHING: the while (!areAllThreadsPaused()) loop generates weird code in the original +void TaskQueueBase::blockTasksAndReloadThreads(u8 id) { + blockTasks(id); + + { + ConditionalScopedLock lock{this}; + for (auto& thread : mThreads) + thread.pause(); + } + + const auto sleep_duration = sead::TickSpan::fromMilliSeconds(1); + + while (!areAllThreadsPaused()) + sead::Thread::sleep(sleep_duration); + + sead::Thread::sleep(sleep_duration); + + { + ConditionalScopedLock lock{this}; + for (auto& thread : mThreads) + thread.resume(); + } +} + +void TaskQueueBase::unblockTasks(u8 id) { + if (mLanes[id].blocked) { + mLanes[id].blocked = false; + notifyThreadsForNewTasks(); + } +} + +void TaskQueueBase::lock(TaskQueueLock* lock) { + lock->lock(this); +} + +TaskThread* TaskQueueBase::getCurrentThread() const { + const sead::Thread* current_thread = sead::ThreadMgr::instance()->getCurrentThread(); + lockIfNeeded(); + for (auto it = mThreads.begin(), end = mThreads.end(); it != end; ++it) { + if (current_thread == std::addressof(*it)) { + unlockIfNeeded(); + return std::addressof(*it); + } + } + unlockIfNeeded(); + return nullptr; +} + +sead::OffsetList::iterator TaskQueueBase::activeTasksBegin(TaskQueueLock* lock) { + lock->lock(this); + return mActiveTasks.begin(); +} + +sead::OffsetList::robustIterator TaskQueueBase::activeTasksRobustBegin(TaskQueueLock* lock) { + lock->lock(this); + return mActiveTasks.robustBegin(); +} + +sead::OffsetList::iterator TaskQueueBase::activeTasksEnd() const { + return mActiveTasks.end(); +} + +sead::OffsetList::robustIterator TaskQueueBase::activeTasksRobustEnd() const { + return mActiveTasks.robustEnd(); +} + +void TaskQueueBase::notifyThreadsForNewTasks() { + s32 retry_count = 0; + const sead::Thread* current_thread = sead::ThreadMgr::instance()->getCurrentThread(); + sead::BitFlag32 mask = 0; + + while (true) { + lockIfNeeded(); + bool done = true; + s32 i = 0; + auto* data = mThreads.data(); + for (auto& thread : mThreads) { + static_cast(thread); + if (current_thread != data[i] && !data[i]->isLookingForTask() && + !data[i]->receivedQueueUpdatedMsg() && !data[i]->receivedPauseMsg() && + !data[i]->receivedResumeMsg() && !data[i]->receivedQuitMsg() && !mask.isOnBit(i)) { + const bool send_ok = data[i]->sendMessage( + TaskThread::cMessage_QueueUpdated, sead::MessageQueue::BlockType::NonBlocking); + if (send_ok) + mask.setBit(i); + done &= send_ok; + } + ++i; + } + unlockIfNeeded(); + + if (done) + break; + + ++retry_count; + sead::Thread::sleep(cSleepSpan); + } + + if (retry_count >= 2) + PrintDebug(sead::FormatFixedSafeString<128>("↓↓↓\nリトライ回数 %d 回\n↑↑↑\n", retry_count)); +} + +// NON_MATCHING: regalloc for max_idx +bool TaskQueueBase::push(const PushArg& arg) { + lock(); + + if (!arg.task || mActiveTasks.isNodeLinked(arg.task)) { + unlock(); + return false; + } + + const auto num_tasks = mActiveTasks.size(); + const u8 max_idx = mLanes.size() - 1; + const u8 id = arg.lane_id <= max_idx ? arg.lane_id : max_idx; + arg.task->setLaneId(id); + + bool added = false; + for (u8 i = id - 1; i != 0xff; --i) { + if (!mLanes[i].head_task) + continue; + + mActiveTasks.insertBefore(mLanes[i].head_task, arg.task); + added = true; + break; + } + + if (!added) { + mActiveTasks.pushBack(arg.task); + mLanes[id].lane_empty_event->resetSignal(); + } + + if (!mLanes[id].head_task) + mLanes[id].head_task = arg.task; + + arg.task->setStatusPushed(); + + if (num_tasks == 0) + mQueueEmptyEvent.resetSignal(); + + unlock(); + notifyThreadsForNewTasks(); + return true; +} + +void TaskQueueBase::removeTask(Task* task, bool b) { + if (!task) + return; + + lock(); + + if (!task->isInactive()) { + if (task->getStatus() == Task::Status::Pushed) { + const u8 id = task->getLaneId(); + if (mLanes[id].head_task == task) { + auto* new_task = mActiveTasks.next(task); + if (new_task && task->getLaneId() == new_task->getLaneId()) + mLanes[id].head_task = new_task; + else + mLanes[id].head_task = nullptr; + } + + mActiveTasks.erase(task); + task->onRemove(); + signalEmptyEventsIfNeeded(); + } else if (b) { + task->cancel(); + unlock(); + task->wait(); + return; + } + } + + unlock(); +} + +// NON_MATCHING: regalloc inside the task lambda + reorderings for the loop counters. +void TaskQueueBase::fetchTask(Task** out_task) { + lock(); + + const auto check_state = [&] { + if (!mActiveTasks.isEmpty() || isAnyThreadBusy()) + return true; + mQueueEmptyEvent.setSignal(); + *out_task = nullptr; + unlock(); + return false; + }; + + if (!check_state()) + return; + + auto* task = [&]() -> Task* { + for (auto it = mLanes.rbegin(), end = mLanes.rend(); it != end; ++it) { + if (it->blocked) + continue; + if (it->head_task == nullptr) + continue; + if (!mTaskSelectionDelegate) + return it->head_task; + + const auto it_begin = mActiveTasks.begin(it->head_task); + Task* end_ptr = nullptr; + for (auto it2 = it; it2 != mLanes.rbegin(0);) { + // XXX: This looks really weird. + auto* t = std::addressof(*it2)[-1].head_task; + ++it2; + if (t) { + if (it2->head_task) + end_ptr = it2->head_task; + break; + } + } + const auto it_end = end_ptr ? mActiveTasks.begin(end_ptr) : mActiveTasks.end(); + + TaskSelectionContext context; + context.lane_id = it->head_task->getLaneId(); + context.it_begin = &it_begin; + context.it_end = &it_end; + Task* task = mTaskSelectionDelegate->invoke(context); + if (task) + return task; + } + + return nullptr; + }(); + + if (!check_state()) + return; + + if (task) { + for (u8 id = mLanes.size() - 1; id != 0xff; --id) { + if (mLanes[id].head_task == task) { + auto* new_task = mActiveTasks.next(task); + if (new_task && task->getLaneId() == new_task->getLaneId()) + mLanes[id].head_task = new_task; + else + mLanes[id].head_task = nullptr; + break; + } + } + mActiveTasks.erase(task); + task->setStatusFetched(); + *out_task = task; + } else { + *out_task = nullptr; + } + + unlock(); +} + +} // namespace ksys::util diff --git a/src/KingSystem/Utils/Thread/TaskQueueBase.h b/src/KingSystem/Utils/Thread/TaskQueueBase.h new file mode 100644 index 00000000..3d4b44cf --- /dev/null +++ b/src/KingSystem/Utils/Thread/TaskQueueBase.h @@ -0,0 +1,157 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include