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; 81*f4db079dSs.makeev desc.stackRequirements = T::GetStackRequirements(); 8258d12dadSSergey Makeev desc.userData = &task; 8358d12dadSSergey Makeev 8458d12dadSSergey Makeev #ifdef MT_INSTRUMENTED_BUILD 8558d12dadSSergey Makeev desc.debugID = T::GetDebugID(); 864a90b4a6SSergey Makeev desc.debugColor = T::GetDebugColor(); 8758d12dadSSergey Makeev #endif 88b7f5a220SSergey Makeev } 89b7f5a220SSergey Makeev 90b7f5a220SSergey Makeev }; 91b7f5a220SSergey Makeev 92b7f5a220SSergey Makeev 93b7f5a220SSergey Makeev /// \class TaskHandle 94b7f5a220SSergey Makeev /// \brief 95b7f5a220SSergey Makeev ////////////////////////////////////////////////////////////////////////// 96b7f5a220SSergey Makeev class TaskHandle 97b7f5a220SSergey Makeev { 982e846c40SSergey Makeev int32 check_id; 99b7f5a220SSergey Makeev 100b7f5a220SSergey Makeev protected: 101b7f5a220SSergey Makeev 102b7f5a220SSergey Makeev friend struct PoolElementHeader; 10358d12dadSSergey Makeev 104b7f5a220SSergey Makeev PoolElementHeader* task; 105b7f5a220SSergey Makeev 106b7f5a220SSergey Makeev public: 107b7f5a220SSergey Makeev 108b7f5a220SSergey Makeev //default ctor 109b7f5a220SSergey Makeev TaskHandle() 110b7f5a220SSergey Makeev : check_id(TaskID::UNUSED) 111b7f5a220SSergey Makeev , task(nullptr) 112b7f5a220SSergey Makeev { 113b7f5a220SSergey Makeev 114b7f5a220SSergey Makeev } 115b7f5a220SSergey Makeev 116b7f5a220SSergey Makeev //ctor 117b7f5a220SSergey Makeev TaskHandle(int _id, PoolElementHeader* _task) 118b7f5a220SSergey Makeev : check_id(_id) 119b7f5a220SSergey Makeev , task(_task) 120b7f5a220SSergey Makeev { 121b7f5a220SSergey Makeev } 122b7f5a220SSergey Makeev 123b7f5a220SSergey Makeev //copy ctor 124b7f5a220SSergey Makeev TaskHandle(const TaskHandle & other) 125b7f5a220SSergey Makeev : check_id(other.check_id) 126b7f5a220SSergey Makeev , task(other.task) 127b7f5a220SSergey Makeev { 128b7f5a220SSergey Makeev } 129b7f5a220SSergey Makeev 130b7f5a220SSergey Makeev //move ctor 131b7f5a220SSergey Makeev TaskHandle(TaskHandle && other) 132b7f5a220SSergey Makeev : check_id(other.check_id) 133b7f5a220SSergey Makeev , task(other.task) 134b7f5a220SSergey Makeev { 135b7f5a220SSergey Makeev other.check_id = TaskID::UNUSED; 136b7f5a220SSergey Makeev other.task = nullptr; 137b7f5a220SSergey Makeev } 138b7f5a220SSergey Makeev 139b7f5a220SSergey Makeev ~TaskHandle() 140b7f5a220SSergey Makeev { 141b7f5a220SSergey Makeev } 142b7f5a220SSergey Makeev 143b7f5a220SSergey Makeev bool IsValid() const 144b7f5a220SSergey Makeev { 145b7f5a220SSergey Makeev if (task == nullptr) 146b7f5a220SSergey Makeev { 147b7f5a220SSergey Makeev return false; 148b7f5a220SSergey Makeev } 149b7f5a220SSergey Makeev 15081ec7369SSergey Makeev if (check_id != task->id.Load()) 151b7f5a220SSergey Makeev { 152b7f5a220SSergey Makeev return false; 153b7f5a220SSergey Makeev } 154b7f5a220SSergey Makeev 155b7f5a220SSergey Makeev return true; 156b7f5a220SSergey Makeev } 157b7f5a220SSergey Makeev 1581196c666SSergey Makeev 1591196c666SSergey Makeev // assignment operator 1601196c666SSergey Makeev TaskHandle & operator= (const TaskHandle & other) 1611196c666SSergey Makeev { 1621196c666SSergey Makeev check_id = other.check_id; 1631196c666SSergey Makeev task = other.task; 1641196c666SSergey Makeev 1651196c666SSergey Makeev return *this; 1661196c666SSergey Makeev } 1671196c666SSergey Makeev 1681196c666SSergey Makeev // move assignment operator 1691196c666SSergey Makeev TaskHandle & operator= (TaskHandle && other) 1701196c666SSergey Makeev { 1711196c666SSergey Makeev check_id = other.check_id; 1721196c666SSergey Makeev task = other.task; 1731196c666SSergey Makeev 1741196c666SSergey Makeev other.check_id = TaskID::UNUSED; 1751196c666SSergey Makeev other.task = nullptr; 1761196c666SSergey Makeev 1771196c666SSergey Makeev return *this; 1781196c666SSergey Makeev } 1791196c666SSergey Makeev 180*f4db079dSs.makeev const internal::TaskDesc & GetDesc() const 18158d12dadSSergey Makeev { 18258d12dadSSergey Makeev MT_ASSERT(IsValid(), "Task handle is invalid"); 18358d12dadSSergey Makeev return task->desc; 18458d12dadSSergey Makeev } 18558d12dadSSergey Makeev 18658d12dadSSergey Makeev 187b7f5a220SSergey Makeev }; 188b7f5a220SSergey Makeev 189b7f5a220SSergey Makeev 190b7f5a220SSergey Makeev 191b7f5a220SSergey Makeev 192b7f5a220SSergey Makeev ////////////////////////////////////////////////////////////////////////// 193b7f5a220SSergey Makeev inline bool PoolElementHeader::DestoryByHandle(const MT::TaskHandle & handle) 194b7f5a220SSergey Makeev { 195b7f5a220SSergey Makeev if (!handle.IsValid()) 196b7f5a220SSergey Makeev { 197b7f5a220SSergey Makeev return false; 198b7f5a220SSergey Makeev } 199b7f5a220SSergey Makeev 20058d12dadSSergey Makeev if (handle.task->desc.poolDestroyFunc == nullptr) 20158d12dadSSergey Makeev { 20258d12dadSSergey Makeev return false; 20358d12dadSSergey Makeev } 20458d12dadSSergey Makeev 20558d12dadSSergey Makeev if (handle.task->desc.userData == nullptr) 20658d12dadSSergey Makeev { 20758d12dadSSergey Makeev return false; 20858d12dadSSergey Makeev } 20958d12dadSSergey Makeev 21058d12dadSSergey Makeev //call destroy func 21158d12dadSSergey Makeev handle.task->desc.poolDestroyFunc(handle.task->desc.userData); 212b7f5a220SSergey Makeev return true; 213b7f5a220SSergey Makeev } 214b7f5a220SSergey Makeev 215b7f5a220SSergey Makeev 216b7f5a220SSergey Makeev 217b7f5a220SSergey Makeev 218b7f5a220SSergey Makeev 219b7f5a220SSergey Makeev /// \class TaskPool 220b7f5a220SSergey Makeev /// \brief 221b7f5a220SSergey Makeev ////////////////////////////////////////////////////////////////////////// 222b7f5a220SSergey Makeev template<typename T, size_t N> 223b7f5a220SSergey Makeev class TaskPool 224b7f5a220SSergey Makeev { 225b7f5a220SSergey Makeev typedef PoolElement<T> PoolItem; 226b7f5a220SSergey Makeev 227b7f5a220SSergey Makeev // 228b7f5a220SSergey Makeev static const size_t MASK = (N - 1); 229b7f5a220SSergey Makeev 230b7f5a220SSergey Makeev void* data; 23181ec7369SSergey Makeev AtomicInt32 idGenerator; 23281ec7369SSergey Makeev AtomicInt32 index; 233b7f5a220SSergey Makeev 234b7f5a220SSergey Makeev inline PoolItem* Buffer() 235b7f5a220SSergey Makeev { 236b7f5a220SSergey Makeev return (PoolItem*)(data); 237b7f5a220SSergey Makeev } 238b7f5a220SSergey Makeev 239b7f5a220SSergey Makeev inline void MoveCtor(PoolItem* element, int id, T && val) 240b7f5a220SSergey Makeev { 241b7f5a220SSergey Makeev new(element) PoolItem(id, std::move(val)); 242b7f5a220SSergey Makeev } 243b7f5a220SSergey Makeev 244b7f5a220SSergey Makeev public: 245b7f5a220SSergey Makeev 2462e846c40SSergey Makeev MT_NOCOPYABLE(TaskPool); 2472e846c40SSergey Makeev 248b7f5a220SSergey Makeev TaskPool() 249b7f5a220SSergey Makeev : idGenerator(0) 250b7f5a220SSergey Makeev , index(0) 251b7f5a220SSergey Makeev { 252b7f5a220SSergey Makeev static_assert( MT::StaticIsPow2<N>::result, "Task pool capacity must be power of 2"); 253b7f5a220SSergey Makeev 254b7f5a220SSergey Makeev size_t bytesCount = sizeof(PoolItem) * N; 255b7f5a220SSergey Makeev data = Memory::Alloc(bytesCount); 256b7f5a220SSergey Makeev 257b7f5a220SSergey Makeev for(size_t idx = 0; idx < N; idx++) 258b7f5a220SSergey Makeev { 259b7f5a220SSergey Makeev PoolItem* pElement = Buffer() + idx; 26081ec7369SSergey Makeev pElement->id.Store(TaskID::UNUSED); 261b7f5a220SSergey Makeev } 262b7f5a220SSergey Makeev } 263b7f5a220SSergey Makeev 264b7f5a220SSergey Makeev ~TaskPool() 265b7f5a220SSergey Makeev { 266b7f5a220SSergey Makeev if (data != nullptr) 267b7f5a220SSergey Makeev { 268b7f5a220SSergey Makeev 269b7f5a220SSergey Makeev for(size_t idx = 0; idx < N; idx++) 270b7f5a220SSergey Makeev { 271b7f5a220SSergey Makeev PoolItem* pElement = Buffer() + idx; 272b7f5a220SSergey Makeev 27381ec7369SSergey Makeev int preValue = pElement->id.Store(TaskID::UNUSED); 274b7f5a220SSergey Makeev if (preValue != TaskID::UNUSED) 275b7f5a220SSergey Makeev { 276b7f5a220SSergey Makeev pElement->task.~T(); 277b7f5a220SSergey Makeev } 278b7f5a220SSergey Makeev } 279b7f5a220SSergey Makeev 280b7f5a220SSergey Makeev Memory::Free(data); 281b7f5a220SSergey Makeev data = nullptr; 282b7f5a220SSergey Makeev } 283b7f5a220SSergey Makeev } 284b7f5a220SSergey Makeev 28553334f79SSergey Makeev TaskHandle TryAlloc(T && task) 286b7f5a220SSergey Makeev { 28781ec7369SSergey Makeev int idx = index.IncFetch() - 1; 288b7f5a220SSergey Makeev 289b7f5a220SSergey Makeev int clampedIdx = (idx & MASK); 290b7f5a220SSergey Makeev 291b7f5a220SSergey Makeev PoolItem* pElement = Buffer() + clampedIdx; 292b7f5a220SSergey Makeev 29381ec7369SSergey Makeev bool isUnused = ((pElement->id.Load() & 1 ) != 0); 294e455330fSSergey Makeev 29553334f79SSergey Makeev if (isUnused == false) 29653334f79SSergey Makeev { 297b7f5a220SSergey Makeev //Can't allocate more, next element in circular buffer is already used 29853334f79SSergey Makeev return TaskHandle(); 29953334f79SSergey Makeev } 300b7f5a220SSergey Makeev 301b7f5a220SSergey Makeev //generate next even number for id 30281ec7369SSergey Makeev int id = idGenerator.AddFetch(2); 303b7f5a220SSergey Makeev MoveCtor( pElement, id, std::move(task) ); 304b7f5a220SSergey Makeev return TaskHandle(id, pElement); 305b7f5a220SSergey Makeev } 306b7f5a220SSergey Makeev 30753334f79SSergey Makeev 30853334f79SSergey Makeev TaskHandle Alloc(T && task) 30953334f79SSergey Makeev { 31053334f79SSergey Makeev TaskHandle res = TryAlloc(std::move(task)); 31153334f79SSergey Makeev MT_ASSERT(res.IsValid(), "Pool allocation failed"); 31253334f79SSergey Makeev return res; 31353334f79SSergey Makeev } 31453334f79SSergey Makeev 315b7f5a220SSergey Makeev }; 316b7f5a220SSergey Makeev 317b7f5a220SSergey Makeev } 318