1d7cf17b1Ss.makeev_local // The MIT License (MIT) 2d7cf17b1Ss.makeev_local // 3d7cf17b1Ss.makeev_local // Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev 4d7cf17b1Ss.makeev_local // 5d7cf17b1Ss.makeev_local // Permission is hereby granted, free of charge, to any person obtaining a copy 6d7cf17b1Ss.makeev_local // of this software and associated documentation files (the "Software"), to deal 7d7cf17b1Ss.makeev_local // in the Software without restriction, including without limitation the rights 8d7cf17b1Ss.makeev_local // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9d7cf17b1Ss.makeev_local // copies of the Software, and to permit persons to whom the Software is 10d7cf17b1Ss.makeev_local // furnished to do so, subject to the following conditions: 11d7cf17b1Ss.makeev_local // 12d7cf17b1Ss.makeev_local // The above copyright notice and this permission notice shall be included in 13d7cf17b1Ss.makeev_local // all copies or substantial portions of the Software. 14d7cf17b1Ss.makeev_local // 15d7cf17b1Ss.makeev_local // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16d7cf17b1Ss.makeev_local // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17d7cf17b1Ss.makeev_local // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18d7cf17b1Ss.makeev_local // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19d7cf17b1Ss.makeev_local // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20d7cf17b1Ss.makeev_local // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21d7cf17b1Ss.makeev_local // THE SOFTWARE. 22d7cf17b1Ss.makeev_local 23d7cf17b1Ss.makeev_local #pragma once 24d7cf17b1Ss.makeev_local 25d7cf17b1Ss.makeev_local #include <vector> 26d7cf17b1Ss.makeev_local 27d7cf17b1Ss.makeev_local #include <MTPlatform.h> 28d7cf17b1Ss.makeev_local #include <MTTools.h> 29d7cf17b1Ss.makeev_local #include <MTAppInterop.h> 30d7cf17b1Ss.makeev_local 31d7cf17b1Ss.makeev_local 32d7cf17b1Ss.makeev_local namespace MT 33d7cf17b1Ss.makeev_local { 34*b23bdf5aSs.makeev_local namespace TaskPriority 35*b23bdf5aSs.makeev_local { 36*b23bdf5aSs.makeev_local enum Type 37*b23bdf5aSs.makeev_local { 38*b23bdf5aSs.makeev_local HIGH = 0, 39*b23bdf5aSs.makeev_local NORMAL = 1, 40*b23bdf5aSs.makeev_local LOW = 2, 41*b23bdf5aSs.makeev_local 42*b23bdf5aSs.makeev_local COUNT, 43*b23bdf5aSs.makeev_local 44*b23bdf5aSs.makeev_local INVALID 45*b23bdf5aSs.makeev_local }; 46*b23bdf5aSs.makeev_local } 47*b23bdf5aSs.makeev_local 48d7cf17b1Ss.makeev_local /// \class TaskQueue 49d7cf17b1Ss.makeev_local /// \brief thread safe task queue 50d7cf17b1Ss.makeev_local /// 51*b23bdf5aSs.makeev_local template<typename T, uint32 CAPACITY> 52d7cf17b1Ss.makeev_local class TaskQueue 53d7cf17b1Ss.makeev_local { 54d7cf17b1Ss.makeev_local 55*b23bdf5aSs.makeev_local ////////////////////////////////////////////////////////////////////////// 56*b23bdf5aSs.makeev_local class Queue 57*b23bdf5aSs.makeev_local { 58*b23bdf5aSs.makeev_local static const int32 ALIGNMENT = 16; 59d7cf17b1Ss.makeev_local static const unsigned int MASK = CAPACITY - 1u; 60d7cf17b1Ss.makeev_local 61d7cf17b1Ss.makeev_local void* data; 62d7cf17b1Ss.makeev_local size_t begin; 63d7cf17b1Ss.makeev_local size_t end; 64d7cf17b1Ss.makeev_local 65d7cf17b1Ss.makeev_local inline T* Buffer() 66d7cf17b1Ss.makeev_local { 67d7cf17b1Ss.makeev_local return (T*)(data); 68d7cf17b1Ss.makeev_local } 69d7cf17b1Ss.makeev_local 70d7cf17b1Ss.makeev_local inline void CopyCtor(T* element, const T & val) 71d7cf17b1Ss.makeev_local { 72d7cf17b1Ss.makeev_local new(element) T(val); 73d7cf17b1Ss.makeev_local } 74d7cf17b1Ss.makeev_local 75d7cf17b1Ss.makeev_local inline void MoveCtor(T* element, T && val) 76d7cf17b1Ss.makeev_local { 77d7cf17b1Ss.makeev_local new(element) T(std::move(val)); 78d7cf17b1Ss.makeev_local } 79d7cf17b1Ss.makeev_local 80d7cf17b1Ss.makeev_local inline void Dtor(T* element) 81d7cf17b1Ss.makeev_local { 82d7cf17b1Ss.makeev_local MT_UNUSED(element); 83d7cf17b1Ss.makeev_local element->~T(); 84d7cf17b1Ss.makeev_local } 85d7cf17b1Ss.makeev_local 86d7cf17b1Ss.makeev_local inline size_t Size() const 87d7cf17b1Ss.makeev_local { 88*b23bdf5aSs.makeev_local if (IsEmpty()) 89d7cf17b1Ss.makeev_local { 90d7cf17b1Ss.makeev_local return 0; 91d7cf17b1Ss.makeev_local } 92d7cf17b1Ss.makeev_local 93d7cf17b1Ss.makeev_local size_t count = ((end & MASK) - (begin & MASK)) & MASK; 94d7cf17b1Ss.makeev_local return count; 95d7cf17b1Ss.makeev_local } 96d7cf17b1Ss.makeev_local 97d7cf17b1Ss.makeev_local inline void Clear() 98d7cf17b1Ss.makeev_local { 99d7cf17b1Ss.makeev_local size_t queueSize = Size(); 100d7cf17b1Ss.makeev_local for (size_t i = 0; i < queueSize; i++) 101d7cf17b1Ss.makeev_local { 102d7cf17b1Ss.makeev_local T* pElement = Buffer() + ((begin + i) & MASK); 103d7cf17b1Ss.makeev_local Dtor(pElement); 104d7cf17b1Ss.makeev_local } 105d7cf17b1Ss.makeev_local 106d7cf17b1Ss.makeev_local begin = 0; 107d7cf17b1Ss.makeev_local end = 0; 108d7cf17b1Ss.makeev_local } 109d7cf17b1Ss.makeev_local 110d7cf17b1Ss.makeev_local public: 111d7cf17b1Ss.makeev_local 112*b23bdf5aSs.makeev_local Queue() 113d7cf17b1Ss.makeev_local : begin(0) 114d7cf17b1Ss.makeev_local , end(0) 115d7cf17b1Ss.makeev_local { 116d7cf17b1Ss.makeev_local size_t bytesCount = sizeof(T) * CAPACITY; 117d7cf17b1Ss.makeev_local data = Memory::Alloc(bytesCount, ALIGNMENT); 118d7cf17b1Ss.makeev_local } 119d7cf17b1Ss.makeev_local 120*b23bdf5aSs.makeev_local ~Queue() 121d7cf17b1Ss.makeev_local { 122d7cf17b1Ss.makeev_local if (data != nullptr) 123d7cf17b1Ss.makeev_local { 124d7cf17b1Ss.makeev_local Memory::Free(data); 125d7cf17b1Ss.makeev_local data = nullptr; 126d7cf17b1Ss.makeev_local } 127d7cf17b1Ss.makeev_local } 128d7cf17b1Ss.makeev_local 129*b23bdf5aSs.makeev_local inline bool HasSpace(size_t itemCount) 130d7cf17b1Ss.makeev_local { 131*b23bdf5aSs.makeev_local if ((Size() + itemCount) >= CAPACITY) 132d7cf17b1Ss.makeev_local { 133d7cf17b1Ss.makeev_local return false; 134d7cf17b1Ss.makeev_local } 135d7cf17b1Ss.makeev_local 136d7cf17b1Ss.makeev_local return true; 137d7cf17b1Ss.makeev_local } 138d7cf17b1Ss.makeev_local 139*b23bdf5aSs.makeev_local inline bool Add(const T& item) 140d7cf17b1Ss.makeev_local { 141*b23bdf5aSs.makeev_local if ((Size() + 1) >= CAPACITY) 142*b23bdf5aSs.makeev_local { 143*b23bdf5aSs.makeev_local return false; 144*b23bdf5aSs.makeev_local } 145d7cf17b1Ss.makeev_local 146*b23bdf5aSs.makeev_local size_t index = (end & MASK); 147*b23bdf5aSs.makeev_local T* pElement = Buffer() + index; 148*b23bdf5aSs.makeev_local CopyCtor( pElement, item ); 149*b23bdf5aSs.makeev_local end++; 150*b23bdf5aSs.makeev_local 151*b23bdf5aSs.makeev_local return true; 152*b23bdf5aSs.makeev_local } 153*b23bdf5aSs.makeev_local 154*b23bdf5aSs.makeev_local 155*b23bdf5aSs.makeev_local inline bool TryPopOldest(T & item) 156*b23bdf5aSs.makeev_local { 157*b23bdf5aSs.makeev_local if (IsEmpty()) 158d7cf17b1Ss.makeev_local { 159d7cf17b1Ss.makeev_local return false; 160d7cf17b1Ss.makeev_local } 161d7cf17b1Ss.makeev_local 162d7cf17b1Ss.makeev_local size_t index = (begin & MASK); 163d7cf17b1Ss.makeev_local T* pElement = Buffer() + index; 164d7cf17b1Ss.makeev_local begin++; 165d7cf17b1Ss.makeev_local item = *pElement; 166d7cf17b1Ss.makeev_local Dtor(pElement); 167d7cf17b1Ss.makeev_local return true; 168d7cf17b1Ss.makeev_local } 169d7cf17b1Ss.makeev_local 170*b23bdf5aSs.makeev_local inline bool TryPopNewest(T & item) 171d7cf17b1Ss.makeev_local { 172*b23bdf5aSs.makeev_local if (IsEmpty()) 173d7cf17b1Ss.makeev_local { 174d7cf17b1Ss.makeev_local return false; 175d7cf17b1Ss.makeev_local } 176d7cf17b1Ss.makeev_local 177d7cf17b1Ss.makeev_local end--; 178d7cf17b1Ss.makeev_local size_t index = (end & MASK); 179d7cf17b1Ss.makeev_local T* pElement = Buffer() + index; 180d7cf17b1Ss.makeev_local item = *pElement; 181d7cf17b1Ss.makeev_local Dtor(pElement); 182d7cf17b1Ss.makeev_local return true; 183d7cf17b1Ss.makeev_local } 184d7cf17b1Ss.makeev_local 185*b23bdf5aSs.makeev_local inline bool IsEmpty() const 186*b23bdf5aSs.makeev_local { 187*b23bdf5aSs.makeev_local return (begin == end); 188*b23bdf5aSs.makeev_local } 189*b23bdf5aSs.makeev_local }; 190*b23bdf5aSs.makeev_local ////////////////////////////////////////////////////////////////////////// 191*b23bdf5aSs.makeev_local 192*b23bdf5aSs.makeev_local MT::Mutex mutex; 193*b23bdf5aSs.makeev_local Queue queues[TaskPriority::COUNT]; 194*b23bdf5aSs.makeev_local 195*b23bdf5aSs.makeev_local public: 196*b23bdf5aSs.makeev_local 197*b23bdf5aSs.makeev_local MT_NOCOPYABLE(TaskQueue); 198*b23bdf5aSs.makeev_local 199*b23bdf5aSs.makeev_local TaskQueue() 200*b23bdf5aSs.makeev_local { 201*b23bdf5aSs.makeev_local } 202*b23bdf5aSs.makeev_local 203*b23bdf5aSs.makeev_local ~TaskQueue() 204*b23bdf5aSs.makeev_local { 205*b23bdf5aSs.makeev_local } 206*b23bdf5aSs.makeev_local 207*b23bdf5aSs.makeev_local bool Add(const T* itemArray, size_t count) 208d7cf17b1Ss.makeev_local { 209d7cf17b1Ss.makeev_local MT::ScopedGuard guard(mutex); 210d7cf17b1Ss.makeev_local 211*b23bdf5aSs.makeev_local // Check for space for all queues. 212*b23bdf5aSs.makeev_local // At the moment it is not known exactly in what queue items will be added. 213*b23bdf5aSs.makeev_local for(size_t i = 0; i < MT_ARRAY_SIZE(queues); i++) 214*b23bdf5aSs.makeev_local { 215*b23bdf5aSs.makeev_local Queue& queue = queues[i]; 216*b23bdf5aSs.makeev_local if (!queue.HasSpace(count)) 217*b23bdf5aSs.makeev_local { 218*b23bdf5aSs.makeev_local return false; 219d7cf17b1Ss.makeev_local } 220*b23bdf5aSs.makeev_local } 221*b23bdf5aSs.makeev_local 222*b23bdf5aSs.makeev_local // Adding the tasks into the appropriate queue 223*b23bdf5aSs.makeev_local for(size_t i = 0; i < count; i++) 224*b23bdf5aSs.makeev_local { 225*b23bdf5aSs.makeev_local const T& item = itemArray[i]; 226*b23bdf5aSs.makeev_local 227*b23bdf5aSs.makeev_local uint32 queueIndex = (uint32)item.desc.priority; 228*b23bdf5aSs.makeev_local MT_ASSERT(queueIndex < MT_ARRAY_SIZE(queues), "Invalid task priority"); 229*b23bdf5aSs.makeev_local 230*b23bdf5aSs.makeev_local Queue& queue = queues[queueIndex]; 231*b23bdf5aSs.makeev_local bool res = queue.Add(itemArray[i]); 232*b23bdf5aSs.makeev_local MT_ASSERT(res == true, "Sanity check failed"); 233*b23bdf5aSs.makeev_local } 234*b23bdf5aSs.makeev_local 235*b23bdf5aSs.makeev_local return true; 236*b23bdf5aSs.makeev_local } 237*b23bdf5aSs.makeev_local 238*b23bdf5aSs.makeev_local 239*b23bdf5aSs.makeev_local bool TryPopOldest(T & item) 240*b23bdf5aSs.makeev_local { 241*b23bdf5aSs.makeev_local MT::ScopedGuard guard(mutex); 242*b23bdf5aSs.makeev_local for(uint32 queueIndex = 0; queueIndex < TaskPriority::COUNT; queueIndex++) 243*b23bdf5aSs.makeev_local { 244*b23bdf5aSs.makeev_local Queue& queue = queues[queueIndex]; 245*b23bdf5aSs.makeev_local if (queue.TryPopOldest(item)) 246*b23bdf5aSs.makeev_local { 247*b23bdf5aSs.makeev_local return true; 248*b23bdf5aSs.makeev_local } 249*b23bdf5aSs.makeev_local } 250*b23bdf5aSs.makeev_local return false; 251*b23bdf5aSs.makeev_local } 252*b23bdf5aSs.makeev_local 253*b23bdf5aSs.makeev_local bool TryPopNewest(T & item) 254*b23bdf5aSs.makeev_local { 255*b23bdf5aSs.makeev_local MT::ScopedGuard guard(mutex); 256*b23bdf5aSs.makeev_local for(uint32 queueIndex = 0; queueIndex < TaskPriority::COUNT; queueIndex++) 257*b23bdf5aSs.makeev_local { 258*b23bdf5aSs.makeev_local Queue& queue = queues[queueIndex]; 259*b23bdf5aSs.makeev_local if (queue.TryPopNewest(item)) 260*b23bdf5aSs.makeev_local { 261*b23bdf5aSs.makeev_local return true; 262*b23bdf5aSs.makeev_local } 263*b23bdf5aSs.makeev_local } 264*b23bdf5aSs.makeev_local return false; 265*b23bdf5aSs.makeev_local } 266*b23bdf5aSs.makeev_local 267d7cf17b1Ss.makeev_local 268d7cf17b1Ss.makeev_local }; 269d7cf17b1Ss.makeev_local } 270