ksys: Add Task utilities

This commit is contained in:
Léo Lam 2020-09-10 22:11:27 +02:00
parent c5ef0a1fd3
commit 8b7369dffb
No known key found for this signature in database
GPG Key ID: 0DF30F9081000741
13 changed files with 1707 additions and 125 deletions

View File

@ -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

View File

@ -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,

Can't render this file because it is too large.

@ -1 +1 @@
Subproject commit 9e500212341ace1ecd1d970581d4e37b858bea57
Subproject commit 26b88aa2275b7c39d8b0898f0c77567b37ad6c11

View File

@ -0,0 +1,277 @@
#include "KingSystem/Utils/Thread/Task.h"
#include <thread/seadThread.h>
#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

View File

@ -0,0 +1,193 @@
#pragma once
#include <basis/seadTypes.h>
#include <container/seadListImpl.h>
#include <prim/seadDelegate.h>
#include <prim/seadRuntimeTypeInfo.h>
#include <prim/seadSafeString.h>
#include <prim/seadTypedBitFlag.h>
#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<void*, bool>;
using TaskPostRunCallback = sead::IDelegate2<TaskPostRunResult*, const TaskPostRunContext&>;
using TaskRemoveCallback = sead::IDelegate1<const TaskRemoveCallbackContext&>;
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<Flag, u8> 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

View File

@ -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

View File

@ -0,0 +1,21 @@
#pragma once
#include <thread/seadCriticalSection.h>
#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

View File

@ -0,0 +1,491 @@
#include "KingSystem/Utils/Thread/TaskQueueBase.h"
#include <algorithm>
#include <memory>
#include <thread/seadThread.h>
#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<Task>::iterator TaskQueueBase::activeTasksBegin(TaskQueueLock* lock) {
lock->lock(this);
return mActiveTasks.begin();
}
sead::OffsetList<Task>::robustIterator TaskQueueBase::activeTasksRobustBegin(TaskQueueLock* lock) {
lock->lock(this);
return mActiveTasks.robustBegin();
}
sead::OffsetList<Task>::iterator TaskQueueBase::activeTasksEnd() const {
return mActiveTasks.end();
}
sead::OffsetList<Task>::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<void>(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

View File

@ -0,0 +1,157 @@
#pragma once
#include <basis/seadTypes.h>
#include <container/seadBuffer.h>
#include <container/seadOffsetList.h>
#include <container/seadPtrArray.h>
#include <prim/seadDelegate.h>
#include <prim/seadRuntimeTypeInfo.h>
#include <prim/seadTypedBitFlag.h>
#include <time/seadTickSpan.h>
#include "KingSystem/Utils/Thread/Event.h"
#include "KingSystem/Utils/Types.h"
namespace ksys::util {
class Task;
class TaskQueueLock;
class TaskThread;
struct TaskSelectionContext {
const auto& begin() const { return *it_begin; }
const auto& end() const { return *it_end; }
u8 lane_id;
const sead::OffsetList<Task>::iterator* it_begin;
const sead::OffsetList<Task>::iterator* it_end;
};
using TaskSelectionDelegate = sead::IDelegate1R<const TaskSelectionContext&, Task*>;
class TaskQueueBase {
SEAD_RTTI_BASE(TaskQueueBase)
public:
struct InitArg {
bool enable_locks;
/// Number of lanes.
u16 num_lanes;
/// Maximum number of threads that will be processing the queue.
u16 max_num_threads;
sead::Heap* heap;
TaskSelectionDelegate* task_selection_delegate;
};
KSYS_CHECK_SIZE_NX150(InitArg, 0x18);
struct PushArg {
u8 lane_id;
Task* task;
};
KSYS_CHECK_SIZE_NX150(PushArg, 0x10);
explicit TaskQueueBase(sead::Heap* heap);
virtual ~TaskQueueBase();
void clear();
bool init(const InitArg& arg);
bool addThread(TaskThread* thread);
void removeThread(TaskThread* thread);
s32 getNumActiveTasks() const;
s32 countTasksInLane(u16 id) const;
bool areNoThreadsBusy() const;
bool isAnyThreadBusy() const;
bool areAllThreadsPaused() const;
void waitForQueueToEmpty();
void waitForLaneToEmpty(u8 id);
void cancelTasks(u8 id);
bool isProcessingTask(u8 id) const;
void signalEmptyEventsIfNeeded();
void blockTasks(u8 id);
void blockTasksAndReloadThreads(u8 id);
void unblockTasks(u8 id);
void lock(TaskQueueLock* lock);
/// @returns the current thread if it is in the thread pool and nullptr otherwise.
TaskThread* getCurrentThread() const;
sead::OffsetList<Task>::iterator activeTasksBegin(TaskQueueLock* lock);
sead::OffsetList<Task>::robustIterator activeTasksRobustBegin(TaskQueueLock* lock);
sead::OffsetList<Task>::iterator activeTasksEnd() const;
sead::OffsetList<Task>::robustIterator activeTasksRobustEnd() const;
bool push(const PushArg& arg);
void removeTask(Task* task, bool b);
void fetchTask(Task** out_task);
protected:
enum class Flag {
Lock = 0x1,
PreventThreadPoolChanges = 0x2,
};
struct Lane {
/// If true, tasks in this lane are not allowed to be fetched by any thread.
bool blocked = false;
/// First task in the lane. Tasks are also added to a linked list (mActiveTasks).
Task* head_task = nullptr;
Event* lane_empty_event = nullptr;
};
KSYS_CHECK_SIZE_NX150(Lane, 0x18);
class ScopedLock {
public:
explicit ScopedLock(const TaskQueueBase* queue) : mQueue(queue) { mQueue->lock(); }
ScopedLock(const ScopedLock&) = delete;
~ScopedLock() { mQueue->unlock(); }
ScopedLock& operator=(const ScopedLock&) = delete;
private:
const TaskQueueBase* mQueue;
};
class ConditionalScopedLock {
public:
explicit ConditionalScopedLock(const TaskQueueBase* queue) : mQueue(queue) {
mQueue->lockIfNeeded();
}
ConditionalScopedLock(const ConditionalScopedLock&) = delete;
~ConditionalScopedLock() { mQueue->unlockIfNeeded(); }
ConditionalScopedLock& operator=(const ConditionalScopedLock&) = delete;
private:
const TaskQueueBase* mQueue;
};
friend class TaskQueueLock;
virtual void lock() const {}
virtual void unlock() const {}
bool shouldLock() const { return mFlags.isOn(Flag::Lock); }
void lockIfNeeded() const {
if (shouldLock())
lock();
}
void unlockIfNeeded() const {
if (shouldLock())
unlock();
}
void notifyThreadsForNewTasks();
sead::TypedBitFlag<Flag, u8> mFlags;
sead::OffsetList<Task> mActiveTasks;
sead::Buffer<Lane> mLanes;
Event mQueueEmptyEvent;
sead::PtrArray<TaskThread> mThreads;
TaskSelectionDelegate* mTaskSelectionDelegate = nullptr;
};
KSYS_CHECK_SIZE_NX150(TaskQueueBase, 0x90);
} // namespace ksys::util

View File

@ -0,0 +1,26 @@
#include "KingSystem/Utils/Thread/TaskQueueLock.h"
#include "KingSystem/Utils/Thread/TaskQueueBase.h"
namespace ksys::util {
TaskQueueLock::TaskQueueLock() = default;
TaskQueueLock::~TaskQueueLock() {
unlock();
}
void TaskQueueLock::lock(TaskQueueBase* queue) {
if (!mQueue) {
mQueue = queue;
mQueue->lock();
}
}
void TaskQueueLock::unlock() {
if (mQueue) {
mQueue->unlock();
mQueue = nullptr;
}
}
} // namespace ksys::util

View File

@ -0,0 +1,28 @@
#pragma once
#include <prim/seadRuntimeTypeInfo.h>
#include "KingSystem/Utils/Thread/TaskThread.h"
#include "KingSystem/Utils/Types.h"
namespace ksys::util {
class TaskQueueBase;
class TaskQueueLock {
SEAD_RTTI_BASE(TaskQueueLock)
public:
TaskQueueLock();
explicit TaskQueueLock(TaskThread* thread) : TaskQueueLock() { thread->lock(this); }
TaskQueueLock(const TaskQueueLock&) = delete;
virtual ~TaskQueueLock();
TaskQueueLock& operator=(const TaskQueueLock&) = delete;
void lock(TaskQueueBase* queue);
void unlock();
private:
TaskQueueBase* mQueue = nullptr;
};
KSYS_CHECK_SIZE_NX150(TaskQueueLock, 0x10);
} // namespace ksys::util

View File

@ -0,0 +1,261 @@
#include "KingSystem/Utils/Thread/TaskThread.h"
#include <thread/seadThread.h>
#include "KingSystem/Utils/Thread/Task.h"
#include "KingSystem/Utils/Thread/TaskQueue.h"
#include "KingSystem/Utils/Thread/TaskQueueLock.h"
namespace ksys::util {
TaskThread::TaskThread(const sead::SafeString& name, sead::Heap* heap, s32 priority,
sead::MessageQueue::BlockType block_type,
sead::MessageQueue::Element quit_msg, s32 stack_size, s32 message_queue_size)
: Thread(name, heap, priority, block_type, quit_msg, stack_size, message_queue_size),
mPauseResumeEvent(heap), mTaskProcessedEvent(heap) {}
TaskThread::~TaskThread() {
if (!mTaskQueue)
return;
mTaskQueue->removeThread(this);
if (mFlags.isOff(Flag::DoesNotOwnTaskQueue) && mTaskQueue) {
delete mTaskQueue;
mTaskQueue = nullptr;
}
}
bool TaskThread::init(const TaskThread::InitArg& arg) {
if (arg.queue) {
mTaskQueue = arg.queue;
mFlags.set(Flag::DoesNotOwnTaskQueue);
} else {
mTaskQueue = new (arg.heap) TaskQueue(arg.heap);
TaskQueueBase::InitArg queue_arg;
queue_arg.enable_locks = false;
queue_arg.task_selection_delegate = nullptr;
queue_arg.heap = arg.heap;
queue_arg.num_lanes = arg.num_lanes;
queue_arg.max_num_threads = 1;
mTaskQueue->init(queue_arg);
}
mTaskQueue->addThread(this);
mPauseResumeEvent.initialize(true);
mPauseResumeEvent.setSignal();
mTaskProcessedEvent.initialize(true);
mTaskProcessedEvent.setSignal();
mBatchSize = arg.batch_size;
return true;
}
s32 TaskThread::getNumActiveTasks() const {
return mTaskQueue->getNumActiveTasks();
}
void TaskThread::waitForQueueToEmpty() {
mTaskQueue->waitForQueueToEmpty();
}
void TaskThread::cancelTasks(u8 id) {
mTaskQueue->cancelTasks(id);
}
void TaskThread::clearQueue() {
mTaskQueue->clear();
}
void TaskThread::lock(TaskQueueLock* lock) {
mTaskQueue->lock(lock);
}
bool TaskThread::isActiveAndReceivedQueueUpdateMsg() const {
if (mFlags.isOn(Flag::Paused))
return false;
if (mFlags.isOn(Flag::IsActive))
return true;
return receivedQueueUpdatedMsg();
}
bool TaskThread::isPaused() const {
return mFlags.isOn(Flag::Paused);
}
bool TaskThread::receivedQueueUpdatedMsg() const {
return mMessageQueue.peek(sead::MessageQueue::BlockType::NonBlocking) == cMessage_QueueUpdated;
}
void TaskThread::pause() {
if (sead::ThreadMgr::instance()->getCurrentThread() == this)
return;
if (!mPauseResumeMsg.compareExchange(cMessage_Resume, cMessage_Pause))
return;
mPauseResumeEvent.wait();
mPauseResumeEvent.resetSignal();
mMessageQueue.jam(cMessage_Pause, sead::MessageQueue::BlockType::Blocking);
}
void TaskThread::pauseAndWaitForAck() {
if (sead::ThreadMgr::instance()->getCurrentThread() == this)
return;
pause();
mPauseResumeEvent.wait();
}
void TaskThread::resume() {
if (sead::ThreadMgr::instance()->getCurrentThread() == this)
return;
if (!mPauseResumeMsg.compareExchange(cMessage_Pause, cMessage_Resume))
return;
mPauseResumeEvent.wait();
mPauseResumeEvent.resetSignal();
mMessageQueue.jam(cMessage_Resume, sead::MessageQueue::BlockType::Blocking);
}
void TaskThread::resumeAndWaitForAck() {
if (sead::ThreadMgr::instance()->getCurrentThread() == this)
return;
resume();
mPauseResumeEvent.wait();
}
bool TaskThread::isBusyProcessingTask() const {
return mFlags.isOn(Flag::IsBusyProcessingTask);
}
bool TaskThread::isLookingForTask() const {
return mFlags.isOn(Flag::IsLookingForTask);
}
// NON_MATCHING: branching for `if (mTaskQueue->getNumActiveTasks() == 0)`:
// Clang got rid of the branch and merged the two mFlags writes
void TaskThread::calc_(sead::MessageQueue::Element msg) {
if (mFlags.isOn(Flag::Paused)) {
if (msg != cMessage_Resume)
return;
mFlags.reset(Flag::Paused);
mPauseResumeEvent.setSignal();
}
if (msg == cMessage_Pause) {
mPauseResumeEvent.setSignal();
mFlags.set(Flag::Paused);
return;
}
if (mBatchSize >= 1)
mNumRemainingTasksInBatch = mBatchSize;
while (true) {
{
TaskQueueLock lock{this};
const auto latest_msg = mMessageQueue.peek(sead::MessageQueue::BlockType::NonBlocking);
if (latest_msg == mQuitMsg) {
mFlags.reset(Flag::IsActive);
mFlags.reset(Flag::IsLookingForTask);
break;
}
if (latest_msg == cMessage_Pause) {
mFlags.reset(Flag::IsActive);
mFlags.reset(Flag::IsLookingForTask);
break;
}
mFlags.set(Flag::IsActive);
mFlags.set(Flag::IsLookingForTask);
mTaskQueue->fetchTask(&mTask);
mFlags.reset(Flag::IsLookingForTask);
if (mTask == nullptr) {
mFlags.reset(Flag::IsActive);
mFlags.reset(Flag::IsLookingForTask);
mTaskQueue->signalEmptyEventsIfNeeded();
break;
}
mFlags.reset(Flag::IsLookingForTask);
mFlags.set(Flag::IsBusyProcessingTask);
mTask->setThread(this);
}
mTask->run();
Task* task;
{
TaskQueueLock lock{this};
mTask->onRunFinished();
task = mTask;
mTask = nullptr;
}
if (task) {
TaskPostRunResult result;
task->invokePostRunCallback(&result);
TaskQueueLock lock{this};
if (!result.getResult())
task->finish();
mFlags.reset(Flag::IsBusyProcessingTask);
mTaskProcessedEvent.setSignal();
mTaskQueue->signalEmptyEventsIfNeeded();
if (mTaskQueue->getNumActiveTasks() == 0) {
mFlags.reset(Flag::IsActive);
#ifdef MATCHING_HACK_NX_CLANG
// To make it easier to see what this function is functionally equivalent.
// Does not fix the matching issue, but turns it into a 2-line reordering.
asm("" ::: "memory");
#endif
break;
}
mFlags.set(Flag::IsLookingForTask);
}
if (mBatchSize <= 0)
continue;
--mNumRemainingTasksInBatch;
if (mNumRemainingTasksInBatch == 0) {
sead::Thread::yield();
mNumRemainingTasksInBatch = mBatchSize;
}
}
mFlags.reset(Flag::IsActive);
mFlags.reset(Flag::IsLookingForTask);
}
bool TaskThread::receivedPauseMsg() const {
return mMessageQueue.peek(sead::MessageQueue::BlockType::NonBlocking) == cMessage_Pause;
}
bool TaskThread::receivedResumeMsg() const {
return mMessageQueue.peek(sead::MessageQueue::BlockType::NonBlocking) == cMessage_Resume;
}
bool TaskThread::receivedQuitMsg() const {
const auto msg = static_cast<s32>(mQuitMsg);
return mMessageQueue.peek(sead::MessageQueue::BlockType::NonBlocking) == msg;
}
void TaskThread::cancelCurrentTask() {
TaskQueueLock lock{this};
if (mTask)
mTask->cancel();
}
} // namespace ksys::util

View File

@ -0,0 +1,109 @@
#pragma once
#include <prim/seadRuntimeTypeInfo.h>
#include <prim/seadTypedBitFlag.h>
#include <thread/seadAtomic.h>
#include <thread/seadThread.h>
#include "KingSystem/Utils/Thread/Event.h"
#include "KingSystem/Utils/Types.h"
namespace ksys::util {
class Task;
class TaskQueueBase;
class TaskQueueLock;
class TaskThread : public sead::Thread {
SEAD_RTTI_BASE(TaskThread)
public:
enum Message {
cMessage_QueueUpdated = 1,
cMessage_Pause = 2,
cMessage_Resume = 3,
};
struct InitArg {
/// Number of lanes if a new queue is to be created.
/// Only used if queue is nullptr.
u16 num_lanes;
/// Number of tasks to process in a row before yielding. Can be zero to disable the limit.
u32 batch_size;
/// Heap that will be used to allocate a new queue if necessary.
/// Only used if queue is nullptr.
sead::Heap* heap;
/// Task queue. If null, a new queue will be created and owned by this thread.
TaskQueueBase* queue;
};
KSYS_CHECK_SIZE_NX150(InitArg, 0x18);
TaskThread(const sead::SafeString& name, sead::Heap* heap, s32 priority,
sead::MessageQueue::BlockType block_type, sead::MessageQueue::Element quit_msg,
s32 stack_size, s32 message_queue_size);
~TaskThread() override;
bool init(const InitArg& arg);
s32 getNumActiveTasks() const;
void waitForQueueToEmpty();
void cancelTasks(u8 id);
void clearQueue();
void lock(TaskQueueLock* lock);
bool isActiveAndReceivedQueueUpdateMsg() const;
bool isPaused() const;
bool receivedQueueUpdatedMsg() const;
void pause();
void pauseAndWaitForAck();
void resume();
void resumeAndWaitForAck();
bool isBusyProcessingTask() const;
bool isLookingForTask() const;
bool receivedPauseMsg() const;
bool receivedResumeMsg() const;
bool receivedQuitMsg() const;
void cancelCurrentTask();
TaskQueueBase* getTaskQueue() const { return mTaskQueue; }
protected:
friend class TaskQueueBase;
enum class Flag {
_1 = 0x1,
_2 = 0x2,
_4 = 0x4,
Paused = 0x8,
/// The task queue is *not* owned by this TaskThread.
DoesNotOwnTaskQueue = 0x10,
/// A batch is being processed.
IsActive = 0x20,
/// This thread is looking for a task to process.
IsLookingForTask = 0x40,
/// A task is being processed.
IsBusyProcessingTask = 0x80,
};
void calc_(sead::MessageQueue::Element msg) override;
sead::TypedBitFlag<Flag, u8> mFlags = [] {
decltype(mFlags) flags;
flags.set(Flag::_2);
flags.set(Flag::_4);
return flags;
}();
Task* mTask = nullptr;
s32 mBatchSize = 0;
s32 mNumRemainingTasksInBatch = 0;
sead::Atomic<Message> mPauseResumeMsg = cMessage_Resume;
Event mPauseResumeEvent;
Event mTaskProcessedEvent;
TaskQueueBase* mTaskQueue = nullptr;
};
KSYS_CHECK_SIZE_NX150(TaskThread, 0x1a0);
} // namespace ksys::util