Protium
Math and Design Features
 All Classes Namespaces Files Functions Variables Typedefs Enumerator Friends Macros Pages
Chunk.cxx
Go to the documentation of this file.
2 
3 #include <assert.h>
4 #include <bitset>
5 
6 bool Protium::Allocation::Chunk::Init( std::size_t blockSize, unsigned char blocks ){
7  assert(blockSize > 0 && blocks >0);
8  const std::size_t totalSize= blockSize*blocks;
9  assert( totalSize / blockSize == blocks);
10  fData = static_cast<unsigned char* > (operator new(totalSize) );
11  Reset( blockSize, blocks );
12  return true;
13 }
14 
15 void Protium::Allocation::Chunk::Reset(std::size_t blockSize, unsigned char blocks){
16  assert(blockSize > 0 && blocks > 0);
17  fFirstAvailable = 0;
18  fNAvail = blocks;
19  unsigned char i = 0;
20  for ( unsigned char * p = fData; i != blocks; p += blockSize )
21  *p = ++i;
22 }
23 
25  assert( fData != NULL );
26  ::operator delete ( fData );
27 }
28 
29 
30 void* Protium::Allocation::Chunk::Allocate(std::size_t blockSize){
31  if ( IsFilled() ) return NULL;
32 
33  assert((fFirstAvailable * blockSize) / blockSize == fFirstAvailable);
34 
35  unsigned char* result = fData + (fFirstAvailable * blockSize);
36  fFirstAvailable = *result;
37  --fNAvail;
38 
39  return result;
40 }
41 
42 
43 void Protium::Allocation::Chunk::Deallocate(void* p, std::size_t blockSize){
44  assert(p >= fData);
45 
46  unsigned char* toRelease = static_cast<unsigned char*>(p);
47  // Alignment check
48  assert((toRelease - fData) % blockSize == 0);
49  unsigned char index = static_cast< unsigned char >(
50  ( toRelease - fData ) / blockSize);
51 
52 
53  *toRelease = fFirstAvailable;
54  fFirstAvailable = index;
55  // Truncation check
56  assert(fFirstAvailable == (toRelease - fData) / blockSize);
57 
58  ++fNAvail;
59 }
60 
61 bool Protium::Allocation::Chunk::IsCorrupt( unsigned char numBlocks, std::size_t blockSize, bool checkIndexes ) const{
62 
63  if ( numBlocks < fNAvail )
64  {
65  // Contents at this Chunk corrupted. This might mean something has
66  // overwritten memory owned by the Chunks container.
67  assert( false );
68  return true;
69  }
70  if ( IsFilled() )
71  // Useless to do further corruption checks if all blocks allocated.
72  return false;
73  unsigned char index = fFirstAvailable;
74  if ( numBlocks <= index )
75  {
76  // Contents at this Chunk corrupted. This might mean something has
77  // overwritten memory owned by the Chunks container.
78  assert( false );
79  return true;
80  }
81  if ( !checkIndexes )
82  // Caller chose to skip more complex corruption tests.
83  return false;
84 
85  /* If the bit at index was set in foundBlocks, then the stealth index was
86  found on the linked-list.
87  */
88  std::bitset< 256 > foundBlocks;
89  unsigned char * nextBlock = NULL;
90 
91  /* The loop goes along singly linked-list of stealth indexes and makes sure
92  that each index is within bounds (0 <= index < numBlocks) and that the
93  index was not already found while traversing the linked-list. The linked-
94  list should have exactly fNAvail nodes, so the for loop will not
95  check more than fNAvail. This loop can't check inside allocated
96  blocks for corruption since such blocks are not within the linked-list.
97  Contents of allocated blocks are not changed by Chunk.
98 
99  Here are the types of corrupted link-lists which can be verified. The
100  corrupt index is shown with asterisks in each example.
101 
102  Type 1: Index is too big.
103  numBlocks == 64
104  fNAvail == 7
105  fFirstAvailable -> 17 -> 29 -> *101*
106  There should be no indexes which are equal to or larger than the total
107  number of blocks. Such an index would refer to a block beyond the
108  Chunk's allocated domain.
109 
110  Type 2: Index is repeated.
111  numBlocks == 64
112  fNAvail == 5
113  fFirstAvailable -> 17 -> 29 -> 53 -> *17* -> 29 -> 53 ...
114  No index should be repeated within the linked-list since that would
115  indicate the presence of a loop in the linked-list.
116  */
117  for ( unsigned char cc = 0; ; )
118  {
119  nextBlock = fData + ( index * blockSize );
120  foundBlocks.set( index, true );
121  ++cc;
122  if ( cc >= fNAvail )
123  // Successfully counted off number of nodes in linked-list.
124  break;
125  index = *nextBlock;
126  if ( numBlocks <= index )
127  {
128  /* This catches Type 1 corruptions as shown in above comments.
129  This implies that a block was corrupted due to a stray pointer
130  or an operation on a nearby block overran the size of the block.
131  */
132  assert( false );
133  return true;
134  }
135  if ( foundBlocks.test( index ) )
136  {
137  /* This catches Type 2 corruptions as shown in above comments.
138  This implies that a block was corrupted due to a stray pointer
139  or an operation on a nearby block overran the size of the block.
140  Or perhaps the program tried to delete a block more than once.
141  */
142  assert( false );
143  return true;
144  }
145  }
146  if ( foundBlocks.count() != fNAvail )
147  {
148  /* This implies that the singly-linked-list of stealth indexes was
149  corrupted. Ideally, this should have been detected within the loop.
150  */
151  assert( false );
152  return true;
153  }
154 
155  return false;
156 }
157 
158 // Chunk::IsBlockAvailable ----------------------------------------------------
159 
160 bool Protium::Allocation::Chunk::IsBlockAvailable( void * p, unsigned char numBlocks,
161  std::size_t blockSize ) const
162 {
163  (void) numBlocks;
164 
165  if ( IsFilled() )
166  return false;
167 
168  unsigned char * place = static_cast< unsigned char * >( p );
169  // Alignment check
170  assert( ( place - fData ) % blockSize == 0 );
171  unsigned char blockIndex = static_cast< unsigned char >(
172  ( place - fData ) / blockSize );
173 
174  unsigned char index = fFirstAvailable;
175  assert( numBlocks > index );
176  if ( index == blockIndex )
177  return true;
178 
179  /* If the bit at index was set in foundBlocks, then the stealth index was
180  found on the linked-list.
181  */
182  std::bitset< 256 > foundBlocks;
183  unsigned char * nextBlock = NULL;
184  for ( unsigned char cc = 0; ; )
185  {
186  nextBlock = fData + ( index * blockSize );
187  foundBlocks.set( index, true );
188  ++cc;
189  if ( cc >= fNAvail )
190  // Successfully counted off number of nodes in linked-list.
191  break;
192  index = *nextBlock;
193  if ( index == blockIndex )
194  return true;
195  assert( numBlocks > index );
196  assert( !foundBlocks.test( index ) );
197  }
198 
199  return false;
200 }
bool IsCorrupt(unsigned char numBlocks, std::size_t blockSize, bool checkIndexes) const
Definition: Chunk.cxx:61
unsigned char * fData
Definition: Chunk.h:19
void * Allocate(std::size_t blocks)
Allocates out a number of additional blocks.
Definition: Chunk.cxx:30
void Reset(std::size_t blockSize, unsigned char blocks)
Each time a chunk is reused, it needs to be reset.
Definition: Chunk.cxx:15
bool Init(std::size_t size, unsigned char n)
Definition: Chunk.cxx:6
void Deallocate(void *p, std::size_t blocks)
DeAllocates a number of blocks starting at pointer.
Definition: Chunk.cxx:43
void Release()
Deallocates all blocks in chunck.
Definition: Chunk.cxx:24
bool IsBlockAvailable(void *p, unsigned char numBlocks, std::size_t blockSize) const
Checks the block starting at p and for p+numBlocks*blockSize checks to see if they're used...
Definition: Chunk.cxx:160