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