1*b7f5a220SSergey Makeev // The MIT License (MIT) 2*b7f5a220SSergey Makeev // 3*b7f5a220SSergey Makeev // Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev 4*b7f5a220SSergey Makeev // 5*b7f5a220SSergey Makeev // Permission is hereby granted, free of charge, to any person obtaining a copy 6*b7f5a220SSergey Makeev // of this software and associated documentation files (the "Software"), to deal 7*b7f5a220SSergey Makeev // in the Software without restriction, including without limitation the rights 8*b7f5a220SSergey Makeev // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9*b7f5a220SSergey Makeev // copies of the Software, and to permit persons to whom the Software is 10*b7f5a220SSergey Makeev // furnished to do so, subject to the following conditions: 11*b7f5a220SSergey Makeev // 12*b7f5a220SSergey Makeev // The above copyright notice and this permission notice shall be included in 13*b7f5a220SSergey Makeev // all copies or substantial portions of the Software. 14*b7f5a220SSergey Makeev // 15*b7f5a220SSergey Makeev // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16*b7f5a220SSergey Makeev // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17*b7f5a220SSergey Makeev // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18*b7f5a220SSergey Makeev // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19*b7f5a220SSergey Makeev // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20*b7f5a220SSergey Makeev // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21*b7f5a220SSergey Makeev // THE SOFTWARE. 22*b7f5a220SSergey Makeev 23*b7f5a220SSergey Makeev #pragma once 24*b7f5a220SSergey Makeev 25*b7f5a220SSergey Makeev 26*b7f5a220SSergey Makeev 27*b7f5a220SSergey Makeev namespace MT 28*b7f5a220SSergey Makeev { 29*b7f5a220SSergey Makeev 30*b7f5a220SSergey Makeev namespace TaskID 31*b7f5a220SSergey Makeev { 32*b7f5a220SSergey Makeev //unused_id is any odd number, valid_id should be always only even numbers 33*b7f5a220SSergey Makeev static const int UNUSED = 1; 34*b7f5a220SSergey Makeev } 35*b7f5a220SSergey Makeev 36*b7f5a220SSergey Makeev 37*b7f5a220SSergey Makeev //forward declaration 38*b7f5a220SSergey Makeev class TaskHandle; 39*b7f5a220SSergey Makeev 40*b7f5a220SSergey Makeev 41*b7f5a220SSergey Makeev /// \class TaskPoolBase 42*b7f5a220SSergey Makeev /// \brief 43*b7f5a220SSergey Makeev ////////////////////////////////////////////////////////////////////////// 44*b7f5a220SSergey Makeev struct PoolElementHeader 45*b7f5a220SSergey Makeev { 46*b7f5a220SSergey Makeev AtomicInt id; 47*b7f5a220SSergey Makeev 48*b7f5a220SSergey Makeev protected: 49*b7f5a220SSergey Makeev 50*b7f5a220SSergey Makeev virtual void Destroy() 51*b7f5a220SSergey Makeev { 52*b7f5a220SSergey Makeev id.Set(TaskID::UNUSED); 53*b7f5a220SSergey Makeev } 54*b7f5a220SSergey Makeev 55*b7f5a220SSergey Makeev public: 56*b7f5a220SSergey Makeev 57*b7f5a220SSergey Makeev PoolElementHeader(int _id) 58*b7f5a220SSergey Makeev : id(_id) 59*b7f5a220SSergey Makeev { 60*b7f5a220SSergey Makeev } 61*b7f5a220SSergey Makeev 62*b7f5a220SSergey Makeev static bool DestoryByHandle(const MT::TaskHandle & handle); 63*b7f5a220SSergey Makeev }; 64*b7f5a220SSergey Makeev 65*b7f5a220SSergey Makeev 66*b7f5a220SSergey Makeev /// \class TaskPoolElement 67*b7f5a220SSergey Makeev /// \brief 68*b7f5a220SSergey Makeev ////////////////////////////////////////////////////////////////////////// 69*b7f5a220SSergey Makeev template<typename T> 70*b7f5a220SSergey Makeev class PoolElement : public PoolElementHeader 71*b7f5a220SSergey Makeev { 72*b7f5a220SSergey Makeev protected: 73*b7f5a220SSergey Makeev 74*b7f5a220SSergey Makeev virtual void Destroy() 75*b7f5a220SSergey Makeev { 76*b7f5a220SSergey Makeev PoolElementHeader::Destroy(); 77*b7f5a220SSergey Makeev //call dtor 78*b7f5a220SSergey Makeev task.~T(); 79*b7f5a220SSergey Makeev } 80*b7f5a220SSergey Makeev 81*b7f5a220SSergey Makeev public: 82*b7f5a220SSergey Makeev 83*b7f5a220SSergey Makeev T task; 84*b7f5a220SSergey Makeev 85*b7f5a220SSergey Makeev PoolElement(int _id, T && _task) 86*b7f5a220SSergey Makeev : PoolElementHeader(_id) 87*b7f5a220SSergey Makeev , task( std::move(_task) ) 88*b7f5a220SSergey Makeev { 89*b7f5a220SSergey Makeev } 90*b7f5a220SSergey Makeev 91*b7f5a220SSergey Makeev }; 92*b7f5a220SSergey Makeev 93*b7f5a220SSergey Makeev 94*b7f5a220SSergey Makeev /// \class TaskHandle 95*b7f5a220SSergey Makeev /// \brief 96*b7f5a220SSergey Makeev ////////////////////////////////////////////////////////////////////////// 97*b7f5a220SSergey Makeev class TaskHandle 98*b7f5a220SSergey Makeev { 99*b7f5a220SSergey Makeev 100*b7f5a220SSergey Makeev int check_id; 101*b7f5a220SSergey Makeev 102*b7f5a220SSergey Makeev protected: 103*b7f5a220SSergey Makeev 104*b7f5a220SSergey Makeev friend struct PoolElementHeader; 105*b7f5a220SSergey Makeev PoolElementHeader * task; 106*b7f5a220SSergey Makeev 107*b7f5a220SSergey Makeev public: 108*b7f5a220SSergey Makeev 109*b7f5a220SSergey Makeev //default ctor 110*b7f5a220SSergey Makeev TaskHandle() 111*b7f5a220SSergey Makeev : check_id(TaskID::UNUSED) 112*b7f5a220SSergey Makeev , task(nullptr) 113*b7f5a220SSergey Makeev { 114*b7f5a220SSergey Makeev 115*b7f5a220SSergey Makeev } 116*b7f5a220SSergey Makeev 117*b7f5a220SSergey Makeev //ctor 118*b7f5a220SSergey Makeev TaskHandle(int _id, PoolElementHeader* _task) 119*b7f5a220SSergey Makeev : check_id(_id) 120*b7f5a220SSergey Makeev , task(_task) 121*b7f5a220SSergey Makeev { 122*b7f5a220SSergey Makeev } 123*b7f5a220SSergey Makeev 124*b7f5a220SSergey Makeev //copy ctor 125*b7f5a220SSergey Makeev TaskHandle(const TaskHandle & other) 126*b7f5a220SSergey Makeev : check_id(other.check_id) 127*b7f5a220SSergey Makeev , task(other.task) 128*b7f5a220SSergey Makeev { 129*b7f5a220SSergey Makeev } 130*b7f5a220SSergey Makeev 131*b7f5a220SSergey Makeev //move ctor 132*b7f5a220SSergey Makeev TaskHandle(TaskHandle && other) 133*b7f5a220SSergey Makeev : check_id(other.check_id) 134*b7f5a220SSergey Makeev , task(other.task) 135*b7f5a220SSergey Makeev { 136*b7f5a220SSergey Makeev other.check_id = TaskID::UNUSED; 137*b7f5a220SSergey Makeev other.task = nullptr; 138*b7f5a220SSergey Makeev } 139*b7f5a220SSergey Makeev 140*b7f5a220SSergey Makeev ~TaskHandle() 141*b7f5a220SSergey Makeev { 142*b7f5a220SSergey Makeev } 143*b7f5a220SSergey Makeev 144*b7f5a220SSergey Makeev bool IsValid() const 145*b7f5a220SSergey Makeev { 146*b7f5a220SSergey Makeev if (task == nullptr) 147*b7f5a220SSergey Makeev { 148*b7f5a220SSergey Makeev return false; 149*b7f5a220SSergey Makeev } 150*b7f5a220SSergey Makeev 151*b7f5a220SSergey Makeev if (check_id != task->id.Get()) 152*b7f5a220SSergey Makeev { 153*b7f5a220SSergey Makeev return false; 154*b7f5a220SSergey Makeev } 155*b7f5a220SSergey Makeev 156*b7f5a220SSergey Makeev return true; 157*b7f5a220SSergey Makeev } 158*b7f5a220SSergey Makeev 159*b7f5a220SSergey Makeev }; 160*b7f5a220SSergey Makeev 161*b7f5a220SSergey Makeev 162*b7f5a220SSergey Makeev 163*b7f5a220SSergey Makeev 164*b7f5a220SSergey Makeev ////////////////////////////////////////////////////////////////////////// 165*b7f5a220SSergey Makeev inline bool PoolElementHeader::DestoryByHandle(const MT::TaskHandle & handle) 166*b7f5a220SSergey Makeev { 167*b7f5a220SSergey Makeev if (!handle.IsValid()) 168*b7f5a220SSergey Makeev { 169*b7f5a220SSergey Makeev return false; 170*b7f5a220SSergey Makeev } 171*b7f5a220SSergey Makeev 172*b7f5a220SSergey Makeev handle.task->Destroy(); 173*b7f5a220SSergey Makeev return true; 174*b7f5a220SSergey Makeev } 175*b7f5a220SSergey Makeev 176*b7f5a220SSergey Makeev 177*b7f5a220SSergey Makeev 178*b7f5a220SSergey Makeev 179*b7f5a220SSergey Makeev 180*b7f5a220SSergey Makeev /// \class TaskPool 181*b7f5a220SSergey Makeev /// \brief 182*b7f5a220SSergey Makeev ////////////////////////////////////////////////////////////////////////// 183*b7f5a220SSergey Makeev template<typename T, size_t N> 184*b7f5a220SSergey Makeev class TaskPool 185*b7f5a220SSergey Makeev { 186*b7f5a220SSergey Makeev typedef PoolElement<T> PoolItem; 187*b7f5a220SSergey Makeev 188*b7f5a220SSergey Makeev // 189*b7f5a220SSergey Makeev static const size_t MASK = (N - 1); 190*b7f5a220SSergey Makeev 191*b7f5a220SSergey Makeev void* data; 192*b7f5a220SSergey Makeev AtomicInt idGenerator; 193*b7f5a220SSergey Makeev AtomicInt index; 194*b7f5a220SSergey Makeev 195*b7f5a220SSergey Makeev inline PoolItem* Buffer() 196*b7f5a220SSergey Makeev { 197*b7f5a220SSergey Makeev return (PoolItem*)(data); 198*b7f5a220SSergey Makeev } 199*b7f5a220SSergey Makeev 200*b7f5a220SSergey Makeev inline void MoveCtor(PoolItem* element, int id, T && val) 201*b7f5a220SSergey Makeev { 202*b7f5a220SSergey Makeev new(element) PoolItem(id, std::move(val)); 203*b7f5a220SSergey Makeev } 204*b7f5a220SSergey Makeev 205*b7f5a220SSergey Makeev private: 206*b7f5a220SSergey Makeev 207*b7f5a220SSergey Makeev TaskPool(const TaskPool &) {} 208*b7f5a220SSergey Makeev void operator=(const TaskPool &) {} 209*b7f5a220SSergey Makeev 210*b7f5a220SSergey Makeev public: 211*b7f5a220SSergey Makeev 212*b7f5a220SSergey Makeev TaskPool() 213*b7f5a220SSergey Makeev : idGenerator(0) 214*b7f5a220SSergey Makeev , index(0) 215*b7f5a220SSergey Makeev { 216*b7f5a220SSergey Makeev static_assert( MT::StaticIsPow2<N>::result, "Task pool capacity must be power of 2"); 217*b7f5a220SSergey Makeev 218*b7f5a220SSergey Makeev size_t bytesCount = sizeof(PoolItem) * N; 219*b7f5a220SSergey Makeev data = Memory::Alloc(bytesCount); 220*b7f5a220SSergey Makeev 221*b7f5a220SSergey Makeev for(size_t idx = 0; idx < N; idx++) 222*b7f5a220SSergey Makeev { 223*b7f5a220SSergey Makeev PoolItem* pElement = Buffer() + idx; 224*b7f5a220SSergey Makeev pElement->id.Set(TaskID::UNUSED); 225*b7f5a220SSergey Makeev } 226*b7f5a220SSergey Makeev } 227*b7f5a220SSergey Makeev 228*b7f5a220SSergey Makeev ~TaskPool() 229*b7f5a220SSergey Makeev { 230*b7f5a220SSergey Makeev if (data != nullptr) 231*b7f5a220SSergey Makeev { 232*b7f5a220SSergey Makeev 233*b7f5a220SSergey Makeev for(size_t idx = 0; idx < N; idx++) 234*b7f5a220SSergey Makeev { 235*b7f5a220SSergey Makeev PoolItem* pElement = Buffer() + idx; 236*b7f5a220SSergey Makeev 237*b7f5a220SSergey Makeev int preValue = pElement->id.Set(TaskID::UNUSED); 238*b7f5a220SSergey Makeev if (preValue != TaskID::UNUSED) 239*b7f5a220SSergey Makeev { 240*b7f5a220SSergey Makeev pElement->task.~T(); 241*b7f5a220SSergey Makeev } 242*b7f5a220SSergey Makeev } 243*b7f5a220SSergey Makeev 244*b7f5a220SSergey Makeev Memory::Free(data); 245*b7f5a220SSergey Makeev data = nullptr; 246*b7f5a220SSergey Makeev } 247*b7f5a220SSergey Makeev } 248*b7f5a220SSergey Makeev 249*b7f5a220SSergey Makeev 250*b7f5a220SSergey Makeev TaskHandle Alloc(T && task) 251*b7f5a220SSergey Makeev { 252*b7f5a220SSergey Makeev int idx = index.Inc() - 1; 253*b7f5a220SSergey Makeev 254*b7f5a220SSergey Makeev int clampedIdx = (idx & MASK); 255*b7f5a220SSergey Makeev 256*b7f5a220SSergey Makeev PoolItem* pElement = Buffer() + clampedIdx; 257*b7f5a220SSergey Makeev 258*b7f5a220SSergey Makeev bool isUnused = ((pElement->id.Get() & 1 ) != 0); 259*b7f5a220SSergey Makeev if (isUnused == false) 260*b7f5a220SSergey Makeev { 261*b7f5a220SSergey Makeev //Can't allocate more, next element in circular buffer is already used 262*b7f5a220SSergey Makeev return TaskHandle(); 263*b7f5a220SSergey Makeev } 264*b7f5a220SSergey Makeev 265*b7f5a220SSergey Makeev //generate next even number for id 266*b7f5a220SSergey Makeev int id = idGenerator.Add(2); 267*b7f5a220SSergey Makeev MoveCtor( pElement, id, std::move(task) ); 268*b7f5a220SSergey Makeev return TaskHandle(id, pElement); 269*b7f5a220SSergey Makeev } 270*b7f5a220SSergey Makeev 271*b7f5a220SSergey Makeev }; 272*b7f5a220SSergey Makeev 273*b7f5a220SSergey Makeev } 274