/* * Copyright (c) 2014, Oculus VR, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * */ /// \file DS_ThreadsafeAllocatingQueue.h /// \internal /// A threadsafe queue, that also uses a memory pool for allocation #ifndef __THREADSAFE_ALLOCATING_QUEUE #define __THREADSAFE_ALLOCATING_QUEUE #include "DS_Queue.hpp" #include "SimpleMutex.hpp" #include "DS_MemoryPool.hpp" // #if defined(new) // #pragma push_macro("new") // #undef new // #define RMO_NEW_UNDEF_ALLOCATING_QUEUE // #endif namespace DataStructures { template class RAK_DLL_EXPORT ThreadsafeAllocatingQueue { public: // Queue operations void Push(structureType *s); structureType *PopInaccurate(void); structureType *Pop(void); void SetPageSize(int size); bool IsEmpty(void); structureType * operator[] ( unsigned int position ); void RemoveAtIndex( unsigned int position ); unsigned int Size( void ); // Memory pool operations structureType *Allocate(const char *file, unsigned int line); void Deallocate(structureType *s, const char *file, unsigned int line); void Clear(const char *file, unsigned int line); protected: mutable MemoryPool memoryPool; RakNet::SimpleMutex memoryPoolMutex; Queue queue; RakNet::SimpleMutex queueMutex; }; template void ThreadsafeAllocatingQueue::Push(structureType *s) { queueMutex.Lock(); queue.Push(s, _FILE_AND_LINE_ ); queueMutex.Unlock(); } template structureType *ThreadsafeAllocatingQueue::PopInaccurate(void) { structureType *s; if (queue.IsEmpty()) return 0; queueMutex.Lock(); if (queue.IsEmpty()==false) s=queue.Pop(); else s=0; queueMutex.Unlock(); return s; } template structureType *ThreadsafeAllocatingQueue::Pop(void) { structureType *s; queueMutex.Lock(); if (queue.IsEmpty()) { queueMutex.Unlock(); return 0; } s=queue.Pop(); queueMutex.Unlock(); return s; } template structureType *ThreadsafeAllocatingQueue::Allocate(const char *file, unsigned int line) { structureType *s; memoryPoolMutex.Lock(); s=memoryPool.Allocate(file, line); memoryPoolMutex.Unlock(); // Call new operator, memoryPool doesn't do this s = new ((void*)s) structureType; return s; } template void ThreadsafeAllocatingQueue::Deallocate(structureType *s, const char *file, unsigned int line) { // Call delete operator, memory pool doesn't do this s->~structureType(); memoryPoolMutex.Lock(); memoryPool.Release(s, file, line); memoryPoolMutex.Unlock(); } template void ThreadsafeAllocatingQueue::Clear(const char *file, unsigned int line) { memoryPoolMutex.Lock(); for (unsigned int i=0; i < queue.Size(); i++) { queue[i]->~structureType(); memoryPool.Release(queue[i], file, line); } queue.Clear(file, line); memoryPoolMutex.Unlock(); memoryPoolMutex.Lock(); memoryPool.Clear(file, line); memoryPoolMutex.Unlock(); } template void ThreadsafeAllocatingQueue::SetPageSize(int size) { memoryPool.SetPageSize(size); } template bool ThreadsafeAllocatingQueue::IsEmpty(void) { bool isEmpty; queueMutex.Lock(); isEmpty=queue.IsEmpty(); queueMutex.Unlock(); return isEmpty; } template structureType * ThreadsafeAllocatingQueue::operator[] ( unsigned int position ) { structureType *s; queueMutex.Lock(); s=queue[position]; queueMutex.Unlock(); return s; } template void ThreadsafeAllocatingQueue::RemoveAtIndex( unsigned int position ) { queueMutex.Lock(); queue.RemoveAtIndex(position); queueMutex.Unlock(); } template unsigned int ThreadsafeAllocatingQueue::Size( void ) { unsigned int s; queueMutex.Lock(); s=queue.Size(); queueMutex.Unlock(); return s; } } // #if defined(RMO_NEW_UNDEF_ALLOCATING_QUEUE) // #pragma pop_macro("new") // #undef RMO_NEW_UNDEF_ALLOCATING_QUEUE // #endif #endif