Torque3D Documentation / _generateds / threadSafeFreeList.h

threadSafeFreeList.h

Engine/source/platform/threads/threadSafeFreeList.h

Lock-free freelists for concurrent access.

More...

Classes:

class

Freelist for re-using allocations in a concurrent setting.

class

Baseclass for objects allocated from ThreadSafeFreeLists.

Detailed Description

Lock-free freelists for concurrent access.

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#ifndef _THREADSAFEFREELIST_H_
 25#define _THREADSAFEFREELIST_H_
 26
 27#ifndef _THREADSAFEREFCOUNT_H_
 28#  include "platform/threads/threadSafeRefCount.h"
 29#endif
 30#ifndef _PLATFORMINTRINSICS_H_
 31#  include "platform/platformIntrinsics.h"
 32#endif
 33
 34#include "platform/tmm_off.h"
 35
 36
 37/// @file
 38/// Lock-free freelists for concurrent access.
 39
 40
 41/// Freelist for re-using allocations in a concurrent setting.
 42///
 43/// @note Make sure that there are no more allocations in use
 44///   when the free list is destructed.
 45/// @note Allocated instances come with a reference already counted
 46///   on the instance.
 47///
 48/// @param T Type of elements to allocate; must be derived from
 49///   ThreadSafeRefCount and have at least define one additional
 50///   pointer-sized field.
 51template< class T >
 52class ThreadSafeFreeList
 53{
 54   protected:
 55
 56      T* mFreeList;
 57
 58      #ifdef TORQUE_DEBUG
 59      S32 mNumNodesTotal;
 60      S32 mNumNodesFree;
 61      #endif
 62
 63      T*& getNext( T* ptr )
 64      {
 65         return *( ( T** ) &( ( U8* ) ptr )[ sizeof( T ) - sizeof( T* ) ] );
 66      }
 67
 68   public:
 69
 70      /// Create the freelist.
 71      ///
 72      /// @param numPreAlloc Number of instances to pre-allocate.
 73      ThreadSafeFreeList( U32 numPreAlloc = 0 )
 74         : mFreeList( 0 )
 75      {
 76         #ifdef TORQUE_DEBUG
 77         mNumNodesTotal = 0;
 78         mNumNodesFree = 0;
 79         #endif
 80
 81         for( U32 i = 0; i < numPreAlloc; ++ i )
 82            free( alloc() );
 83      }
 84
 85      ~ThreadSafeFreeList()
 86      {
 87         #ifdef TORQUE_DEBUG
 88         AssertWarn( mNumNodesTotal == mNumNodesFree,
 89            "ThreadSafeFreeList::~ThreadSafeFreeList() - still got live instances" );
 90         #endif
 91
 92         // Destroy remaining nodes.  Not synchronized.  We assume all
 93         // concurrent processing to have finished.
 94
 95         while( mFreeList )
 96         {
 97            T* next = getNext( mFreeList );
 98            dFree( mFreeList );
 99            mFreeList = next;
100         }
101      }
102
103      /// Return memory for a new instance.
104      void* alloc()
105      {
106         T* ptr;
107         while( 1 )
108         {
109            ptr = ThreadSafeRef< T >::safeRead( mFreeList );
110            if( !ptr )
111            {
112               ptr = ( T* ) dMalloc( sizeof( T ) );
113               dMemset( ptr, 0, sizeof( T ) );
114
115               #ifdef TORQUE_DEBUG
116               dFetchAndAdd( mNumNodesTotal, 1 );
117               #endif
118
119               ptr->addRef();
120               break;
121            }
122            else if( dCompareAndSwap( mFreeList, ptr, getNext( ptr ) ) )
123            {
124               #ifdef TORQUE_DEBUG
125               dFetchAndAdd( mNumNodesFree, -1 );
126               #endif
127
128               ptr->clearLowestBit();
129               break;
130            }
131            else
132               ptr->release();
133         }
134
135         return ptr;
136      }
137
138      /// Return the memory allocated to the given instance to the freelist.
139      void free( void* ptr )
140      {
141         AssertFatal( ptr, "ThreadSafeFreeList::free() - got a NULL pointer" );
142         T* node = ( T* ) ptr;
143
144         while( 1 )
145         {
146            T* list = mFreeList;
147            getNext( node ) = list;
148            if( dCompareAndSwap( mFreeList, list, node ) )
149               break;
150         }
151
152         #ifdef TORQUE_DEBUG
153         dFetchAndAdd( mNumNodesFree, 1 );
154         #endif
155      }
156
157      void dumpDebug()
158      {
159         #ifdef TORQUE_DEBUG
160         Platform::outputDebugString( "[ThreadSafeFreeList] total=%i, free=%i",
161            mNumNodesTotal, mNumNodesFree );
162         #endif
163      }
164};
165
166/// Baseclass for objects allocated from ThreadSafeFreeLists.
167template< class T, class DeletePolicy = DeleteSingle >
168class ThreadSafeFreeListNode : public ThreadSafeRefCount< T, DeletePolicy >
169{
170   public:
171
172      typedef ThreadSafeRefCount< T, DeletePolicy> Parent;
173
174      ThreadSafeFreeListNode()
175         : Parent( false ) {}
176
177      static void* operator new( size_t size, ThreadSafeFreeList< T>& freeList )
178      {
179         AssertFatal( size <= sizeof( T ),
180            "ThreadSafeFreeListNode::new() - size exceeds limit of freelist" );
181         TORQUE_UNUSED( size );
182         return freeList.alloc();
183      }
184      static void operator delete( void* ptr, ThreadSafeFreeList< T>& freeList )
185      {
186         freeList.free( ptr );
187      }
188};
189
190
191#include "platform/tmm_on.h"
192
193#endif // _THREADSAFEFREELIST_H_
194