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) 4881ec7369SSergey Makeev AtomicInt32 id; 49b7f5a220SSergey Makeev 5058d12dadSSergey Makeev internal::TaskDesc desc; 51b7f5a220SSergey Makeev 52b7f5a220SSergey Makeev public: 53b7f5a220SSergey Makeev 54b7f5a220SSergey 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 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(); 9158d12dadSSergey Makeev desc.userData = &task; 9258d12dadSSergey Makeev 9358d12dadSSergey Makeev #ifdef MT_INSTRUMENTED_BUILD 9458d12dadSSergey Makeev desc.debugID = T::GetDebugID(); 954a90b4a6SSergey Makeev desc.debugColor = T::GetDebugColor(); 9658d12dadSSergey Makeev #endif 97b7f5a220SSergey Makeev } 98b7f5a220SSergey Makeev 99b7f5a220SSergey Makeev }; 100b7f5a220SSergey Makeev 101b7f5a220SSergey Makeev 102b7f5a220SSergey Makeev /// \class TaskHandle 103b7f5a220SSergey Makeev /// \brief 104b7f5a220SSergey Makeev ////////////////////////////////////////////////////////////////////////// 105b7f5a220SSergey Makeev class TaskHandle 106b7f5a220SSergey Makeev { 1072e846c40SSergey Makeev int32 check_id; 108b7f5a220SSergey Makeev 109b7f5a220SSergey Makeev protected: 110b7f5a220SSergey Makeev 111b7f5a220SSergey Makeev friend struct PoolElementHeader; 11258d12dadSSergey Makeev 113b7f5a220SSergey Makeev PoolElementHeader* task; 114b7f5a220SSergey Makeev 115b7f5a220SSergey Makeev public: 116b7f5a220SSergey Makeev 117b7f5a220SSergey Makeev //default ctor 118b7f5a220SSergey Makeev TaskHandle() 119b7f5a220SSergey Makeev : check_id(TaskID::UNUSED) 120b7f5a220SSergey Makeev , task(nullptr) 121b7f5a220SSergey Makeev { 122b7f5a220SSergey Makeev 123b7f5a220SSergey Makeev } 124b7f5a220SSergey Makeev 125b7f5a220SSergey Makeev //ctor 126b7f5a220SSergey Makeev TaskHandle(int _id, PoolElementHeader* _task) 127b7f5a220SSergey Makeev : check_id(_id) 128b7f5a220SSergey Makeev , task(_task) 129b7f5a220SSergey Makeev { 130b7f5a220SSergey Makeev } 131b7f5a220SSergey Makeev 132b7f5a220SSergey Makeev //copy ctor 133b7f5a220SSergey Makeev TaskHandle(const TaskHandle & other) 134b7f5a220SSergey Makeev : check_id(other.check_id) 135b7f5a220SSergey Makeev , task(other.task) 136b7f5a220SSergey Makeev { 137b7f5a220SSergey Makeev } 138b7f5a220SSergey Makeev 139b7f5a220SSergey Makeev //move ctor 140b7f5a220SSergey Makeev TaskHandle(TaskHandle && other) 141b7f5a220SSergey Makeev : check_id(other.check_id) 142b7f5a220SSergey Makeev , task(other.task) 143b7f5a220SSergey Makeev { 144b7f5a220SSergey Makeev other.check_id = TaskID::UNUSED; 145b7f5a220SSergey Makeev other.task = nullptr; 146b7f5a220SSergey Makeev } 147b7f5a220SSergey Makeev 148b7f5a220SSergey Makeev ~TaskHandle() 149b7f5a220SSergey Makeev { 150b7f5a220SSergey Makeev } 151b7f5a220SSergey Makeev 152b7f5a220SSergey Makeev bool IsValid() const 153b7f5a220SSergey Makeev { 154b7f5a220SSergey Makeev if (task == nullptr) 155b7f5a220SSergey Makeev { 156b7f5a220SSergey Makeev return false; 157b7f5a220SSergey Makeev } 158b7f5a220SSergey Makeev 15981ec7369SSergey Makeev if (check_id != task->id.Load()) 160b7f5a220SSergey Makeev { 161b7f5a220SSergey Makeev return false; 162b7f5a220SSergey Makeev } 163b7f5a220SSergey Makeev 164b7f5a220SSergey Makeev return true; 165b7f5a220SSergey Makeev } 166b7f5a220SSergey Makeev 1671196c666SSergey Makeev 1681196c666SSergey Makeev // assignment operator 1691196c666SSergey Makeev TaskHandle & operator= (const TaskHandle & other) 1701196c666SSergey Makeev { 1711196c666SSergey Makeev check_id = other.check_id; 1721196c666SSergey Makeev task = other.task; 1731196c666SSergey Makeev 1741196c666SSergey Makeev return *this; 1751196c666SSergey Makeev } 1761196c666SSergey Makeev 1771196c666SSergey Makeev // move assignment operator 1781196c666SSergey Makeev TaskHandle & operator= (TaskHandle && other) 1791196c666SSergey Makeev { 1801196c666SSergey Makeev check_id = other.check_id; 1811196c666SSergey Makeev task = other.task; 1821196c666SSergey Makeev 1831196c666SSergey Makeev other.check_id = TaskID::UNUSED; 1841196c666SSergey Makeev other.task = nullptr; 1851196c666SSergey Makeev 1861196c666SSergey Makeev return *this; 1871196c666SSergey Makeev } 1881196c666SSergey Makeev 189f4db079dSs.makeev const internal::TaskDesc & GetDesc() const 19058d12dadSSergey Makeev { 19158d12dadSSergey Makeev MT_ASSERT(IsValid(), "Task handle is invalid"); 19258d12dadSSergey Makeev return task->desc; 19358d12dadSSergey Makeev } 19458d12dadSSergey Makeev 19558d12dadSSergey Makeev 196b7f5a220SSergey Makeev }; 197b7f5a220SSergey Makeev 198b7f5a220SSergey Makeev 199b7f5a220SSergey Makeev 200b7f5a220SSergey Makeev 201b7f5a220SSergey Makeev ////////////////////////////////////////////////////////////////////////// 202b7f5a220SSergey Makeev inline bool PoolElementHeader::DestoryByHandle(const MT::TaskHandle & handle) 203b7f5a220SSergey Makeev { 204b7f5a220SSergey Makeev if (!handle.IsValid()) 205b7f5a220SSergey Makeev { 206b7f5a220SSergey Makeev return false; 207b7f5a220SSergey Makeev } 208b7f5a220SSergey Makeev 20958d12dadSSergey Makeev if (handle.task->desc.poolDestroyFunc == nullptr) 21058d12dadSSergey Makeev { 21158d12dadSSergey Makeev return false; 21258d12dadSSergey Makeev } 21358d12dadSSergey Makeev 21458d12dadSSergey Makeev if (handle.task->desc.userData == nullptr) 21558d12dadSSergey Makeev { 21658d12dadSSergey Makeev return false; 21758d12dadSSergey Makeev } 21858d12dadSSergey Makeev 21958d12dadSSergey Makeev //call destroy func 22058d12dadSSergey Makeev handle.task->desc.poolDestroyFunc(handle.task->desc.userData); 221b7f5a220SSergey Makeev return true; 222b7f5a220SSergey Makeev } 223b7f5a220SSergey Makeev 224b7f5a220SSergey Makeev 225b7f5a220SSergey Makeev 226b7f5a220SSergey Makeev 227b7f5a220SSergey Makeev 228b7f5a220SSergey Makeev /// \class TaskPool 229b7f5a220SSergey Makeev /// \brief 230b7f5a220SSergey Makeev ////////////////////////////////////////////////////////////////////////// 231b7f5a220SSergey Makeev template<typename T, size_t N> 232b7f5a220SSergey Makeev class TaskPool 233b7f5a220SSergey Makeev { 234*c7362320Ss.makeev_local static const int32 ALIGNMENT = 16; 235*c7362320Ss.makeev_local 236b7f5a220SSergey Makeev typedef PoolElement<T> PoolItem; 237b7f5a220SSergey Makeev 238b7f5a220SSergey Makeev // 239b7f5a220SSergey Makeev static const size_t MASK = (N - 1); 240b7f5a220SSergey Makeev 241b7f5a220SSergey Makeev void* data; 24281ec7369SSergey Makeev AtomicInt32 idGenerator; 24381ec7369SSergey Makeev AtomicInt32 index; 244b7f5a220SSergey Makeev 245b7f5a220SSergey Makeev inline PoolItem* Buffer() 246b7f5a220SSergey Makeev { 247b7f5a220SSergey Makeev return (PoolItem*)(data); 248b7f5a220SSergey Makeev } 249b7f5a220SSergey Makeev 250b7f5a220SSergey Makeev inline void MoveCtor(PoolItem* element, int id, T && val) 251b7f5a220SSergey Makeev { 252b7f5a220SSergey Makeev new(element) PoolItem(id, std::move(val)); 253b7f5a220SSergey Makeev } 254b7f5a220SSergey Makeev 255b7f5a220SSergey Makeev public: 256b7f5a220SSergey Makeev 2572e846c40SSergey Makeev MT_NOCOPYABLE(TaskPool); 2582e846c40SSergey Makeev 259b7f5a220SSergey Makeev TaskPool() 260b7f5a220SSergey Makeev : idGenerator(0) 261b7f5a220SSergey Makeev , index(0) 262b7f5a220SSergey Makeev { 263b7f5a220SSergey Makeev static_assert( MT::StaticIsPow2<N>::result, "Task pool capacity must be power of 2"); 264b7f5a220SSergey Makeev 265b7f5a220SSergey Makeev size_t bytesCount = sizeof(PoolItem) * N; 266*c7362320Ss.makeev_local data = Memory::Alloc(bytesCount, ALIGNMENT); 267b7f5a220SSergey Makeev 268b7f5a220SSergey Makeev for(size_t idx = 0; idx < N; idx++) 269b7f5a220SSergey Makeev { 270b7f5a220SSergey Makeev PoolItem* pElement = Buffer() + idx; 27181ec7369SSergey Makeev pElement->id.Store(TaskID::UNUSED); 272b7f5a220SSergey Makeev } 273b7f5a220SSergey Makeev } 274b7f5a220SSergey Makeev 275b7f5a220SSergey Makeev ~TaskPool() 276b7f5a220SSergey Makeev { 277b7f5a220SSergey Makeev if (data != nullptr) 278b7f5a220SSergey Makeev { 279b7f5a220SSergey Makeev 280b7f5a220SSergey Makeev for(size_t idx = 0; idx < N; idx++) 281b7f5a220SSergey Makeev { 282b7f5a220SSergey Makeev PoolItem* pElement = Buffer() + idx; 283b7f5a220SSergey Makeev 28481ec7369SSergey Makeev int preValue = pElement->id.Store(TaskID::UNUSED); 285b7f5a220SSergey Makeev if (preValue != TaskID::UNUSED) 286b7f5a220SSergey Makeev { 287b7f5a220SSergey Makeev pElement->task.~T(); 288b7f5a220SSergey Makeev } 289b7f5a220SSergey Makeev } 290b7f5a220SSergey Makeev 291b7f5a220SSergey Makeev Memory::Free(data); 292b7f5a220SSergey Makeev data = nullptr; 293b7f5a220SSergey Makeev } 294b7f5a220SSergey Makeev } 295b7f5a220SSergey Makeev 29653334f79SSergey Makeev TaskHandle TryAlloc(T && task) 297b7f5a220SSergey Makeev { 29881ec7369SSergey Makeev int idx = index.IncFetch() - 1; 299b7f5a220SSergey Makeev 300b7f5a220SSergey Makeev int clampedIdx = (idx & MASK); 301b7f5a220SSergey Makeev 302b7f5a220SSergey Makeev PoolItem* pElement = Buffer() + clampedIdx; 303b7f5a220SSergey Makeev 30481ec7369SSergey Makeev bool isUnused = ((pElement->id.Load() & 1 ) != 0); 305e455330fSSergey Makeev 30653334f79SSergey Makeev if (isUnused == false) 30753334f79SSergey Makeev { 308b7f5a220SSergey Makeev //Can't allocate more, next element in circular buffer is already used 30953334f79SSergey Makeev return TaskHandle(); 31053334f79SSergey Makeev } 311b7f5a220SSergey Makeev 312b7f5a220SSergey Makeev //generate next even number for id 31381ec7369SSergey Makeev int id = idGenerator.AddFetch(2); 314b7f5a220SSergey Makeev MoveCtor( pElement, id, std::move(task) ); 315b7f5a220SSergey Makeev return TaskHandle(id, pElement); 316b7f5a220SSergey Makeev } 317b7f5a220SSergey Makeev 31853334f79SSergey Makeev 31953334f79SSergey Makeev TaskHandle Alloc(T && task) 32053334f79SSergey Makeev { 32153334f79SSergey Makeev TaskHandle res = TryAlloc(std::move(task)); 32253334f79SSergey Makeev MT_ASSERT(res.IsValid(), "Pool allocation failed"); 32353334f79SSergey Makeev return res; 32453334f79SSergey Makeev } 32553334f79SSergey Makeev 326b7f5a220SSergey Makeev }; 327b7f5a220SSergey Makeev 328b7f5a220SSergey Makeev } 329