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 { 34b23bdf5aSs.makeev_local namespace TaskPriority 35b23bdf5aSs.makeev_local { 36b23bdf5aSs.makeev_local enum Type 37b23bdf5aSs.makeev_local { 38b23bdf5aSs.makeev_local HIGH = 0, 39b23bdf5aSs.makeev_local NORMAL = 1, 40b23bdf5aSs.makeev_local LOW = 2, 41b23bdf5aSs.makeev_local 42b23bdf5aSs.makeev_local COUNT, 43b23bdf5aSs.makeev_local 44b23bdf5aSs.makeev_local INVALID 45b23bdf5aSs.makeev_local }; 46b23bdf5aSs.makeev_local } 47b23bdf5aSs.makeev_local 48d7cf17b1Ss.makeev_local /// \class TaskQueue 49d7cf17b1Ss.makeev_local /// \brief thread safe task queue 50d7cf17b1Ss.makeev_local /// 51b23bdf5aSs.makeev_local template<typename T, uint32 CAPACITY> 52d7cf17b1Ss.makeev_local class TaskQueue 53d7cf17b1Ss.makeev_local { 54d7cf17b1Ss.makeev_local 55b23bdf5aSs.makeev_local ////////////////////////////////////////////////////////////////////////// 56b23bdf5aSs.makeev_local class Queue 57b23bdf5aSs.makeev_local { 58b23bdf5aSs.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 { 88b23bdf5aSs.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 112b23bdf5aSs.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 120b23bdf5aSs.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 129b23bdf5aSs.makeev_local inline bool HasSpace(size_t itemCount) 130d7cf17b1Ss.makeev_local { 131b23bdf5aSs.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 139b23bdf5aSs.makeev_local inline bool Add(const T& item) 140d7cf17b1Ss.makeev_local { 141b23bdf5aSs.makeev_local if ((Size() + 1) >= CAPACITY) 142b23bdf5aSs.makeev_local { 143b23bdf5aSs.makeev_local return false; 144b23bdf5aSs.makeev_local } 145d7cf17b1Ss.makeev_local 146b23bdf5aSs.makeev_local size_t index = (end & MASK); 147b23bdf5aSs.makeev_local T* pElement = Buffer() + index; 148b23bdf5aSs.makeev_local CopyCtor( pElement, item ); 149b23bdf5aSs.makeev_local end++; 150b23bdf5aSs.makeev_local 151b23bdf5aSs.makeev_local return true; 152b23bdf5aSs.makeev_local } 153b23bdf5aSs.makeev_local 154b23bdf5aSs.makeev_local 155b23bdf5aSs.makeev_local inline bool TryPopOldest(T & item) 156b23bdf5aSs.makeev_local { 157b23bdf5aSs.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 170b23bdf5aSs.makeev_local inline bool TryPopNewest(T & item) 171d7cf17b1Ss.makeev_local { 172b23bdf5aSs.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 185b23bdf5aSs.makeev_local inline bool IsEmpty() const 186b23bdf5aSs.makeev_local { 187b23bdf5aSs.makeev_local return (begin == end); 188b23bdf5aSs.makeev_local } 189b23bdf5aSs.makeev_local }; 190b23bdf5aSs.makeev_local ////////////////////////////////////////////////////////////////////////// 191b23bdf5aSs.makeev_local 192b23bdf5aSs.makeev_local MT::Mutex mutex; 193b23bdf5aSs.makeev_local Queue queues[TaskPriority::COUNT]; 194b23bdf5aSs.makeev_local 195b23bdf5aSs.makeev_local public: 196b23bdf5aSs.makeev_local 197b23bdf5aSs.makeev_local MT_NOCOPYABLE(TaskQueue); 198b23bdf5aSs.makeev_local 199b23bdf5aSs.makeev_local TaskQueue() 200b23bdf5aSs.makeev_local { 201b23bdf5aSs.makeev_local } 202b23bdf5aSs.makeev_local 203b23bdf5aSs.makeev_local ~TaskQueue() 204b23bdf5aSs.makeev_local { 205b23bdf5aSs.makeev_local } 206b23bdf5aSs.makeev_local 207b23bdf5aSs.makeev_local bool Add(const T* itemArray, size_t count) 208d7cf17b1Ss.makeev_local { 209d7cf17b1Ss.makeev_local MT::ScopedGuard guard(mutex); 210d7cf17b1Ss.makeev_local 211b23bdf5aSs.makeev_local // Check for space for all queues. 212b23bdf5aSs.makeev_local // At the moment it is not known exactly in what queue items will be added. 213b23bdf5aSs.makeev_local for(size_t i = 0; i < MT_ARRAY_SIZE(queues); i++) 214b23bdf5aSs.makeev_local { 215b23bdf5aSs.makeev_local Queue& queue = queues[i]; 216b23bdf5aSs.makeev_local if (!queue.HasSpace(count)) 217b23bdf5aSs.makeev_local { 218b23bdf5aSs.makeev_local return false; 219d7cf17b1Ss.makeev_local } 220b23bdf5aSs.makeev_local } 221b23bdf5aSs.makeev_local 222b23bdf5aSs.makeev_local // Adding the tasks into the appropriate queue 223b23bdf5aSs.makeev_local for(size_t i = 0; i < count; i++) 224b23bdf5aSs.makeev_local { 225b23bdf5aSs.makeev_local const T& item = itemArray[i]; 226b23bdf5aSs.makeev_local 227b23bdf5aSs.makeev_local uint32 queueIndex = (uint32)item.desc.priority; 228b23bdf5aSs.makeev_local MT_ASSERT(queueIndex < MT_ARRAY_SIZE(queues), "Invalid task priority"); 229b23bdf5aSs.makeev_local 230b23bdf5aSs.makeev_local Queue& queue = queues[queueIndex]; 231b23bdf5aSs.makeev_local bool res = queue.Add(itemArray[i]); 232*0d87ba20Ss.makeev_local MT_USED_IN_ASSERT(res); 233b23bdf5aSs.makeev_local MT_ASSERT(res == true, "Sanity check failed"); 234b23bdf5aSs.makeev_local } 235b23bdf5aSs.makeev_local 236b23bdf5aSs.makeev_local return true; 237b23bdf5aSs.makeev_local } 238b23bdf5aSs.makeev_local 239b23bdf5aSs.makeev_local 240b23bdf5aSs.makeev_local bool TryPopOldest(T & item) 241b23bdf5aSs.makeev_local { 242b23bdf5aSs.makeev_local MT::ScopedGuard guard(mutex); 243b23bdf5aSs.makeev_local for(uint32 queueIndex = 0; queueIndex < TaskPriority::COUNT; queueIndex++) 244b23bdf5aSs.makeev_local { 245b23bdf5aSs.makeev_local Queue& queue = queues[queueIndex]; 246b23bdf5aSs.makeev_local if (queue.TryPopOldest(item)) 247b23bdf5aSs.makeev_local { 248b23bdf5aSs.makeev_local return true; 249b23bdf5aSs.makeev_local } 250b23bdf5aSs.makeev_local } 251b23bdf5aSs.makeev_local return false; 252b23bdf5aSs.makeev_local } 253b23bdf5aSs.makeev_local 254b23bdf5aSs.makeev_local bool TryPopNewest(T & item) 255b23bdf5aSs.makeev_local { 256b23bdf5aSs.makeev_local MT::ScopedGuard guard(mutex); 257b23bdf5aSs.makeev_local for(uint32 queueIndex = 0; queueIndex < TaskPriority::COUNT; queueIndex++) 258b23bdf5aSs.makeev_local { 259b23bdf5aSs.makeev_local Queue& queue = queues[queueIndex]; 260b23bdf5aSs.makeev_local if (queue.TryPopNewest(item)) 261b23bdf5aSs.makeev_local { 262b23bdf5aSs.makeev_local return true; 263b23bdf5aSs.makeev_local } 264b23bdf5aSs.makeev_local } 265b23bdf5aSs.makeev_local return false; 266b23bdf5aSs.makeev_local } 267b23bdf5aSs.makeev_local 268d7cf17b1Ss.makeev_local 269d7cf17b1Ss.makeev_local }; 270d7cf17b1Ss.makeev_local } 271