1b7f5a220SSergey Makeev // The MIT License (MIT) 2b7f5a220SSergey Makeev // 3b7f5a220SSergey Makeev // Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev 4b7f5a220SSergey Makeev // 5b7f5a220SSergey Makeev // Permission is hereby granted, free of charge, to any person obtaining a copy 6b7f5a220SSergey Makeev // of this software and associated documentation files (the "Software"), to deal 7b7f5a220SSergey Makeev // in the Software without restriction, including without limitation the rights 8b7f5a220SSergey Makeev // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9b7f5a220SSergey Makeev // copies of the Software, and to permit persons to whom the Software is 10b7f5a220SSergey Makeev // furnished to do so, subject to the following conditions: 11b7f5a220SSergey Makeev // 12b7f5a220SSergey Makeev // The above copyright notice and this permission notice shall be included in 13b7f5a220SSergey Makeev // all copies or substantial portions of the Software. 14b7f5a220SSergey Makeev // 15b7f5a220SSergey Makeev // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16b7f5a220SSergey Makeev // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17b7f5a220SSergey Makeev // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18b7f5a220SSergey Makeev // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19b7f5a220SSergey Makeev // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20b7f5a220SSergey Makeev // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21b7f5a220SSergey Makeev // THE SOFTWARE. 22b7f5a220SSergey Makeev 23b7f5a220SSergey Makeev #pragma once 24b7f5a220SSergey Makeev 2502d170cfSs.makeev_local #include <MTConfig.h> 26b7f5a220SSergey Makeev 27b7f5a220SSergey Makeev 28b7f5a220SSergey Makeev namespace MT 29b7f5a220SSergey Makeev { 30b7f5a220SSergey Makeev 31b7f5a220SSergey Makeev namespace TaskID 32b7f5a220SSergey Makeev { 33b7f5a220SSergey Makeev //unused_id is any odd number, valid_id should be always only even numbers 34b7f5a220SSergey Makeev static const int UNUSED = 1; 35b7f5a220SSergey Makeev } 36b7f5a220SSergey Makeev 37b7f5a220SSergey Makeev 38b7f5a220SSergey Makeev //forward declaration 39b7f5a220SSergey Makeev class TaskHandle; 40b7f5a220SSergey Makeev 41b7f5a220SSergey Makeev 4258d12dadSSergey Makeev /// \class PoolElementHeader 43b7f5a220SSergey Makeev /// \brief 44b7f5a220SSergey Makeev ////////////////////////////////////////////////////////////////////////// 45b7f5a220SSergey Makeev struct PoolElementHeader 46b7f5a220SSergey Makeev { 4758d12dadSSergey Makeev //Task id (timestamp) 48721f8c0bSs.makeev_local Atomic32<int32> id; 49b7f5a220SSergey Makeev 5058d12dadSSergey Makeev internal::TaskDesc desc; 51b7f5a220SSergey Makeev 52b7f5a220SSergey Makeev public: 53b7f5a220SSergey Makeev PoolElementHeaderPoolElementHeader54b7f5a220SSergey Makeev PoolElementHeader(int _id) 55b7f5a220SSergey Makeev : id(_id) 56b7f5a220SSergey Makeev { 57b7f5a220SSergey Makeev } 58b7f5a220SSergey Makeev 59b7f5a220SSergey Makeev static bool DestoryByHandle(const MT::TaskHandle & handle); 60b7f5a220SSergey Makeev }; 61b7f5a220SSergey Makeev 62b7f5a220SSergey Makeev 63b7f5a220SSergey Makeev /// \class TaskPoolElement 64b7f5a220SSergey Makeev /// \brief 65b7f5a220SSergey Makeev ////////////////////////////////////////////////////////////////////////// 66b7f5a220SSergey Makeev template<typename T> 67b7f5a220SSergey Makeev class PoolElement : public PoolElementHeader 68b7f5a220SSergey Makeev { 69b7f5a220SSergey Makeev public: 70b7f5a220SSergey Makeev 7158d12dadSSergey Makeev // Storage for task 72b7f5a220SSergey Makeev T task; 73b7f5a220SSergey Makeev PoolElement(int _id,T && _task)74b7f5a220SSergey Makeev PoolElement(int _id, T && _task) 75b7f5a220SSergey Makeev : PoolElementHeader(_id) 76b7f5a220SSergey Makeev , task( std::move(_task) ) 77b7f5a220SSergey Makeev { 7802d170cfSs.makeev_local 7902d170cfSs.makeev_local #if MT_CLANG_COMPILER_FAMILY 8002d170cfSs.makeev_local #pragma clang diagnostic push 8102d170cfSs.makeev_local #pragma clang diagnostic ignored "-Winvalid-offsetof" 8202d170cfSs.makeev_local #endif 8302d170cfSs.makeev_local static_assert( offsetof(PoolElement<T>, task) == sizeof(PoolElementHeader), "Invalid offset for task in PoolElement"); 8402d170cfSs.makeev_local #if MT_CLANG_COMPILER_FAMILY 8502d170cfSs.makeev_local #pragma clang diagnostic pop 8602d170cfSs.makeev_local #endif 8758d12dadSSergey Makeev 8858d12dadSSergey Makeev desc.poolDestroyFunc = T::PoolTaskDestroy; 8958d12dadSSergey Makeev desc.taskFunc = T::TaskEntryPoint; 90f4db079dSs.makeev desc.stackRequirements = T::GetStackRequirements(); 91*b23bdf5aSs.makeev_local desc.priority = T::GetTaskPriority(); 9258d12dadSSergey Makeev desc.userData = &task; 9358d12dadSSergey Makeev 9458d12dadSSergey Makeev #ifdef MT_INSTRUMENTED_BUILD 9558d12dadSSergey Makeev desc.debugID = T::GetDebugID(); 964a90b4a6SSergey Makeev desc.debugColor = T::GetDebugColor(); 9758d12dadSSergey Makeev #endif 98b7f5a220SSergey Makeev } 99b7f5a220SSergey Makeev 100b7f5a220SSergey Makeev }; 101b7f5a220SSergey Makeev 102b7f5a220SSergey Makeev 103b7f5a220SSergey Makeev /// \class TaskHandle 104b7f5a220SSergey Makeev /// \brief 105b7f5a220SSergey Makeev ////////////////////////////////////////////////////////////////////////// 106b7f5a220SSergey Makeev class TaskHandle 107b7f5a220SSergey Makeev { 1082e846c40SSergey Makeev int32 check_id; 109b7f5a220SSergey Makeev 110b7f5a220SSergey Makeev protected: 111b7f5a220SSergey Makeev 112b7f5a220SSergey Makeev friend struct PoolElementHeader; 11358d12dadSSergey Makeev 114b7f5a220SSergey Makeev PoolElementHeader* task; 115b7f5a220SSergey Makeev 116b7f5a220SSergey Makeev public: 117b7f5a220SSergey Makeev 118b7f5a220SSergey Makeev //default ctor TaskHandle()119b7f5a220SSergey Makeev TaskHandle() 120b7f5a220SSergey Makeev : check_id(TaskID::UNUSED) 121b7f5a220SSergey Makeev , task(nullptr) 122b7f5a220SSergey Makeev { 123b7f5a220SSergey Makeev 124b7f5a220SSergey Makeev } 125b7f5a220SSergey Makeev 126b7f5a220SSergey Makeev //ctor TaskHandle(int _id,PoolElementHeader * _task)127b7f5a220SSergey Makeev TaskHandle(int _id, PoolElementHeader* _task) 128b7f5a220SSergey Makeev : check_id(_id) 129b7f5a220SSergey Makeev , task(_task) 130b7f5a220SSergey Makeev { 131b7f5a220SSergey Makeev } 132b7f5a220SSergey Makeev 133b7f5a220SSergey Makeev //copy ctor TaskHandle(const TaskHandle & other)134b7f5a220SSergey Makeev TaskHandle(const TaskHandle & other) 135b7f5a220SSergey Makeev : check_id(other.check_id) 136b7f5a220SSergey Makeev , task(other.task) 137b7f5a220SSergey Makeev { 138b7f5a220SSergey Makeev } 139b7f5a220SSergey Makeev 140b7f5a220SSergey Makeev //move ctor TaskHandle(TaskHandle && other)141b7f5a220SSergey Makeev TaskHandle(TaskHandle && other) 142b7f5a220SSergey Makeev : check_id(other.check_id) 143b7f5a220SSergey Makeev , task(other.task) 144b7f5a220SSergey Makeev { 145b7f5a220SSergey Makeev other.check_id = TaskID::UNUSED; 146b7f5a220SSergey Makeev other.task = nullptr; 147b7f5a220SSergey Makeev } 148b7f5a220SSergey Makeev ~TaskHandle()149b7f5a220SSergey Makeev ~TaskHandle() 150b7f5a220SSergey Makeev { 151b7f5a220SSergey Makeev } 152b7f5a220SSergey Makeev IsValid()153b7f5a220SSergey Makeev bool IsValid() const 154b7f5a220SSergey Makeev { 155b7f5a220SSergey Makeev if (task == nullptr) 156b7f5a220SSergey Makeev { 157b7f5a220SSergey Makeev return false; 158b7f5a220SSergey Makeev } 159b7f5a220SSergey Makeev 16081ec7369SSergey Makeev if (check_id != task->id.Load()) 161b7f5a220SSergey Makeev { 162b7f5a220SSergey Makeev return false; 163b7f5a220SSergey Makeev } 164b7f5a220SSergey Makeev 165b7f5a220SSergey Makeev return true; 166b7f5a220SSergey Makeev } 167b7f5a220SSergey Makeev 1681196c666SSergey Makeev 1691196c666SSergey Makeev // assignment operator 1701196c666SSergey Makeev TaskHandle & operator= (const TaskHandle & other) 1711196c666SSergey Makeev { 1721196c666SSergey Makeev check_id = other.check_id; 1731196c666SSergey Makeev task = other.task; 1741196c666SSergey Makeev 1751196c666SSergey Makeev return *this; 1761196c666SSergey Makeev } 1771196c666SSergey Makeev 1781196c666SSergey Makeev // move assignment operator 1791196c666SSergey Makeev TaskHandle & operator= (TaskHandle && other) 1801196c666SSergey Makeev { 1811196c666SSergey Makeev check_id = other.check_id; 1821196c666SSergey Makeev task = other.task; 1831196c666SSergey Makeev 1841196c666SSergey Makeev other.check_id = TaskID::UNUSED; 1851196c666SSergey Makeev other.task = nullptr; 1861196c666SSergey Makeev 1871196c666SSergey Makeev return *this; 1881196c666SSergey Makeev } 1891196c666SSergey Makeev GetDesc()190f4db079dSs.makeev const internal::TaskDesc & GetDesc() const 19158d12dadSSergey Makeev { 19258d12dadSSergey Makeev MT_ASSERT(IsValid(), "Task handle is invalid"); 19358d12dadSSergey Makeev return task->desc; 19458d12dadSSergey Makeev } 19558d12dadSSergey Makeev 19658d12dadSSergey Makeev 197b7f5a220SSergey Makeev }; 198b7f5a220SSergey Makeev 199b7f5a220SSergey Makeev 200b7f5a220SSergey Makeev 201b7f5a220SSergey Makeev 202b7f5a220SSergey Makeev ////////////////////////////////////////////////////////////////////////// DestoryByHandle(const MT::TaskHandle & handle)203b7f5a220SSergey Makeev inline bool PoolElementHeader::DestoryByHandle(const MT::TaskHandle & handle) 204b7f5a220SSergey Makeev { 205b7f5a220SSergey Makeev if (!handle.IsValid()) 206b7f5a220SSergey Makeev { 207b7f5a220SSergey Makeev return false; 208b7f5a220SSergey Makeev } 209b7f5a220SSergey Makeev 21058d12dadSSergey Makeev if (handle.task->desc.poolDestroyFunc == nullptr) 21158d12dadSSergey Makeev { 21258d12dadSSergey Makeev return false; 21358d12dadSSergey Makeev } 21458d12dadSSergey Makeev 21558d12dadSSergey Makeev if (handle.task->desc.userData == nullptr) 21658d12dadSSergey Makeev { 21758d12dadSSergey Makeev return false; 21858d12dadSSergey Makeev } 21958d12dadSSergey Makeev 22058d12dadSSergey Makeev //call destroy func 22158d12dadSSergey Makeev handle.task->desc.poolDestroyFunc(handle.task->desc.userData); 222b7f5a220SSergey Makeev return true; 223b7f5a220SSergey Makeev } 224b7f5a220SSergey Makeev 225b7f5a220SSergey Makeev 226b7f5a220SSergey Makeev 227b7f5a220SSergey Makeev 228b7f5a220SSergey Makeev 229b7f5a220SSergey Makeev /// \class TaskPool 230b7f5a220SSergey Makeev /// \brief 231b7f5a220SSergey Makeev ////////////////////////////////////////////////////////////////////////// 232b7f5a220SSergey Makeev template<typename T, size_t N> 233b7f5a220SSergey Makeev class TaskPool 234b7f5a220SSergey Makeev { 235c7362320Ss.makeev_local static const int32 ALIGNMENT = 16; 236c7362320Ss.makeev_local 237b7f5a220SSergey Makeev typedef PoolElement<T> PoolItem; 238b7f5a220SSergey Makeev 239b7f5a220SSergey Makeev // 240b7f5a220SSergey Makeev static const size_t MASK = (N - 1); 241b7f5a220SSergey Makeev 242b7f5a220SSergey Makeev void* data; 243721f8c0bSs.makeev_local Atomic32<int32> idGenerator; 244721f8c0bSs.makeev_local Atomic32<int32> index; 245b7f5a220SSergey Makeev Buffer()246b7f5a220SSergey Makeev inline PoolItem* Buffer() 247b7f5a220SSergey Makeev { 248b7f5a220SSergey Makeev return (PoolItem*)(data); 249b7f5a220SSergey Makeev } 250b7f5a220SSergey Makeev MoveCtor(PoolItem * element,int id,T && val)251b7f5a220SSergey Makeev inline void MoveCtor(PoolItem* element, int id, T && val) 252b7f5a220SSergey Makeev { 253b7f5a220SSergey Makeev new(element) PoolItem(id, std::move(val)); 254b7f5a220SSergey Makeev } 255b7f5a220SSergey Makeev 256b7f5a220SSergey Makeev public: 257b7f5a220SSergey Makeev 2582e846c40SSergey Makeev MT_NOCOPYABLE(TaskPool); 2592e846c40SSergey Makeev TaskPool()260b7f5a220SSergey Makeev TaskPool() 261b7f5a220SSergey Makeev : idGenerator(0) 262b7f5a220SSergey Makeev , index(0) 263b7f5a220SSergey Makeev { 264b7f5a220SSergey Makeev static_assert( MT::StaticIsPow2<N>::result, "Task pool capacity must be power of 2"); 265b7f5a220SSergey Makeev 266b7f5a220SSergey Makeev size_t bytesCount = sizeof(PoolItem) * N; 267c7362320Ss.makeev_local data = Memory::Alloc(bytesCount, ALIGNMENT); 268b7f5a220SSergey Makeev 269b7f5a220SSergey Makeev for(size_t idx = 0; idx < N; idx++) 270b7f5a220SSergey Makeev { 271b7f5a220SSergey Makeev PoolItem* pElement = Buffer() + idx; 27281ec7369SSergey Makeev pElement->id.Store(TaskID::UNUSED); 273b7f5a220SSergey Makeev } 274b7f5a220SSergey Makeev } 275b7f5a220SSergey Makeev ~TaskPool()276b7f5a220SSergey Makeev ~TaskPool() 277b7f5a220SSergey Makeev { 278b7f5a220SSergey Makeev if (data != nullptr) 279b7f5a220SSergey Makeev { 280b7f5a220SSergey Makeev 281b7f5a220SSergey Makeev for(size_t idx = 0; idx < N; idx++) 282b7f5a220SSergey Makeev { 283b7f5a220SSergey Makeev PoolItem* pElement = Buffer() + idx; 284b7f5a220SSergey Makeev 285721f8c0bSs.makeev_local int preValue = pElement->id.Exchange(TaskID::UNUSED); 286b7f5a220SSergey Makeev if (preValue != TaskID::UNUSED) 287b7f5a220SSergey Makeev { 288b7f5a220SSergey Makeev pElement->task.~T(); 289b7f5a220SSergey Makeev } 290b7f5a220SSergey Makeev } 291b7f5a220SSergey Makeev 292b7f5a220SSergey Makeev Memory::Free(data); 293b7f5a220SSergey Makeev data = nullptr; 294b7f5a220SSergey Makeev } 295b7f5a220SSergey Makeev } 296b7f5a220SSergey Makeev TryAlloc(T && task)29753334f79SSergey Makeev TaskHandle TryAlloc(T && task) 298b7f5a220SSergey Makeev { 29981ec7369SSergey Makeev int idx = index.IncFetch() - 1; 300b7f5a220SSergey Makeev 301b7f5a220SSergey Makeev int clampedIdx = (idx & MASK); 302b7f5a220SSergey Makeev 303b7f5a220SSergey Makeev PoolItem* pElement = Buffer() + clampedIdx; 304b7f5a220SSergey Makeev 30581ec7369SSergey Makeev bool isUnused = ((pElement->id.Load() & 1 ) != 0); 306e455330fSSergey Makeev 30753334f79SSergey Makeev if (isUnused == false) 30853334f79SSergey Makeev { 309b7f5a220SSergey Makeev //Can't allocate more, next element in circular buffer is already used 31053334f79SSergey Makeev return TaskHandle(); 31153334f79SSergey Makeev } 312b7f5a220SSergey Makeev 313b7f5a220SSergey Makeev //generate next even number for id 31481ec7369SSergey Makeev int id = idGenerator.AddFetch(2); 315b7f5a220SSergey Makeev MoveCtor( pElement, id, std::move(task) ); 316b7f5a220SSergey Makeev return TaskHandle(id, pElement); 317b7f5a220SSergey Makeev } 318b7f5a220SSergey Makeev 31953334f79SSergey Makeev Alloc(T && task)32053334f79SSergey Makeev TaskHandle Alloc(T && task) 32153334f79SSergey Makeev { 32253334f79SSergey Makeev TaskHandle res = TryAlloc(std::move(task)); 32353334f79SSergey Makeev MT_ASSERT(res.IsValid(), "Pool allocation failed"); 32453334f79SSergey Makeev return res; 32553334f79SSergey Makeev } 32653334f79SSergey Makeev 327b7f5a220SSergey Makeev }; 328b7f5a220SSergey Makeev 329b7f5a220SSergey Makeev } 330