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 25b7f5a220SSergey Makeev 26b7f5a220SSergey Makeev 27b7f5a220SSergey Makeev namespace MT 28b7f5a220SSergey Makeev { 29b7f5a220SSergey Makeev 30b7f5a220SSergey Makeev namespace TaskID 31b7f5a220SSergey Makeev { 32b7f5a220SSergey Makeev //unused_id is any odd number, valid_id should be always only even numbers 33b7f5a220SSergey Makeev static const int UNUSED = 1; 34b7f5a220SSergey Makeev } 35b7f5a220SSergey Makeev 36b7f5a220SSergey Makeev 37b7f5a220SSergey Makeev //forward declaration 38b7f5a220SSergey Makeev class TaskHandle; 39b7f5a220SSergey Makeev 40b7f5a220SSergey Makeev 4158d12dadSSergey Makeev /// \class PoolElementHeader 42b7f5a220SSergey Makeev /// \brief 43b7f5a220SSergey Makeev ////////////////////////////////////////////////////////////////////////// 44b7f5a220SSergey Makeev struct PoolElementHeader 45b7f5a220SSergey Makeev { 4658d12dadSSergey Makeev //Task id (timestamp) 4781ec7369SSergey Makeev AtomicInt32 id; 48b7f5a220SSergey Makeev 4958d12dadSSergey Makeev internal::TaskDesc desc; 50b7f5a220SSergey Makeev 51b7f5a220SSergey Makeev public: 52b7f5a220SSergey Makeev 53b7f5a220SSergey Makeev PoolElementHeader(int _id) 54b7f5a220SSergey Makeev : id(_id) 55b7f5a220SSergey Makeev { 56b7f5a220SSergey Makeev } 57b7f5a220SSergey Makeev 58b7f5a220SSergey Makeev static bool DestoryByHandle(const MT::TaskHandle & handle); 59b7f5a220SSergey Makeev }; 60b7f5a220SSergey Makeev 61b7f5a220SSergey Makeev 62b7f5a220SSergey Makeev /// \class TaskPoolElement 63b7f5a220SSergey Makeev /// \brief 64b7f5a220SSergey Makeev ////////////////////////////////////////////////////////////////////////// 65b7f5a220SSergey Makeev template<typename T> 66b7f5a220SSergey Makeev class PoolElement : public PoolElementHeader 67b7f5a220SSergey Makeev { 68b7f5a220SSergey Makeev public: 69b7f5a220SSergey Makeev 7058d12dadSSergey Makeev // Storage for task 71b7f5a220SSergey Makeev T task; 72b7f5a220SSergey Makeev 73b7f5a220SSergey Makeev PoolElement(int _id, T && _task) 74b7f5a220SSergey Makeev : PoolElementHeader(_id) 75b7f5a220SSergey Makeev , task( std::move(_task) ) 76b7f5a220SSergey Makeev { 7758d12dadSSergey Makeev MT_ASSERT( offsetof(PoolElement<T>, task) == sizeof(PoolElementHeader), "Invalid offset for task in PoolElement"); 7858d12dadSSergey Makeev 7958d12dadSSergey Makeev desc.poolDestroyFunc = T::PoolTaskDestroy; 8058d12dadSSergey Makeev desc.taskFunc = T::TaskEntryPoint; 8158d12dadSSergey Makeev desc.userData = &task; 8258d12dadSSergey Makeev 8358d12dadSSergey Makeev #ifdef MT_INSTRUMENTED_BUILD 8458d12dadSSergey Makeev desc.debugID = T::GetDebugID(); 854a90b4a6SSergey Makeev desc.debugColor = T::GetDebugColor(); 8658d12dadSSergey Makeev #endif 87b7f5a220SSergey Makeev } 88b7f5a220SSergey Makeev 89b7f5a220SSergey Makeev }; 90b7f5a220SSergey Makeev 91b7f5a220SSergey Makeev 92b7f5a220SSergey Makeev /// \class TaskHandle 93b7f5a220SSergey Makeev /// \brief 94b7f5a220SSergey Makeev ////////////////////////////////////////////////////////////////////////// 95b7f5a220SSergey Makeev class TaskHandle 96b7f5a220SSergey Makeev { 97*2e846c40SSergey Makeev int32 check_id; 98b7f5a220SSergey Makeev 99b7f5a220SSergey Makeev protected: 100b7f5a220SSergey Makeev 101b7f5a220SSergey Makeev friend struct PoolElementHeader; 10258d12dadSSergey Makeev 103b7f5a220SSergey Makeev PoolElementHeader* task; 104b7f5a220SSergey Makeev 105b7f5a220SSergey Makeev public: 106b7f5a220SSergey Makeev 107b7f5a220SSergey Makeev //default ctor 108b7f5a220SSergey Makeev TaskHandle() 109b7f5a220SSergey Makeev : check_id(TaskID::UNUSED) 110b7f5a220SSergey Makeev , task(nullptr) 111b7f5a220SSergey Makeev { 112b7f5a220SSergey Makeev 113b7f5a220SSergey Makeev } 114b7f5a220SSergey Makeev 115b7f5a220SSergey Makeev //ctor 116b7f5a220SSergey Makeev TaskHandle(int _id, PoolElementHeader* _task) 117b7f5a220SSergey Makeev : check_id(_id) 118b7f5a220SSergey Makeev , task(_task) 119b7f5a220SSergey Makeev { 120b7f5a220SSergey Makeev } 121b7f5a220SSergey Makeev 122b7f5a220SSergey Makeev //copy ctor 123b7f5a220SSergey Makeev TaskHandle(const TaskHandle & other) 124b7f5a220SSergey Makeev : check_id(other.check_id) 125b7f5a220SSergey Makeev , task(other.task) 126b7f5a220SSergey Makeev { 127b7f5a220SSergey Makeev } 128b7f5a220SSergey Makeev 129b7f5a220SSergey Makeev //move ctor 130b7f5a220SSergey Makeev TaskHandle(TaskHandle && other) 131b7f5a220SSergey Makeev : check_id(other.check_id) 132b7f5a220SSergey Makeev , task(other.task) 133b7f5a220SSergey Makeev { 134b7f5a220SSergey Makeev other.check_id = TaskID::UNUSED; 135b7f5a220SSergey Makeev other.task = nullptr; 136b7f5a220SSergey Makeev } 137b7f5a220SSergey Makeev 138b7f5a220SSergey Makeev ~TaskHandle() 139b7f5a220SSergey Makeev { 140b7f5a220SSergey Makeev } 141b7f5a220SSergey Makeev 142b7f5a220SSergey Makeev bool IsValid() const 143b7f5a220SSergey Makeev { 144b7f5a220SSergey Makeev if (task == nullptr) 145b7f5a220SSergey Makeev { 146b7f5a220SSergey Makeev return false; 147b7f5a220SSergey Makeev } 148b7f5a220SSergey Makeev 14981ec7369SSergey Makeev if (check_id != task->id.Load()) 150b7f5a220SSergey Makeev { 151b7f5a220SSergey Makeev return false; 152b7f5a220SSergey Makeev } 153b7f5a220SSergey Makeev 154b7f5a220SSergey Makeev return true; 155b7f5a220SSergey Makeev } 156b7f5a220SSergey Makeev 1571196c666SSergey Makeev 1581196c666SSergey Makeev // assignment operator 1591196c666SSergey Makeev TaskHandle & operator= (const TaskHandle & other) 1601196c666SSergey Makeev { 1611196c666SSergey Makeev check_id = other.check_id; 1621196c666SSergey Makeev task = other.task; 1631196c666SSergey Makeev 1641196c666SSergey Makeev return *this; 1651196c666SSergey Makeev } 1661196c666SSergey Makeev 1671196c666SSergey Makeev // move assignment operator 1681196c666SSergey Makeev TaskHandle & operator= (TaskHandle && other) 1691196c666SSergey Makeev { 1701196c666SSergey Makeev check_id = other.check_id; 1711196c666SSergey Makeev task = other.task; 1721196c666SSergey Makeev 1731196c666SSergey Makeev other.check_id = TaskID::UNUSED; 1741196c666SSergey Makeev other.task = nullptr; 1751196c666SSergey Makeev 1761196c666SSergey Makeev return *this; 1771196c666SSergey Makeev } 1781196c666SSergey Makeev 17958d12dadSSergey Makeev const internal::TaskDesc & GetDesc() 18058d12dadSSergey Makeev { 18158d12dadSSergey Makeev MT_ASSERT(IsValid(), "Task handle is invalid"); 18258d12dadSSergey Makeev return task->desc; 18358d12dadSSergey Makeev } 18458d12dadSSergey Makeev 18558d12dadSSergey Makeev 186b7f5a220SSergey Makeev }; 187b7f5a220SSergey Makeev 188b7f5a220SSergey Makeev 189b7f5a220SSergey Makeev 190b7f5a220SSergey Makeev 191b7f5a220SSergey Makeev ////////////////////////////////////////////////////////////////////////// 192b7f5a220SSergey Makeev inline bool PoolElementHeader::DestoryByHandle(const MT::TaskHandle & handle) 193b7f5a220SSergey Makeev { 194b7f5a220SSergey Makeev if (!handle.IsValid()) 195b7f5a220SSergey Makeev { 196b7f5a220SSergey Makeev return false; 197b7f5a220SSergey Makeev } 198b7f5a220SSergey Makeev 19958d12dadSSergey Makeev if (handle.task->desc.poolDestroyFunc == nullptr) 20058d12dadSSergey Makeev { 20158d12dadSSergey Makeev return false; 20258d12dadSSergey Makeev } 20358d12dadSSergey Makeev 20458d12dadSSergey Makeev if (handle.task->desc.userData == nullptr) 20558d12dadSSergey Makeev { 20658d12dadSSergey Makeev return false; 20758d12dadSSergey Makeev } 20858d12dadSSergey Makeev 20958d12dadSSergey Makeev //call destroy func 21058d12dadSSergey Makeev handle.task->desc.poolDestroyFunc(handle.task->desc.userData); 211b7f5a220SSergey Makeev return true; 212b7f5a220SSergey Makeev } 213b7f5a220SSergey Makeev 214b7f5a220SSergey Makeev 215b7f5a220SSergey Makeev 216b7f5a220SSergey Makeev 217b7f5a220SSergey Makeev 218b7f5a220SSergey Makeev /// \class TaskPool 219b7f5a220SSergey Makeev /// \brief 220b7f5a220SSergey Makeev ////////////////////////////////////////////////////////////////////////// 221b7f5a220SSergey Makeev template<typename T, size_t N> 222b7f5a220SSergey Makeev class TaskPool 223b7f5a220SSergey Makeev { 224b7f5a220SSergey Makeev typedef PoolElement<T> PoolItem; 225b7f5a220SSergey Makeev 226b7f5a220SSergey Makeev // 227b7f5a220SSergey Makeev static const size_t MASK = (N - 1); 228b7f5a220SSergey Makeev 229b7f5a220SSergey Makeev void* data; 23081ec7369SSergey Makeev AtomicInt32 idGenerator; 23181ec7369SSergey Makeev AtomicInt32 index; 232b7f5a220SSergey Makeev 233b7f5a220SSergey Makeev inline PoolItem* Buffer() 234b7f5a220SSergey Makeev { 235b7f5a220SSergey Makeev return (PoolItem*)(data); 236b7f5a220SSergey Makeev } 237b7f5a220SSergey Makeev 238b7f5a220SSergey Makeev inline void MoveCtor(PoolItem* element, int id, T && val) 239b7f5a220SSergey Makeev { 240b7f5a220SSergey Makeev new(element) PoolItem(id, std::move(val)); 241b7f5a220SSergey Makeev } 242b7f5a220SSergey Makeev 243b7f5a220SSergey Makeev public: 244b7f5a220SSergey Makeev 245*2e846c40SSergey Makeev MT_NOCOPYABLE(TaskPool); 246*2e846c40SSergey Makeev 247b7f5a220SSergey Makeev TaskPool() 248b7f5a220SSergey Makeev : idGenerator(0) 249b7f5a220SSergey Makeev , index(0) 250b7f5a220SSergey Makeev { 251b7f5a220SSergey Makeev static_assert( MT::StaticIsPow2<N>::result, "Task pool capacity must be power of 2"); 252b7f5a220SSergey Makeev 253b7f5a220SSergey Makeev size_t bytesCount = sizeof(PoolItem) * N; 254b7f5a220SSergey Makeev data = Memory::Alloc(bytesCount); 255b7f5a220SSergey Makeev 256b7f5a220SSergey Makeev for(size_t idx = 0; idx < N; idx++) 257b7f5a220SSergey Makeev { 258b7f5a220SSergey Makeev PoolItem* pElement = Buffer() + idx; 25981ec7369SSergey Makeev pElement->id.Store(TaskID::UNUSED); 260b7f5a220SSergey Makeev } 261b7f5a220SSergey Makeev } 262b7f5a220SSergey Makeev 263b7f5a220SSergey Makeev ~TaskPool() 264b7f5a220SSergey Makeev { 265b7f5a220SSergey Makeev if (data != nullptr) 266b7f5a220SSergey Makeev { 267b7f5a220SSergey Makeev 268b7f5a220SSergey Makeev for(size_t idx = 0; idx < N; idx++) 269b7f5a220SSergey Makeev { 270b7f5a220SSergey Makeev PoolItem* pElement = Buffer() + idx; 271b7f5a220SSergey Makeev 27281ec7369SSergey Makeev int preValue = pElement->id.Store(TaskID::UNUSED); 273b7f5a220SSergey Makeev if (preValue != TaskID::UNUSED) 274b7f5a220SSergey Makeev { 275b7f5a220SSergey Makeev pElement->task.~T(); 276b7f5a220SSergey Makeev } 277b7f5a220SSergey Makeev } 278b7f5a220SSergey Makeev 279b7f5a220SSergey Makeev Memory::Free(data); 280b7f5a220SSergey Makeev data = nullptr; 281b7f5a220SSergey Makeev } 282b7f5a220SSergey Makeev } 283b7f5a220SSergey Makeev 28453334f79SSergey Makeev TaskHandle TryAlloc(T && task) 285b7f5a220SSergey Makeev { 28681ec7369SSergey Makeev int idx = index.IncFetch() - 1; 287b7f5a220SSergey Makeev 288b7f5a220SSergey Makeev int clampedIdx = (idx & MASK); 289b7f5a220SSergey Makeev 290b7f5a220SSergey Makeev PoolItem* pElement = Buffer() + clampedIdx; 291b7f5a220SSergey Makeev 29281ec7369SSergey Makeev bool isUnused = ((pElement->id.Load() & 1 ) != 0); 293e455330fSSergey Makeev 29453334f79SSergey Makeev if (isUnused == false) 29553334f79SSergey Makeev { 296b7f5a220SSergey Makeev //Can't allocate more, next element in circular buffer is already used 29753334f79SSergey Makeev return TaskHandle(); 29853334f79SSergey Makeev } 299b7f5a220SSergey Makeev 300b7f5a220SSergey Makeev //generate next even number for id 30181ec7369SSergey Makeev int id = idGenerator.AddFetch(2); 302b7f5a220SSergey Makeev MoveCtor( pElement, id, std::move(task) ); 303b7f5a220SSergey Makeev return TaskHandle(id, pElement); 304b7f5a220SSergey Makeev } 305b7f5a220SSergey Makeev 30653334f79SSergey Makeev 30753334f79SSergey Makeev TaskHandle Alloc(T && task) 30853334f79SSergey Makeev { 30953334f79SSergey Makeev TaskHandle res = TryAlloc(std::move(task)); 31053334f79SSergey Makeev MT_ASSERT(res.IsValid(), "Pool allocation failed"); 31153334f79SSergey Makeev return res; 31253334f79SSergey Makeev } 31353334f79SSergey Makeev 314b7f5a220SSergey Makeev }; 315b7f5a220SSergey Makeev 316b7f5a220SSergey Makeev } 317