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 41*58d12dadSSergey Makeev /// \class PoolElementHeader 42b7f5a220SSergey Makeev /// \brief 43b7f5a220SSergey Makeev ////////////////////////////////////////////////////////////////////////// 44b7f5a220SSergey Makeev struct PoolElementHeader 45b7f5a220SSergey Makeev { 46*58d12dadSSergey Makeev //Task id (timestamp) 47b7f5a220SSergey Makeev AtomicInt id; 48b7f5a220SSergey Makeev 49*58d12dadSSergey 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 70*58d12dadSSergey 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 { 77*58d12dadSSergey Makeev MT_ASSERT( offsetof(PoolElement<T>, task) == sizeof(PoolElementHeader), "Invalid offset for task in PoolElement"); 78*58d12dadSSergey Makeev 79*58d12dadSSergey Makeev desc.poolDestroyFunc = T::PoolTaskDestroy; 80*58d12dadSSergey Makeev desc.taskFunc = T::TaskEntryPoint; 81*58d12dadSSergey Makeev desc.userData = &task; 82*58d12dadSSergey Makeev 83*58d12dadSSergey Makeev #ifdef MT_INSTRUMENTED_BUILD 84*58d12dadSSergey Makeev desc.debugID = T::GetDebugID(); 85*58d12dadSSergey Makeev desc.colorIndex = T::GetDebugColorIndex(); 86*58d12dadSSergey 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 { 97b7f5a220SSergey Makeev 98b7f5a220SSergey Makeev int check_id; 99b7f5a220SSergey Makeev 100b7f5a220SSergey Makeev protected: 101b7f5a220SSergey Makeev 102b7f5a220SSergey Makeev friend struct PoolElementHeader; 103*58d12dadSSergey 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 150b7f5a220SSergey Makeev if (check_id != task->id.Get()) 151b7f5a220SSergey Makeev { 152b7f5a220SSergey Makeev return false; 153b7f5a220SSergey Makeev } 154b7f5a220SSergey Makeev 155b7f5a220SSergey Makeev return true; 156b7f5a220SSergey Makeev } 157b7f5a220SSergey Makeev 158*58d12dadSSergey Makeev const internal::TaskDesc & GetDesc() 159*58d12dadSSergey Makeev { 160*58d12dadSSergey Makeev MT_ASSERT(IsValid(), "Task handle is invalid"); 161*58d12dadSSergey Makeev return task->desc; 162*58d12dadSSergey Makeev } 163*58d12dadSSergey Makeev 164*58d12dadSSergey Makeev 165b7f5a220SSergey Makeev }; 166b7f5a220SSergey Makeev 167b7f5a220SSergey Makeev 168b7f5a220SSergey Makeev 169b7f5a220SSergey Makeev 170b7f5a220SSergey Makeev ////////////////////////////////////////////////////////////////////////// 171b7f5a220SSergey Makeev inline bool PoolElementHeader::DestoryByHandle(const MT::TaskHandle & handle) 172b7f5a220SSergey Makeev { 173b7f5a220SSergey Makeev if (!handle.IsValid()) 174b7f5a220SSergey Makeev { 175b7f5a220SSergey Makeev return false; 176b7f5a220SSergey Makeev } 177b7f5a220SSergey Makeev 178*58d12dadSSergey Makeev if (handle.task->desc.poolDestroyFunc == nullptr) 179*58d12dadSSergey Makeev { 180*58d12dadSSergey Makeev return false; 181*58d12dadSSergey Makeev } 182*58d12dadSSergey Makeev 183*58d12dadSSergey Makeev if (handle.task->desc.userData == nullptr) 184*58d12dadSSergey Makeev { 185*58d12dadSSergey Makeev return false; 186*58d12dadSSergey Makeev } 187*58d12dadSSergey Makeev 188*58d12dadSSergey Makeev //call destroy func 189*58d12dadSSergey Makeev handle.task->desc.poolDestroyFunc(handle.task->desc.userData); 190b7f5a220SSergey Makeev return true; 191b7f5a220SSergey Makeev } 192b7f5a220SSergey Makeev 193b7f5a220SSergey Makeev 194b7f5a220SSergey Makeev 195b7f5a220SSergey Makeev 196b7f5a220SSergey Makeev 197b7f5a220SSergey Makeev /// \class TaskPool 198b7f5a220SSergey Makeev /// \brief 199b7f5a220SSergey Makeev ////////////////////////////////////////////////////////////////////////// 200b7f5a220SSergey Makeev template<typename T, size_t N> 201b7f5a220SSergey Makeev class TaskPool 202b7f5a220SSergey Makeev { 203b7f5a220SSergey Makeev typedef PoolElement<T> PoolItem; 204b7f5a220SSergey Makeev 205b7f5a220SSergey Makeev // 206b7f5a220SSergey Makeev static const size_t MASK = (N - 1); 207b7f5a220SSergey Makeev 208b7f5a220SSergey Makeev void* data; 209b7f5a220SSergey Makeev AtomicInt idGenerator; 210b7f5a220SSergey Makeev AtomicInt index; 211b7f5a220SSergey Makeev 212b7f5a220SSergey Makeev inline PoolItem* Buffer() 213b7f5a220SSergey Makeev { 214b7f5a220SSergey Makeev return (PoolItem*)(data); 215b7f5a220SSergey Makeev } 216b7f5a220SSergey Makeev 217b7f5a220SSergey Makeev inline void MoveCtor(PoolItem* element, int id, T && val) 218b7f5a220SSergey Makeev { 219b7f5a220SSergey Makeev new(element) PoolItem(id, std::move(val)); 220b7f5a220SSergey Makeev } 221b7f5a220SSergey Makeev 222b7f5a220SSergey Makeev private: 223b7f5a220SSergey Makeev 224b7f5a220SSergey Makeev TaskPool(const TaskPool &) {} 225b7f5a220SSergey Makeev void operator=(const TaskPool &) {} 226b7f5a220SSergey Makeev 227b7f5a220SSergey Makeev public: 228b7f5a220SSergey Makeev 229b7f5a220SSergey Makeev TaskPool() 230b7f5a220SSergey Makeev : idGenerator(0) 231b7f5a220SSergey Makeev , index(0) 232b7f5a220SSergey Makeev { 233b7f5a220SSergey Makeev static_assert( MT::StaticIsPow2<N>::result, "Task pool capacity must be power of 2"); 234b7f5a220SSergey Makeev 235b7f5a220SSergey Makeev size_t bytesCount = sizeof(PoolItem) * N; 236b7f5a220SSergey Makeev data = Memory::Alloc(bytesCount); 237b7f5a220SSergey Makeev 238b7f5a220SSergey Makeev for(size_t idx = 0; idx < N; idx++) 239b7f5a220SSergey Makeev { 240b7f5a220SSergey Makeev PoolItem* pElement = Buffer() + idx; 241b7f5a220SSergey Makeev pElement->id.Set(TaskID::UNUSED); 242b7f5a220SSergey Makeev } 243b7f5a220SSergey Makeev } 244b7f5a220SSergey Makeev 245b7f5a220SSergey Makeev ~TaskPool() 246b7f5a220SSergey Makeev { 247b7f5a220SSergey Makeev if (data != nullptr) 248b7f5a220SSergey Makeev { 249b7f5a220SSergey Makeev 250b7f5a220SSergey Makeev for(size_t idx = 0; idx < N; idx++) 251b7f5a220SSergey Makeev { 252b7f5a220SSergey Makeev PoolItem* pElement = Buffer() + idx; 253b7f5a220SSergey Makeev 254b7f5a220SSergey Makeev int preValue = pElement->id.Set(TaskID::UNUSED); 255b7f5a220SSergey Makeev if (preValue != TaskID::UNUSED) 256b7f5a220SSergey Makeev { 257b7f5a220SSergey Makeev pElement->task.~T(); 258b7f5a220SSergey Makeev } 259b7f5a220SSergey Makeev } 260b7f5a220SSergey Makeev 261b7f5a220SSergey Makeev Memory::Free(data); 262b7f5a220SSergey Makeev data = nullptr; 263b7f5a220SSergey Makeev } 264b7f5a220SSergey Makeev } 265b7f5a220SSergey Makeev 266b7f5a220SSergey Makeev 267b7f5a220SSergey Makeev TaskHandle Alloc(T && task) 268b7f5a220SSergey Makeev { 269b7f5a220SSergey Makeev int idx = index.Inc() - 1; 270b7f5a220SSergey Makeev 271b7f5a220SSergey Makeev int clampedIdx = (idx & MASK); 272b7f5a220SSergey Makeev 273b7f5a220SSergey Makeev PoolItem* pElement = Buffer() + clampedIdx; 274b7f5a220SSergey Makeev 275b7f5a220SSergey Makeev bool isUnused = ((pElement->id.Get() & 1 ) != 0); 276b7f5a220SSergey Makeev if (isUnused == false) 277b7f5a220SSergey Makeev { 278b7f5a220SSergey Makeev //Can't allocate more, next element in circular buffer is already used 279b7f5a220SSergey Makeev return TaskHandle(); 280b7f5a220SSergey Makeev } 281b7f5a220SSergey Makeev 282b7f5a220SSergey Makeev //generate next even number for id 283b7f5a220SSergey Makeev int id = idGenerator.Add(2); 284b7f5a220SSergey Makeev MoveCtor( pElement, id, std::move(task) ); 285b7f5a220SSergey Makeev return TaskHandle(id, pElement); 286b7f5a220SSergey Makeev } 287b7f5a220SSergey Makeev 288b7f5a220SSergey Makeev }; 289b7f5a220SSergey Makeev 290b7f5a220SSergey Makeev } 291