EPICS Base  7.0.6.1
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
tsFreeList.h
1 /*************************************************************************\
2 * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3 * National Laboratory.
4 * Copyright (c) 2002 The Regents of the University of California, as
5 * Operator of Los Alamos National Laboratory.
6 * SPDX-License-Identifier: EPICS
7 * EPICS Base is distributed subject to a Software License Agreement found
8 * in file LICENSE that is included with this distribution.
9 \*************************************************************************/
10 
11 #ifndef tsFreeList_h
12 #define tsFreeList_h
13 
14 /*
15  * Author: Jeff Hill
16  */
17 
18 //
19 // TODO: this should allow free list chaining so that a free
20 // list (in a different lock domain) is used to provide the
21 // tsFreeListChunk.
22 //
23 
24 //
25 // To allow your class to be allocated off of a free list
26 // using the new operator:
27 //
28 // 1) add the following static, private free list data members
29 // to your class
30 //
31 // static tsFreeList < class classXYZ > freeList;
32 //
33 // 2) add the following member functions to your class
34 //
35 // inline void * classXYZ::operator new ( size_t size )
36 // {
37 // return freeList.allocate ( size );
38 // }
39 //
40 // inline void classXYZ::operator delete ( void *pCadaver, size_t size )
41 // {
42 // freeList.release ( pCadaver, size );
43 // }
44 //
45 // NOTES:
46 //
47 // 1) A NOOP mutex class may be specified if mutual exclusion isn't required
48 //
49 // 2) If you wish to force use of the new operator, then declare your class's
50 // destructor as a protected member function.
51 //
52 // 3) Setting N to zero causes the free list to be bypassed
53 //
54 
55 #ifdef EPICS_FREELIST_DEBUG
56 # define tsFreeListDebugBypass 1
57 # define tsFreeListMemSetNew(P,SIZE) memset ( (P), 0xaa, (SIZE) )
58 # define tsFreeListMemSetDelete(P,SIZE) memset ( (P), 0xdd, (SIZE) )
59 #else
60 # define tsFreeListDebugBypass 0
61 # define tsFreeListMemSetNew(P,SIZE)
62 # define tsFreeListMemSetDelete(P,SIZE)
63 #endif
64 
65 #include <new>
66 #include "string.h"
67 
68 #include "compilerDependencies.h"
69 #include "epicsMutex.h"
70 #include "epicsGuard.h"
71 
72 // ms visual studio 6.0 and before incorrectly
73 // warn about a missing delete operator if only the
74 // newly preferred delete operator with a size argument
75 // is present
76 #if defined ( _MSC_VER ) && _MSC_VER <= 1200
77 # pragma warning ( disable : 4291 )
78 #endif
79 
80 template < class T > union tsFreeListItem;
81 template < class T, unsigned N> struct tsFreeListChunk;
82 
83 template < class T, unsigned N = 0x400,
84  class MUTEX = epicsMutex >
85 class tsFreeList {
86 public:
87  tsFreeList ();
88  ~tsFreeList ();
89  void * allocate ( size_t size );
90  void release ( void * p );
91  void release ( void * p, size_t size );
92 private:
93  MUTEX mutex;
94  tsFreeListItem < T > * pFreeList;
95  tsFreeListChunk < T, N > * pChunkList;
96  void * allocateFromNewChunk ();
97 };
98 
99 template < class T >
100 union tsFreeListItem {
101 public:
102  char pad [ sizeof ( T ) ];
103  tsFreeListItem < T > * pNext;
104 };
105 
106 template < class T, unsigned N = 0x400 >
107 struct tsFreeListChunk {
108  tsFreeListItem < T > items [N];
109  tsFreeListChunk < T, N > * pNext;
110 };
111 
112 template < class T, unsigned N, class MUTEX >
114  pFreeList ( 0 ), pChunkList ( 0 ) {}
115 
116 template < class T, unsigned N, class MUTEX >
117 tsFreeList < T, N, MUTEX > :: ~tsFreeList ()
118 {
119  while ( tsFreeListChunk < T, N > *pChunk = this->pChunkList ) {
120  this->pChunkList = this->pChunkList->pNext;
121  delete pChunk;
122  }
123 }
124 
125 template < class T, unsigned N, class MUTEX >
126 void * tsFreeList < T, N, MUTEX >::allocate ( size_t size )
127 {
128  if ( size != sizeof ( T ) || N == 0u || tsFreeListDebugBypass ) {
129  void * p = ::operator new ( size );
130  tsFreeListMemSetNew ( p, size );
131  return p;
132  }
133 
134  epicsGuard < MUTEX > guard ( this->mutex );
135 
136  tsFreeListItem < T > * p = this->pFreeList;
137  if ( p ) {
138  this->pFreeList = p->pNext;
139  return static_cast < void * > ( p );
140  }
141  return this->allocateFromNewChunk ();
142 }
143 
144 template < class T, unsigned N, class MUTEX >
146 {
147  tsFreeListChunk < T, N > * pChunk =
149 
150  for ( unsigned i=1u; i < N-1; i++ ) {
151  pChunk->items[i].pNext = &pChunk->items[i+1];
152  }
153  pChunk->items[N-1].pNext = 0;
154  if ( N > 1 ) {
155  this->pFreeList = &pChunk->items[1u];
156  }
157  pChunk->pNext = this->pChunkList;
158  this->pChunkList = pChunk;
159 
160  return static_cast <void *> ( &pChunk->items[0] );
161 }
162 
163 template < class T, unsigned N, class MUTEX >
164 void tsFreeList < T, N, MUTEX >::release ( void * pCadaver, size_t size )
165 {
166  if ( size != sizeof ( T ) ) {
167  tsFreeListMemSetDelete ( pCadaver, size );
168  ::operator delete ( pCadaver );
169  }
170  else {
171  this->release ( pCadaver );
172  }
173 }
174 
175 template < class T, unsigned N, class MUTEX >
176 void tsFreeList < T, N, MUTEX >::release ( void * pCadaver )
177 {
178  if ( N == 0u || tsFreeListDebugBypass ) {
179  tsFreeListMemSetDelete ( pCadaver, sizeof ( T ) );
180  ::operator delete ( pCadaver );
181  }
182  else if ( pCadaver ) {
183  epicsGuard < MUTEX > guard ( this->mutex );
185  static_cast < tsFreeListItem < T > * > ( pCadaver );
186  p->pNext = this->pFreeList;
187  this->pFreeList = p;
188  }
189 }
190 
191 #endif // tsFreeList_h
Compiler specific declarations.
The C++ API for an epicsMutex.
Definition: epicsMutex.h:69
APIs for the epicsMutex mutual exclusion semaphore.