1 /** \file lvmemman.h
2 \brief Fast memory manager implementation
3
4 CoolReader Engine
5
6 (c) Vadim Lopatin, 2000-2006
7 This source code is distributed under the terms of
8 GNU General Public License.
9
10 See LICENSE file for details.
11
12 */
13
14 #ifndef __LV_MEM_MAN_H_INCLUDED__
15 #define __LV_MEM_MAN_H_INCLUDED__
16
17
18 #include "crsetup.h"
19 #include "lvtypes.h"
20
21 #define CR_FATAL_ERROR_UNKNOWN -1
22 #define CR_FATAL_ERROR_INDEX_OUT_OF_BOUND 1
23
24 /// fatal error function type
25 typedef void (lv_FatalErrorHandler_t)(int errorCode, const char * errorText );
26
27 /// set file to remove of fatal error - for removing of book cache file which caused crash
28 void crSetFileToRemoveOnFatalError(const char * filename);
29
30 /// set signal handler to do some cleanup actions (e.g. delete current cache file since it might be corrupted)
31 void crSetSignalHandler();
32
33 /// fatal error function calls fatal error handler
34 void crFatalError( int code, const char * errorText );
crFatalError()35 inline void crFatalError() { crFatalError( -1, "Unknown fatal error" ); }
36
37 /// set fatal error handler
38 void crSetFatalErrorHandler( lv_FatalErrorHandler_t * handler );
39
40 /// typed realloc with result check (size is counted in T), fatal error if failed
cr_realloc(T * ptr,size_t newSize)41 template <typename T> inline T * cr_realloc( T * ptr, size_t newSize ) {
42 T * newptr = reinterpret_cast<T*>(realloc(ptr, sizeof(T)*newSize));
43 if ( newptr )
44 return newptr;
45 free(ptr); // to bypass cppcheck warning
46 crFatalError(-2, "realloc failed");
47 return NULL;
48 }
49
50
51 #if (LDOM_USE_OWN_MEM_MAN==1)
52 #include <stdlib.h>
53
54 #define THROW_MEM_MAN_EXCEPTION crFatalError(-1, "Memory manager fatal error" );
55
56 #define BLOCK_SIZE_GRANULARITY 2
57 #define LOCAL_STORAGE_COUNT 16
58 #define FIRST_SLICE_SIZE 16
59 #define MAX_SLICE_COUNT 24
60 #define MAX_LOCAL_BLOCK_SIZE ((1<<BLOCK_SIZE_GRANULARITY)*LOCAL_STORAGE_COUNT)
61
62 /// memory block
63 union ldomMemBlock {
64 // struct {
65 char buf[4];
66 // };
67 // struct {
68 ldomMemBlock * nextfree;
69 // };
70 };
71
72 /// memory allocation slice
73 struct ldomMemSlice {
74 ldomMemBlock * pBlocks; // first block
75 ldomMemBlock * pEnd; // first free byte after last block
76 ldomMemBlock * pFree; // first free block
77 size_t block_size; // size of block
78 size_t block_count; // count of blocks
79 size_t blocks_used; // number of used blocks
80 //
blockByIndexldomMemSlice81 inline ldomMemBlock * blockByIndex( size_t index )
82 {
83 return (ldomMemBlock *) ( (char*)pBlocks + (block_size*index) );
84 }
nextBlockldomMemSlice85 inline ldomMemBlock * nextBlock( ldomMemBlock * p )
86 {
87 return (ldomMemBlock *) ( (char*)p + (block_size) );
88 }
prevBlockldomMemSlice89 inline ldomMemBlock * prevBlock( ldomMemBlock * p )
90 {
91 return (ldomMemBlock *) ( (char*)p - (block_size) );
92 }
93 //
ldomMemSliceldomMemSlice94 ldomMemSlice( size_t blockSize, size_t blockCount )
95 : block_size(blockSize),
96 block_count(blockCount),
97 blocks_used(0)
98 {
99
100 pBlocks = (ldomMemBlock *) malloc(block_size * block_count);
101 pEnd = blockByIndex(block_count);
102 pFree = pBlocks;
103 for (ldomMemBlock * p = pBlocks; p<pEnd; )
104 {
105 p = p->nextfree = nextBlock(p);
106 }
107 prevBlock(pEnd)->nextfree = NULL;
108 }
~ldomMemSliceldomMemSlice109 ~ldomMemSlice()
110 {
111 free( pBlocks );
112 }
alloc_blockldomMemSlice113 inline ldomMemBlock * alloc_block()
114 {
115 ldomMemBlock * res = pFree;
116 pFree = res->nextfree;
117 ++blocks_used;
118 return res;
119 }
free_blockldomMemSlice120 inline bool free_block( ldomMemBlock * pBlock )
121 {
122 if (pBlock < pBlocks || pBlock >= pEnd)
123 return false; // chunk does not belong to this slice
124 pBlock->nextfree = pFree;
125 pFree = pBlock;
126 --blocks_used;
127 return true;
128 }
129 };
130
131 /// storage for blocks of specified size
132 struct ldomMemManStorage
133 {
134 size_t block_size; // size of block
135 size_t slice_count; // count of existing blocks
136 ldomMemSlice * slices[MAX_SLICE_COUNT];
137 //======================================
ldomMemManStorageldomMemManStorage138 ldomMemManStorage( size_t blockSize )
139 : block_size(blockSize)
140 {
141 slice_count = 1;
142 slices[0] = new ldomMemSlice(block_size, FIRST_SLICE_SIZE);
143 }
~ldomMemManStorageldomMemManStorage144 ~ldomMemManStorage()
145 {
146 for (size_t i=0; i<slice_count; i++)
147 delete slices[i];
148 }
allocldomMemManStorage149 void * alloc()
150 {
151 // search for existing slice
152 for (int i=slice_count-1; i>=0; --i)
153 {
154 if (slices[i]->pFree != NULL)
155 return slices[i]->alloc_block();
156 }
157 // alloc new slice
158 if (slice_count >= MAX_SLICE_COUNT)
159 THROW_MEM_MAN_EXCEPTION;
160 slices[slice_count] =
161 new ldomMemSlice(block_size, FIRST_SLICE_SIZE << (slice_count+1));
162 return slices[slice_count++]->alloc_block();
163 }
freeldomMemManStorage164 void free( ldomMemBlock * pBlock )
165 {
166 for (int i=slice_count-1; i>=0; --i)
167 {
168 if (slices[i]->free_block(pBlock))
169 return;
170 }
171 //throw; // wrong pointer!!!
172 }
173 };
174
175 /// allocate memory
176 void * ldomAlloc( size_t n );
177 /// free memory
178 void ldomFree( void * p, size_t n );
179
180
181 //////////////////////////////////////////////////////////////////////
182
183 /// declare allocator for class: use in class declarations
184 #define DECLARE_CLASS_ALLOCATOR(classname) \
185 void * operator new( size_t size ); \
186 void operator delete( void * p );
187
188
189 /// define allocator for class: use in class definitions
190 #define DEFINE_CLASS_ALLOCATOR(classname) \
191 \
192 static ldomMemManStorage * pms ## classname = NULL; \
193 \
194 void * classname::operator new( size_t size ) \
195 { \
196 if (pms ## classname == NULL) \
197 { \
198 pms ## classname = new ldomMemManStorage(sizeof(classname)); \
199 } \
200 return pms ## classname->alloc(); \
201 } \
202 \
203 void classname::operator delete( void * p ) \
204 { \
205 pms ## classname->free((ldomMemBlock *)p); \
206 }
207
208 void ldomFreeStorage();
209
210 #endif
211
212 #endif //__LV_MEM_MAN_H_INCLUDED__
213