1f25ce65dSSergey Makeev // The MIT License (MIT) 2f25ce65dSSergey Makeev // 3f25ce65dSSergey Makeev // Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev 4f25ce65dSSergey Makeev // 5f25ce65dSSergey Makeev // Permission is hereby granted, free of charge, to any person obtaining a copy 6f25ce65dSSergey Makeev // of this software and associated documentation files (the "Software"), to deal 7f25ce65dSSergey Makeev // in the Software without restriction, including without limitation the rights 8f25ce65dSSergey Makeev // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9f25ce65dSSergey Makeev // copies of the Software, and to permit persons to whom the Software is 10f25ce65dSSergey Makeev // furnished to do so, subject to the following conditions: 11f25ce65dSSergey Makeev // 12f25ce65dSSergey Makeev // The above copyright notice and this permission notice shall be included in 13f25ce65dSSergey Makeev // all copies or substantial portions of the Software. 14f25ce65dSSergey Makeev // 15f25ce65dSSergey Makeev // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16f25ce65dSSergey Makeev // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17f25ce65dSSergey Makeev // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18f25ce65dSSergey Makeev // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19f25ce65dSSergey Makeev // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20f25ce65dSSergey Makeev // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21f25ce65dSSergey Makeev // THE SOFTWARE. 22f25ce65dSSergey Makeev 2347d53e4dSSergey Makeev #pragma once 2447d53e4dSSergey Makeev 254a90b4a6SSergey Makeev #include <MTColorTable.h> 2647d53e4dSSergey Makeev #include <MTTools.h> 2747d53e4dSSergey Makeev #include <MTPlatform.h> 2847d53e4dSSergey Makeev #include <MTConcurrentQueueLIFO.h> 2947d53e4dSSergey Makeev #include <MTStackArray.h> 3056aa031bSSergey Makeev #include <MTArrayView.h> 3158964d0bSSergey Makeev #include <MTThreadContext.h> 3258964d0bSSergey Makeev #include <MTFiberContext.h> 3351901c6bSSergey Makeev #include <MTAllocator.h> 34b7f5a220SSergey Makeev #include <MTTaskPool.h> 35*f4db079dSs.makeev #include <MTStackRequirements.h> 362e846c40SSergey Makeev #include <Scopes/MTScopes.h> 373955e462SSergey Makeev 3866de1283SSergey Makeev 393955e462SSergey Makeev namespace MT 403955e462SSergey Makeev { 413955e462SSergey Makeev 423955e462SSergey Makeev template<typename CLASS_TYPE, typename MACRO_TYPE> 433955e462SSergey Makeev struct CheckType 443955e462SSergey Makeev { 453955e462SSergey Makeev static_assert(std::is_same<CLASS_TYPE, MACRO_TYPE>::value, "Invalid type in MT_DECLARE_TASK macro. See CheckType template instantiation params to details."); 463955e462SSergey Makeev }; 473955e462SSergey Makeev 483955e462SSergey Makeev struct TypeChecker 493955e462SSergey Makeev { 503955e462SSergey Makeev template <typename T> 513955e462SSergey Makeev static T QueryThisType(T thisPtr) 523955e462SSergey Makeev { 533955e462SSergey Makeev return (T)nullptr; 543955e462SSergey Makeev } 553955e462SSergey Makeev }; 563955e462SSergey Makeev 579e8a432bSSergey Makeev 589e8a432bSSergey Makeev template <typename T> 599e8a432bSSergey Makeev inline void CallDtor(T* p) 609e8a432bSSergey Makeev { 612e846c40SSergey Makeev MT_UNUSED(p); 629e8a432bSSergey Makeev p->~T(); 639e8a432bSSergey Makeev } 649e8a432bSSergey Makeev 653955e462SSergey Makeev } 663955e462SSergey Makeev 676b6075aaSSergey Makeev #if _MSC_VER 683955e462SSergey Makeev 696b6075aaSSergey Makeev // Visual Studio compile time check 707f96f495SSergey Makeev #define MT_COMPILE_TIME_TYPE_CHECK(TYPE) \ 713955e462SSergey Makeev void CompileTimeCheckMethod() \ 723955e462SSergey Makeev { \ 73510585fbSSergey Makeev MT::CheckType< typename std::remove_pointer< decltype(MT::TypeChecker::QueryThisType(this)) >::type, typename TYPE > compileTypeTypesCheck; \ 743955e462SSergey Makeev compileTypeTypesCheck; \ 756b6075aaSSergey Makeev } 76510585fbSSergey Makeev 776b6075aaSSergey Makeev #else 786b6075aaSSergey Makeev 797f96f495SSergey Makeev 806b6075aaSSergey Makeev // GCC, Clang and other compilers compile time check 817f96f495SSergey Makeev #define MT_COMPILE_TIME_TYPE_CHECK(TYPE) \ 826b6075aaSSergey Makeev void CompileTimeCheckMethod() \ 836b6075aaSSergey Makeev { \ 84510585fbSSergey Makeev /* query this pointer type */ \ 85510585fbSSergey Makeev typedef decltype(MT::TypeChecker::QueryThisType(this)) THIS_PTR_TYPE; \ 86510585fbSSergey Makeev /* query class type from this pointer type */ \ 87f15c226dSSergey Makeev typedef typename std::remove_pointer<THIS_PTR_TYPE>::type CPP_TYPE; \ 88510585fbSSergey Makeev /* define macro type */ \ 896b6075aaSSergey Makeev typedef TYPE MACRO_TYPE; \ 90510585fbSSergey Makeev /* compile time checking that is same types */ \ 91510585fbSSergey Makeev MT::CheckType< CPP_TYPE, MACRO_TYPE > compileTypeTypesCheck; \ 92510585fbSSergey Makeev /* remove unused variable warning */ \ 937f96f495SSergey Makeev MT_UNUSED(compileTypeTypesCheck); \ 946b6075aaSSergey Makeev } 95510585fbSSergey Makeev 966b6075aaSSergey Makeev #endif 976b6075aaSSergey Makeev 986b6075aaSSergey Makeev 996b6075aaSSergey Makeev 1006b6075aaSSergey Makeev 101*f4db079dSs.makeev #define MT_DECLARE_TASK_IMPL(TYPE, STACK_REQUIREMENTS) \ 1026b6075aaSSergey Makeev \ 1037f96f495SSergey Makeev MT_COMPILE_TIME_TYPE_CHECK(TYPE) \ 1043955e462SSergey Makeev \ 105*f4db079dSs.makeev static void TaskEntryPoint(MT::FiberContext& fiberContext, const void* userData) \ 1063955e462SSergey Makeev { \ 107*f4db079dSs.makeev /* C style cast */ \ 108*f4db079dSs.makeev TYPE * task = (TYPE *)(userData); \ 1093955e462SSergey Makeev task->Do(fiberContext); \ 1103955e462SSergey Makeev } \ 1113955e462SSergey Makeev \ 112*f4db079dSs.makeev static void PoolTaskDestroy(const void* userData) \ 1133955e462SSergey Makeev { \ 114*f4db079dSs.makeev /* C style cast */ \ 115*f4db079dSs.makeev TYPE * task = (TYPE *)(userData); \ 1169e8a432bSSergey Makeev MT::CallDtor( task ); \ 1173955e462SSergey Makeev /* Find task pool header */ \ 1183955e462SSergey Makeev MT::PoolElementHeader * poolHeader = (MT::PoolElementHeader *)((char*)userData - sizeof(MT::PoolElementHeader)); \ 1193955e462SSergey Makeev /* Fixup pool header, mark task as unused */ \ 1203955e462SSergey Makeev poolHeader->id.Store(MT::TaskID::UNUSED); \ 1213955e462SSergey Makeev } \ 122*f4db079dSs.makeev \ 123*f4db079dSs.makeev static MT::StackRequirements::Type GetStackRequirements() \ 124*f4db079dSs.makeev { \ 125*f4db079dSs.makeev return STACK_REQUIREMENTS; \ 126*f4db079dSs.makeev } \ 1273955e462SSergey Makeev 1283955e462SSergey Makeev 1293955e462SSergey Makeev 130ff5c86b0SSergey Makeev #ifdef MT_INSTRUMENTED_BUILD 1310727c1f9SSergey Makeev #include <MTProfilerEventListener.h> 1323955e462SSergey Makeev 133*f4db079dSs.makeev #define MT_DECLARE_TASK(TYPE, STACK_REQUIREMENTS, DEBUG_COLOR) \ 134f371f0bdSSergey Makeev static const mt_char* GetDebugID() \ 1353955e462SSergey Makeev { \ 136f371f0bdSSergey Makeev return MT_TEXT( #TYPE ); \ 1373955e462SSergey Makeev } \ 1383955e462SSergey Makeev \ 1394a90b4a6SSergey Makeev static MT::Color::Type GetDebugColor() \ 1403955e462SSergey Makeev { \ 1414a90b4a6SSergey Makeev return DEBUG_COLOR; \ 1423955e462SSergey Makeev } \ 1433955e462SSergey Makeev \ 144*f4db079dSs.makeev MT_DECLARE_TASK_IMPL(TYPE, STACK_REQUIREMENTS); 1453955e462SSergey Makeev 1463955e462SSergey Makeev 1473955e462SSergey Makeev #else 1483955e462SSergey Makeev 149*f4db079dSs.makeev #define MT_DECLARE_TASK(TYPE, STACK_REQUIREMENTS, DEBUG_COLOR) \ 150*f4db079dSs.makeev MT_DECLARE_TASK_IMPL(TYPE, STACK_REQUIREMENTS); 1513955e462SSergey Makeev 152ff5c86b0SSergey Makeev #endif 153ff5c86b0SSergey Makeev 1543955e462SSergey Makeev 1553955e462SSergey Makeev 1563955e462SSergey Makeev 1573955e462SSergey Makeev 1583955e462SSergey Makeev 15947d53e4dSSergey Makeev namespace MT 16047d53e4dSSergey Makeev { 16143c41d5cSSergey Makeev const uint32 MT_MAX_THREAD_COUNT = 64; 162*f4db079dSs.makeev const uint32 MT_SCHEDULER_STACK_SIZE = 1048576; // 1Mb 163*f4db079dSs.makeev 164*f4db079dSs.makeev const uint32 MT_MAX_STANDART_FIBERS_COUNT = 256; 165*f4db079dSs.makeev const uint32 MT_STANDART_FIBER_STACK_SIZE = 32768; //32Kb 166*f4db079dSs.makeev 167*f4db079dSs.makeev const uint32 MT_MAX_EXTENDED_FIBERS_COUNT = 8; 168*f4db079dSs.makeev const uint32 MT_EXTENDED_FIBER_STACK_SIZE = 1048576; // 1Mb 16947d53e4dSSergey Makeev 17058964d0bSSergey Makeev namespace internal 17147d53e4dSSergey Makeev { 17247d53e4dSSergey Makeev struct ThreadContext; 17347d53e4dSSergey Makeev } 17447d53e4dSSergey Makeev 17547d53e4dSSergey Makeev //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 17647d53e4dSSergey Makeev // Task scheduler 17747d53e4dSSergey Makeev //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 17847d53e4dSSergey Makeev class TaskScheduler 17947d53e4dSSergey Makeev { 18047d53e4dSSergey Makeev friend class FiberContext; 18158964d0bSSergey Makeev friend struct internal::ThreadContext; 18247d53e4dSSergey Makeev 18347d53e4dSSergey Makeev 184806ef292SSergey Makeev 185806ef292SSergey Makeev //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 186806ef292SSergey Makeev // Task group description 187806ef292SSergey Makeev //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 188806ef292SSergey Makeev // Application can assign task group to task and later wait until group was finished. 189806ef292SSergey Makeev class TaskGroupDescription 190806ef292SSergey Makeev { 19181ec7369SSergey Makeev AtomicInt32 inProgressTaskCount; 192806ef292SSergey Makeev Event allDoneEvent; 193806ef292SSergey Makeev 194806ef292SSergey Makeev //Tasks awaiting group through FiberContext::WaitGroupAndYield call 195806ef292SSergey Makeev ConcurrentQueueLIFO<FiberContext*> waitTasksQueue; 196806ef292SSergey Makeev 197806ef292SSergey Makeev bool debugIsFree; 198806ef292SSergey Makeev 199806ef292SSergey Makeev public: 200806ef292SSergey Makeev 2012e846c40SSergey Makeev MT_NOCOPYABLE(TaskGroupDescription); 2022e846c40SSergey Makeev 203806ef292SSergey Makeev TaskGroupDescription() 204806ef292SSergey Makeev { 20581ec7369SSergey Makeev inProgressTaskCount.Store(0); 206806ef292SSergey Makeev allDoneEvent.Create( EventReset::MANUAL, true ); 207806ef292SSergey Makeev debugIsFree = true; 208806ef292SSergey Makeev } 209806ef292SSergey Makeev 21081ec7369SSergey Makeev int GetTaskCount() const 21181ec7369SSergey Makeev { 21281ec7369SSergey Makeev return inProgressTaskCount.Load(); 21381ec7369SSergey Makeev } 21481ec7369SSergey Makeev 21581ec7369SSergey Makeev ConcurrentQueueLIFO<FiberContext*> & GetWaitQueue() 21681ec7369SSergey Makeev { 21781ec7369SSergey Makeev return waitTasksQueue; 21881ec7369SSergey Makeev } 21981ec7369SSergey Makeev 22081ec7369SSergey Makeev int Dec() 22181ec7369SSergey Makeev { 22281ec7369SSergey Makeev return inProgressTaskCount.DecFetch(); 22381ec7369SSergey Makeev } 22481ec7369SSergey Makeev 22581ec7369SSergey Makeev int Inc() 22681ec7369SSergey Makeev { 22781ec7369SSergey Makeev return inProgressTaskCount.IncFetch(); 22881ec7369SSergey Makeev } 22981ec7369SSergey Makeev 23081ec7369SSergey Makeev int Add(int sum) 23181ec7369SSergey Makeev { 23281ec7369SSergey Makeev return inProgressTaskCount.AddFetch(sum); 23381ec7369SSergey Makeev } 23481ec7369SSergey Makeev 23581ec7369SSergey Makeev void Signal() 23681ec7369SSergey Makeev { 23781ec7369SSergey Makeev allDoneEvent.Signal(); 23881ec7369SSergey Makeev } 23981ec7369SSergey Makeev 24081ec7369SSergey Makeev void Reset() 24181ec7369SSergey Makeev { 24281ec7369SSergey Makeev allDoneEvent.Reset(); 24381ec7369SSergey Makeev } 24481ec7369SSergey Makeev 24581ec7369SSergey Makeev bool Wait(uint32 milliseconds) 24681ec7369SSergey Makeev { 24781ec7369SSergey Makeev return allDoneEvent.Wait(milliseconds); 24881ec7369SSergey Makeev } 2492e846c40SSergey Makeev 2502e846c40SSergey Makeev void SetDebugIsFree(bool _debugIsFree) 2512e846c40SSergey Makeev { 2522e846c40SSergey Makeev debugIsFree = _debugIsFree; 2532e846c40SSergey Makeev } 2542e846c40SSergey Makeev 2552e846c40SSergey Makeev bool GetDebugIsFree() const 2562e846c40SSergey Makeev { 2572e846c40SSergey Makeev return debugIsFree; 2582e846c40SSergey Makeev } 259806ef292SSergey Makeev }; 260806ef292SSergey Makeev 261806ef292SSergey Makeev 26247d53e4dSSergey Makeev // Thread index for new task 26381ec7369SSergey Makeev AtomicInt32 roundRobinThreadIndex; 26447d53e4dSSergey Makeev 26543c41d5cSSergey Makeev // Started threads count 26681ec7369SSergey Makeev AtomicInt32 startedThreadsCount; 26743c41d5cSSergey Makeev 26847d53e4dSSergey Makeev // Threads created by task manager 269a23fd933SSergey Makeev AtomicInt32 threadsCount; 27058964d0bSSergey Makeev internal::ThreadContext threadContext[MT_MAX_THREAD_COUNT]; 27147d53e4dSSergey Makeev 27247d53e4dSSergey Makeev // All groups task statistic 273806ef292SSergey Makeev TaskGroupDescription allGroups; 274806ef292SSergey Makeev 275806ef292SSergey Makeev // Groups pool 276806ef292SSergey Makeev ConcurrentQueueLIFO<TaskGroup> availableGroups; 277806ef292SSergey Makeev 278806ef292SSergey Makeev // 279754cb997SSergey Makeev TaskGroupDescription groupStats[TaskGroup::MT_MAX_GROUPS_COUNT]; 28047d53e4dSSergey Makeev 28147d53e4dSSergey Makeev // Fibers context 282*f4db079dSs.makeev FiberContext standartFiberContexts[MT_MAX_STANDART_FIBERS_COUNT]; 283*f4db079dSs.makeev FiberContext extendedFiberContexts[MT_MAX_EXTENDED_FIBERS_COUNT]; 284*f4db079dSs.makeev 285*f4db079dSs.makeev // Fibers pool 286*f4db079dSs.makeev ConcurrentQueueLIFO<FiberContext*> standartFibersAvailable; 287*f4db079dSs.makeev ConcurrentQueueLIFO<FiberContext*> extendedFibersAvailable; 288*f4db079dSs.makeev 289*f4db079dSs.makeev ConcurrentQueueLIFO<FiberContext*>* GetFibersStorage(MT::StackRequirements::Type stackRequirements); 29047d53e4dSSergey Makeev 291ff5c86b0SSergey Makeev #ifdef MT_INSTRUMENTED_BUILD 2920727c1f9SSergey Makeev IProfilerEventListener * profilerEventListener; 293ff5c86b0SSergey Makeev #endif 294ff5c86b0SSergey Makeev 29558964d0bSSergey Makeev FiberContext* RequestFiberContext(internal::GroupedTask& task); 29647d53e4dSSergey Makeev void ReleaseFiberContext(FiberContext* fiberExecutionContext); 29756aa031bSSergey Makeev void RunTasksImpl(ArrayView<internal::TaskBucket>& buckets, FiberContext * parentFiber, bool restoredFromAwaitState); 298806ef292SSergey Makeev TaskGroupDescription & GetGroupDesc(TaskGroup group); 29947d53e4dSSergey Makeev 30047d53e4dSSergey Makeev static void ThreadMain( void* userData ); 30147d53e4dSSergey Makeev static void FiberMain( void* userData ); 302a1626843SSergey Makeev static bool TryStealTask(internal::ThreadContext& threadContext, internal::GroupedTask & task, uint32 workersCount); 3032b4df162SSergey Makeev 30458964d0bSSergey Makeev static FiberContext* ExecuteTask (internal::ThreadContext& threadContext, FiberContext* fiberContext); 30547d53e4dSSergey Makeev 30647d53e4dSSergey Makeev public: 30747d53e4dSSergey Makeev 30834a394c3SSergey Makeev /// \brief Initializes a new instance of the TaskScheduler class. 30934a394c3SSergey Makeev /// \param workerThreadsCount Worker threads count. Automatically determines the required number of threads if workerThreadsCount set to 0 3100727c1f9SSergey Makeev #ifdef MT_INSTRUMENTED_BUILD 3110727c1f9SSergey Makeev TaskScheduler(uint32 workerThreadsCount = 0, IProfilerEventListener* listener = nullptr); 3120727c1f9SSergey Makeev #else 31334a394c3SSergey Makeev TaskScheduler(uint32 workerThreadsCount = 0); 3140727c1f9SSergey Makeev #endif 3150727c1f9SSergey Makeev 3160727c1f9SSergey Makeev 31747d53e4dSSergey Makeev ~TaskScheduler(); 31847d53e4dSSergey Makeev 31947d53e4dSSergey Makeev template<class TTask> 320*f4db079dSs.makeev void RunAsync(TaskGroup group, const TTask* taskArray, uint32 taskCount); 32147d53e4dSSergey Makeev 322*f4db079dSs.makeev void RunAsync(TaskGroup group, const TaskHandle* taskHandleArray, uint32 taskHandleCount); 32358d12dadSSergey Makeev 32458d12dadSSergey Makeev 325806ef292SSergey Makeev bool WaitGroup(TaskGroup group, uint32 milliseconds); 32647d53e4dSSergey Makeev bool WaitAll(uint32 milliseconds); 32747d53e4dSSergey Makeev 328806ef292SSergey Makeev TaskGroup CreateGroup(); 329806ef292SSergey Makeev void ReleaseGroup(TaskGroup group); 330806ef292SSergey Makeev 33147d53e4dSSergey Makeev bool IsEmpty(); 33247d53e4dSSergey Makeev 333a23fd933SSergey Makeev int32 GetWorkersCount() const; 33447d53e4dSSergey Makeev 33547d53e4dSSergey Makeev bool IsWorkerThread() const; 3368112dedfSSergey Makeev 3378112dedfSSergey Makeev #ifdef MT_INSTRUMENTED_BUILD 3388112dedfSSergey Makeev 3390727c1f9SSergey Makeev inline IProfilerEventListener* GetProfilerEventListener() 3400727c1f9SSergey Makeev { 3410727c1f9SSergey Makeev return profilerEventListener; 3420727c1f9SSergey Makeev } 3430727c1f9SSergey Makeev 3448112dedfSSergey Makeev #endif 34547d53e4dSSergey Makeev }; 34647d53e4dSSergey Makeev } 34747d53e4dSSergey Makeev 348b7b54a39SSergey Makeev #include "MTScheduler.inl" 349b7b54a39SSergey Makeev #include "MTFiberContext.inl" 350