OLD | NEW |
| (Empty) |
1 /* | |
2 ** 2007 October 14 | |
3 ** | |
4 ** The author disclaims copyright to this source code. In place of | |
5 ** a legal notice, here is a blessing: | |
6 ** | |
7 ** May you do good and not evil. | |
8 ** May you find forgiveness for yourself and forgive others. | |
9 ** May you share freely, never taking more than you give. | |
10 ** | |
11 ************************************************************************* | |
12 ** This file contains the C functions that implement a memory | |
13 ** allocation subsystem for use by SQLite. | |
14 ** | |
15 ** This version of the memory allocation subsystem omits all | |
16 ** use of malloc(). The SQLite user supplies a block of memory | |
17 ** before calling sqlite3_initialize() from which allocations | |
18 ** are made and returned by the xMalloc() and xRealloc() | |
19 ** implementations. Once sqlite3_initialize() has been called, | |
20 ** the amount of memory available to SQLite is fixed and cannot | |
21 ** be changed. | |
22 ** | |
23 ** This version of the memory allocation subsystem is included | |
24 ** in the build only if SQLITE_ENABLE_MEMSYS3 is defined. | |
25 */ | |
26 #include "sqliteInt.h" | |
27 | |
28 /* | |
29 ** This version of the memory allocator is only built into the library | |
30 ** SQLITE_ENABLE_MEMSYS3 is defined. Defining this symbol does not | |
31 ** mean that the library will use a memory-pool by default, just that | |
32 ** it is available. The mempool allocator is activated by calling | |
33 ** sqlite3_config(). | |
34 */ | |
35 #ifdef SQLITE_ENABLE_MEMSYS3 | |
36 | |
37 /* | |
38 ** Maximum size (in Mem3Blocks) of a "small" chunk. | |
39 */ | |
40 #define MX_SMALL 10 | |
41 | |
42 | |
43 /* | |
44 ** Number of freelist hash slots | |
45 */ | |
46 #define N_HASH 61 | |
47 | |
48 /* | |
49 ** A memory allocation (also called a "chunk") consists of two or | |
50 ** more blocks where each block is 8 bytes. The first 8 bytes are | |
51 ** a header that is not returned to the user. | |
52 ** | |
53 ** A chunk is two or more blocks that is either checked out or | |
54 ** free. The first block has format u.hdr. u.hdr.size4x is 4 times the | |
55 ** size of the allocation in blocks if the allocation is free. | |
56 ** The u.hdr.size4x&1 bit is true if the chunk is checked out and | |
57 ** false if the chunk is on the freelist. The u.hdr.size4x&2 bit | |
58 ** is true if the previous chunk is checked out and false if the | |
59 ** previous chunk is free. The u.hdr.prevSize field is the size of | |
60 ** the previous chunk in blocks if the previous chunk is on the | |
61 ** freelist. If the previous chunk is checked out, then | |
62 ** u.hdr.prevSize can be part of the data for that chunk and should | |
63 ** not be read or written. | |
64 ** | |
65 ** We often identify a chunk by its index in mem3.aPool[]. When | |
66 ** this is done, the chunk index refers to the second block of | |
67 ** the chunk. In this way, the first chunk has an index of 1. | |
68 ** A chunk index of 0 means "no such chunk" and is the equivalent | |
69 ** of a NULL pointer. | |
70 ** | |
71 ** The second block of free chunks is of the form u.list. The | |
72 ** two fields form a double-linked list of chunks of related sizes. | |
73 ** Pointers to the head of the list are stored in mem3.aiSmall[] | |
74 ** for smaller chunks and mem3.aiHash[] for larger chunks. | |
75 ** | |
76 ** The second block of a chunk is user data if the chunk is checked | |
77 ** out. If a chunk is checked out, the user data may extend into | |
78 ** the u.hdr.prevSize value of the following chunk. | |
79 */ | |
80 typedef struct Mem3Block Mem3Block; | |
81 struct Mem3Block { | |
82 union { | |
83 struct { | |
84 u32 prevSize; /* Size of previous chunk in Mem3Block elements */ | |
85 u32 size4x; /* 4x the size of current chunk in Mem3Block elements */ | |
86 } hdr; | |
87 struct { | |
88 u32 next; /* Index in mem3.aPool[] of next free chunk */ | |
89 u32 prev; /* Index in mem3.aPool[] of previous free chunk */ | |
90 } list; | |
91 } u; | |
92 }; | |
93 | |
94 /* | |
95 ** All of the static variables used by this module are collected | |
96 ** into a single structure named "mem3". This is to keep the | |
97 ** static variables organized and to reduce namespace pollution | |
98 ** when this module is combined with other in the amalgamation. | |
99 */ | |
100 static SQLITE_WSD struct Mem3Global { | |
101 /* | |
102 ** Memory available for allocation. nPool is the size of the array | |
103 ** (in Mem3Blocks) pointed to by aPool less 2. | |
104 */ | |
105 u32 nPool; | |
106 Mem3Block *aPool; | |
107 | |
108 /* | |
109 ** True if we are evaluating an out-of-memory callback. | |
110 */ | |
111 int alarmBusy; | |
112 | |
113 /* | |
114 ** Mutex to control access to the memory allocation subsystem. | |
115 */ | |
116 sqlite3_mutex *mutex; | |
117 | |
118 /* | |
119 ** The minimum amount of free space that we have seen. | |
120 */ | |
121 u32 mnMaster; | |
122 | |
123 /* | |
124 ** iMaster is the index of the master chunk. Most new allocations | |
125 ** occur off of this chunk. szMaster is the size (in Mem3Blocks) | |
126 ** of the current master. iMaster is 0 if there is not master chunk. | |
127 ** The master chunk is not in either the aiHash[] or aiSmall[]. | |
128 */ | |
129 u32 iMaster; | |
130 u32 szMaster; | |
131 | |
132 /* | |
133 ** Array of lists of free blocks according to the block size | |
134 ** for smaller chunks, or a hash on the block size for larger | |
135 ** chunks. | |
136 */ | |
137 u32 aiSmall[MX_SMALL-1]; /* For sizes 2 through MX_SMALL, inclusive */ | |
138 u32 aiHash[N_HASH]; /* For sizes MX_SMALL+1 and larger */ | |
139 } mem3 = { 97535575 }; | |
140 | |
141 #define mem3 GLOBAL(struct Mem3Global, mem3) | |
142 | |
143 /* | |
144 ** Unlink the chunk at mem3.aPool[i] from list it is currently | |
145 ** on. *pRoot is the list that i is a member of. | |
146 */ | |
147 static void memsys3UnlinkFromList(u32 i, u32 *pRoot){ | |
148 u32 next = mem3.aPool[i].u.list.next; | |
149 u32 prev = mem3.aPool[i].u.list.prev; | |
150 assert( sqlite3_mutex_held(mem3.mutex) ); | |
151 if( prev==0 ){ | |
152 *pRoot = next; | |
153 }else{ | |
154 mem3.aPool[prev].u.list.next = next; | |
155 } | |
156 if( next ){ | |
157 mem3.aPool[next].u.list.prev = prev; | |
158 } | |
159 mem3.aPool[i].u.list.next = 0; | |
160 mem3.aPool[i].u.list.prev = 0; | |
161 } | |
162 | |
163 /* | |
164 ** Unlink the chunk at index i from | |
165 ** whatever list is currently a member of. | |
166 */ | |
167 static void memsys3Unlink(u32 i){ | |
168 u32 size, hash; | |
169 assert( sqlite3_mutex_held(mem3.mutex) ); | |
170 assert( (mem3.aPool[i-1].u.hdr.size4x & 1)==0 ); | |
171 assert( i>=1 ); | |
172 size = mem3.aPool[i-1].u.hdr.size4x/4; | |
173 assert( size==mem3.aPool[i+size-1].u.hdr.prevSize ); | |
174 assert( size>=2 ); | |
175 if( size <= MX_SMALL ){ | |
176 memsys3UnlinkFromList(i, &mem3.aiSmall[size-2]); | |
177 }else{ | |
178 hash = size % N_HASH; | |
179 memsys3UnlinkFromList(i, &mem3.aiHash[hash]); | |
180 } | |
181 } | |
182 | |
183 /* | |
184 ** Link the chunk at mem3.aPool[i] so that is on the list rooted | |
185 ** at *pRoot. | |
186 */ | |
187 static void memsys3LinkIntoList(u32 i, u32 *pRoot){ | |
188 assert( sqlite3_mutex_held(mem3.mutex) ); | |
189 mem3.aPool[i].u.list.next = *pRoot; | |
190 mem3.aPool[i].u.list.prev = 0; | |
191 if( *pRoot ){ | |
192 mem3.aPool[*pRoot].u.list.prev = i; | |
193 } | |
194 *pRoot = i; | |
195 } | |
196 | |
197 /* | |
198 ** Link the chunk at index i into either the appropriate | |
199 ** small chunk list, or into the large chunk hash table. | |
200 */ | |
201 static void memsys3Link(u32 i){ | |
202 u32 size, hash; | |
203 assert( sqlite3_mutex_held(mem3.mutex) ); | |
204 assert( i>=1 ); | |
205 assert( (mem3.aPool[i-1].u.hdr.size4x & 1)==0 ); | |
206 size = mem3.aPool[i-1].u.hdr.size4x/4; | |
207 assert( size==mem3.aPool[i+size-1].u.hdr.prevSize ); | |
208 assert( size>=2 ); | |
209 if( size <= MX_SMALL ){ | |
210 memsys3LinkIntoList(i, &mem3.aiSmall[size-2]); | |
211 }else{ | |
212 hash = size % N_HASH; | |
213 memsys3LinkIntoList(i, &mem3.aiHash[hash]); | |
214 } | |
215 } | |
216 | |
217 /* | |
218 ** If the STATIC_MEM mutex is not already held, obtain it now. The mutex | |
219 ** will already be held (obtained by code in malloc.c) if | |
220 ** sqlite3GlobalConfig.bMemStat is true. | |
221 */ | |
222 static void memsys3Enter(void){ | |
223 if( sqlite3GlobalConfig.bMemstat==0 && mem3.mutex==0 ){ | |
224 mem3.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); | |
225 } | |
226 sqlite3_mutex_enter(mem3.mutex); | |
227 } | |
228 static void memsys3Leave(void){ | |
229 sqlite3_mutex_leave(mem3.mutex); | |
230 } | |
231 | |
232 /* | |
233 ** Called when we are unable to satisfy an allocation of nBytes. | |
234 */ | |
235 static void memsys3OutOfMemory(int nByte){ | |
236 if( !mem3.alarmBusy ){ | |
237 mem3.alarmBusy = 1; | |
238 assert( sqlite3_mutex_held(mem3.mutex) ); | |
239 sqlite3_mutex_leave(mem3.mutex); | |
240 sqlite3_release_memory(nByte); | |
241 sqlite3_mutex_enter(mem3.mutex); | |
242 mem3.alarmBusy = 0; | |
243 } | |
244 } | |
245 | |
246 | |
247 /* | |
248 ** Chunk i is a free chunk that has been unlinked. Adjust its | |
249 ** size parameters for check-out and return a pointer to the | |
250 ** user portion of the chunk. | |
251 */ | |
252 static void *memsys3Checkout(u32 i, u32 nBlock){ | |
253 u32 x; | |
254 assert( sqlite3_mutex_held(mem3.mutex) ); | |
255 assert( i>=1 ); | |
256 assert( mem3.aPool[i-1].u.hdr.size4x/4==nBlock ); | |
257 assert( mem3.aPool[i+nBlock-1].u.hdr.prevSize==nBlock ); | |
258 x = mem3.aPool[i-1].u.hdr.size4x; | |
259 mem3.aPool[i-1].u.hdr.size4x = nBlock*4 | 1 | (x&2); | |
260 mem3.aPool[i+nBlock-1].u.hdr.prevSize = nBlock; | |
261 mem3.aPool[i+nBlock-1].u.hdr.size4x |= 2; | |
262 return &mem3.aPool[i]; | |
263 } | |
264 | |
265 /* | |
266 ** Carve a piece off of the end of the mem3.iMaster free chunk. | |
267 ** Return a pointer to the new allocation. Or, if the master chunk | |
268 ** is not large enough, return 0. | |
269 */ | |
270 static void *memsys3FromMaster(u32 nBlock){ | |
271 assert( sqlite3_mutex_held(mem3.mutex) ); | |
272 assert( mem3.szMaster>=nBlock ); | |
273 if( nBlock>=mem3.szMaster-1 ){ | |
274 /* Use the entire master */ | |
275 void *p = memsys3Checkout(mem3.iMaster, mem3.szMaster); | |
276 mem3.iMaster = 0; | |
277 mem3.szMaster = 0; | |
278 mem3.mnMaster = 0; | |
279 return p; | |
280 }else{ | |
281 /* Split the master block. Return the tail. */ | |
282 u32 newi, x; | |
283 newi = mem3.iMaster + mem3.szMaster - nBlock; | |
284 assert( newi > mem3.iMaster+1 ); | |
285 mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = nBlock; | |
286 mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x |= 2; | |
287 mem3.aPool[newi-1].u.hdr.size4x = nBlock*4 + 1; | |
288 mem3.szMaster -= nBlock; | |
289 mem3.aPool[newi-1].u.hdr.prevSize = mem3.szMaster; | |
290 x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2; | |
291 mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x; | |
292 if( mem3.szMaster < mem3.mnMaster ){ | |
293 mem3.mnMaster = mem3.szMaster; | |
294 } | |
295 return (void*)&mem3.aPool[newi]; | |
296 } | |
297 } | |
298 | |
299 /* | |
300 ** *pRoot is the head of a list of free chunks of the same size | |
301 ** or same size hash. In other words, *pRoot is an entry in either | |
302 ** mem3.aiSmall[] or mem3.aiHash[]. | |
303 ** | |
304 ** This routine examines all entries on the given list and tries | |
305 ** to coalesce each entries with adjacent free chunks. | |
306 ** | |
307 ** If it sees a chunk that is larger than mem3.iMaster, it replaces | |
308 ** the current mem3.iMaster with the new larger chunk. In order for | |
309 ** this mem3.iMaster replacement to work, the master chunk must be | |
310 ** linked into the hash tables. That is not the normal state of | |
311 ** affairs, of course. The calling routine must link the master | |
312 ** chunk before invoking this routine, then must unlink the (possibly | |
313 ** changed) master chunk once this routine has finished. | |
314 */ | |
315 static void memsys3Merge(u32 *pRoot){ | |
316 u32 iNext, prev, size, i, x; | |
317 | |
318 assert( sqlite3_mutex_held(mem3.mutex) ); | |
319 for(i=*pRoot; i>0; i=iNext){ | |
320 iNext = mem3.aPool[i].u.list.next; | |
321 size = mem3.aPool[i-1].u.hdr.size4x; | |
322 assert( (size&1)==0 ); | |
323 if( (size&2)==0 ){ | |
324 memsys3UnlinkFromList(i, pRoot); | |
325 assert( i > mem3.aPool[i-1].u.hdr.prevSize ); | |
326 prev = i - mem3.aPool[i-1].u.hdr.prevSize; | |
327 if( prev==iNext ){ | |
328 iNext = mem3.aPool[prev].u.list.next; | |
329 } | |
330 memsys3Unlink(prev); | |
331 size = i + size/4 - prev; | |
332 x = mem3.aPool[prev-1].u.hdr.size4x & 2; | |
333 mem3.aPool[prev-1].u.hdr.size4x = size*4 | x; | |
334 mem3.aPool[prev+size-1].u.hdr.prevSize = size; | |
335 memsys3Link(prev); | |
336 i = prev; | |
337 }else{ | |
338 size /= 4; | |
339 } | |
340 if( size>mem3.szMaster ){ | |
341 mem3.iMaster = i; | |
342 mem3.szMaster = size; | |
343 } | |
344 } | |
345 } | |
346 | |
347 /* | |
348 ** Return a block of memory of at least nBytes in size. | |
349 ** Return NULL if unable. | |
350 ** | |
351 ** This function assumes that the necessary mutexes, if any, are | |
352 ** already held by the caller. Hence "Unsafe". | |
353 */ | |
354 static void *memsys3MallocUnsafe(int nByte){ | |
355 u32 i; | |
356 u32 nBlock; | |
357 u32 toFree; | |
358 | |
359 assert( sqlite3_mutex_held(mem3.mutex) ); | |
360 assert( sizeof(Mem3Block)==8 ); | |
361 if( nByte<=12 ){ | |
362 nBlock = 2; | |
363 }else{ | |
364 nBlock = (nByte + 11)/8; | |
365 } | |
366 assert( nBlock>=2 ); | |
367 | |
368 /* STEP 1: | |
369 ** Look for an entry of the correct size in either the small | |
370 ** chunk table or in the large chunk hash table. This is | |
371 ** successful most of the time (about 9 times out of 10). | |
372 */ | |
373 if( nBlock <= MX_SMALL ){ | |
374 i = mem3.aiSmall[nBlock-2]; | |
375 if( i>0 ){ | |
376 memsys3UnlinkFromList(i, &mem3.aiSmall[nBlock-2]); | |
377 return memsys3Checkout(i, nBlock); | |
378 } | |
379 }else{ | |
380 int hash = nBlock % N_HASH; | |
381 for(i=mem3.aiHash[hash]; i>0; i=mem3.aPool[i].u.list.next){ | |
382 if( mem3.aPool[i-1].u.hdr.size4x/4==nBlock ){ | |
383 memsys3UnlinkFromList(i, &mem3.aiHash[hash]); | |
384 return memsys3Checkout(i, nBlock); | |
385 } | |
386 } | |
387 } | |
388 | |
389 /* STEP 2: | |
390 ** Try to satisfy the allocation by carving a piece off of the end | |
391 ** of the master chunk. This step usually works if step 1 fails. | |
392 */ | |
393 if( mem3.szMaster>=nBlock ){ | |
394 return memsys3FromMaster(nBlock); | |
395 } | |
396 | |
397 | |
398 /* STEP 3: | |
399 ** Loop through the entire memory pool. Coalesce adjacent free | |
400 ** chunks. Recompute the master chunk as the largest free chunk. | |
401 ** Then try again to satisfy the allocation by carving a piece off | |
402 ** of the end of the master chunk. This step happens very | |
403 ** rarely (we hope!) | |
404 */ | |
405 for(toFree=nBlock*16; toFree<(mem3.nPool*16); toFree *= 2){ | |
406 memsys3OutOfMemory(toFree); | |
407 if( mem3.iMaster ){ | |
408 memsys3Link(mem3.iMaster); | |
409 mem3.iMaster = 0; | |
410 mem3.szMaster = 0; | |
411 } | |
412 for(i=0; i<N_HASH; i++){ | |
413 memsys3Merge(&mem3.aiHash[i]); | |
414 } | |
415 for(i=0; i<MX_SMALL-1; i++){ | |
416 memsys3Merge(&mem3.aiSmall[i]); | |
417 } | |
418 if( mem3.szMaster ){ | |
419 memsys3Unlink(mem3.iMaster); | |
420 if( mem3.szMaster>=nBlock ){ | |
421 return memsys3FromMaster(nBlock); | |
422 } | |
423 } | |
424 } | |
425 | |
426 /* If none of the above worked, then we fail. */ | |
427 return 0; | |
428 } | |
429 | |
430 /* | |
431 ** Free an outstanding memory allocation. | |
432 ** | |
433 ** This function assumes that the necessary mutexes, if any, are | |
434 ** already held by the caller. Hence "Unsafe". | |
435 */ | |
436 static void memsys3FreeUnsafe(void *pOld){ | |
437 Mem3Block *p = (Mem3Block*)pOld; | |
438 int i; | |
439 u32 size, x; | |
440 assert( sqlite3_mutex_held(mem3.mutex) ); | |
441 assert( p>mem3.aPool && p<&mem3.aPool[mem3.nPool] ); | |
442 i = p - mem3.aPool; | |
443 assert( (mem3.aPool[i-1].u.hdr.size4x&1)==1 ); | |
444 size = mem3.aPool[i-1].u.hdr.size4x/4; | |
445 assert( i+size<=mem3.nPool+1 ); | |
446 mem3.aPool[i-1].u.hdr.size4x &= ~1; | |
447 mem3.aPool[i+size-1].u.hdr.prevSize = size; | |
448 mem3.aPool[i+size-1].u.hdr.size4x &= ~2; | |
449 memsys3Link(i); | |
450 | |
451 /* Try to expand the master using the newly freed chunk */ | |
452 if( mem3.iMaster ){ | |
453 while( (mem3.aPool[mem3.iMaster-1].u.hdr.size4x&2)==0 ){ | |
454 size = mem3.aPool[mem3.iMaster-1].u.hdr.prevSize; | |
455 mem3.iMaster -= size; | |
456 mem3.szMaster += size; | |
457 memsys3Unlink(mem3.iMaster); | |
458 x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2; | |
459 mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x; | |
460 mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = mem3.szMaster; | |
461 } | |
462 x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2; | |
463 while( (mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x&1)==0 ){ | |
464 memsys3Unlink(mem3.iMaster+mem3.szMaster); | |
465 mem3.szMaster += mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x/4; | |
466 mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x; | |
467 mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = mem3.szMaster; | |
468 } | |
469 } | |
470 } | |
471 | |
472 /* | |
473 ** Return the size of an outstanding allocation, in bytes. The | |
474 ** size returned omits the 8-byte header overhead. This only | |
475 ** works for chunks that are currently checked out. | |
476 */ | |
477 static int memsys3Size(void *p){ | |
478 Mem3Block *pBlock; | |
479 if( p==0 ) return 0; | |
480 pBlock = (Mem3Block*)p; | |
481 assert( (pBlock[-1].u.hdr.size4x&1)!=0 ); | |
482 return (pBlock[-1].u.hdr.size4x&~3)*2 - 4; | |
483 } | |
484 | |
485 /* | |
486 ** Round up a request size to the next valid allocation size. | |
487 */ | |
488 static int memsys3Roundup(int n){ | |
489 if( n<=12 ){ | |
490 return 12; | |
491 }else{ | |
492 return ((n+11)&~7) - 4; | |
493 } | |
494 } | |
495 | |
496 /* | |
497 ** Allocate nBytes of memory. | |
498 */ | |
499 static void *memsys3Malloc(int nBytes){ | |
500 sqlite3_int64 *p; | |
501 assert( nBytes>0 ); /* malloc.c filters out 0 byte requests */ | |
502 memsys3Enter(); | |
503 p = memsys3MallocUnsafe(nBytes); | |
504 memsys3Leave(); | |
505 return (void*)p; | |
506 } | |
507 | |
508 /* | |
509 ** Free memory. | |
510 */ | |
511 static void memsys3Free(void *pPrior){ | |
512 assert( pPrior ); | |
513 memsys3Enter(); | |
514 memsys3FreeUnsafe(pPrior); | |
515 memsys3Leave(); | |
516 } | |
517 | |
518 /* | |
519 ** Change the size of an existing memory allocation | |
520 */ | |
521 static void *memsys3Realloc(void *pPrior, int nBytes){ | |
522 int nOld; | |
523 void *p; | |
524 if( pPrior==0 ){ | |
525 return sqlite3_malloc(nBytes); | |
526 } | |
527 if( nBytes<=0 ){ | |
528 sqlite3_free(pPrior); | |
529 return 0; | |
530 } | |
531 nOld = memsys3Size(pPrior); | |
532 if( nBytes<=nOld && nBytes>=nOld-128 ){ | |
533 return pPrior; | |
534 } | |
535 memsys3Enter(); | |
536 p = memsys3MallocUnsafe(nBytes); | |
537 if( p ){ | |
538 if( nOld<nBytes ){ | |
539 memcpy(p, pPrior, nOld); | |
540 }else{ | |
541 memcpy(p, pPrior, nBytes); | |
542 } | |
543 memsys3FreeUnsafe(pPrior); | |
544 } | |
545 memsys3Leave(); | |
546 return p; | |
547 } | |
548 | |
549 /* | |
550 ** Initialize this module. | |
551 */ | |
552 static int memsys3Init(void *NotUsed){ | |
553 UNUSED_PARAMETER(NotUsed); | |
554 if( !sqlite3GlobalConfig.pHeap ){ | |
555 return SQLITE_ERROR; | |
556 } | |
557 | |
558 /* Store a pointer to the memory block in global structure mem3. */ | |
559 assert( sizeof(Mem3Block)==8 ); | |
560 mem3.aPool = (Mem3Block *)sqlite3GlobalConfig.pHeap; | |
561 mem3.nPool = (sqlite3GlobalConfig.nHeap / sizeof(Mem3Block)) - 2; | |
562 | |
563 /* Initialize the master block. */ | |
564 mem3.szMaster = mem3.nPool; | |
565 mem3.mnMaster = mem3.szMaster; | |
566 mem3.iMaster = 1; | |
567 mem3.aPool[0].u.hdr.size4x = (mem3.szMaster<<2) + 2; | |
568 mem3.aPool[mem3.nPool].u.hdr.prevSize = mem3.nPool; | |
569 mem3.aPool[mem3.nPool].u.hdr.size4x = 1; | |
570 | |
571 return SQLITE_OK; | |
572 } | |
573 | |
574 /* | |
575 ** Deinitialize this module. | |
576 */ | |
577 static void memsys3Shutdown(void *NotUsed){ | |
578 UNUSED_PARAMETER(NotUsed); | |
579 mem3.mutex = 0; | |
580 return; | |
581 } | |
582 | |
583 | |
584 | |
585 /* | |
586 ** Open the file indicated and write a log of all unfreed memory | |
587 ** allocations into that log. | |
588 */ | |
589 void sqlite3Memsys3Dump(const char *zFilename){ | |
590 #ifdef SQLITE_DEBUG | |
591 FILE *out; | |
592 u32 i, j; | |
593 u32 size; | |
594 if( zFilename==0 || zFilename[0]==0 ){ | |
595 out = stdout; | |
596 }else{ | |
597 out = fopen(zFilename, "w"); | |
598 if( out==0 ){ | |
599 fprintf(stderr, "** Unable to output memory debug output log: %s **\n", | |
600 zFilename); | |
601 return; | |
602 } | |
603 } | |
604 memsys3Enter(); | |
605 fprintf(out, "CHUNKS:\n"); | |
606 for(i=1; i<=mem3.nPool; i+=size/4){ | |
607 size = mem3.aPool[i-1].u.hdr.size4x; | |
608 if( size/4<=1 ){ | |
609 fprintf(out, "%p size error\n", &mem3.aPool[i]); | |
610 assert( 0 ); | |
611 break; | |
612 } | |
613 if( (size&1)==0 && mem3.aPool[i+size/4-1].u.hdr.prevSize!=size/4 ){ | |
614 fprintf(out, "%p tail size does not match\n", &mem3.aPool[i]); | |
615 assert( 0 ); | |
616 break; | |
617 } | |
618 if( ((mem3.aPool[i+size/4-1].u.hdr.size4x&2)>>1)!=(size&1) ){ | |
619 fprintf(out, "%p tail checkout bit is incorrect\n", &mem3.aPool[i]); | |
620 assert( 0 ); | |
621 break; | |
622 } | |
623 if( size&1 ){ | |
624 fprintf(out, "%p %6d bytes checked out\n", &mem3.aPool[i], (size/4)*8-8); | |
625 }else{ | |
626 fprintf(out, "%p %6d bytes free%s\n", &mem3.aPool[i], (size/4)*8-8, | |
627 i==mem3.iMaster ? " **master**" : ""); | |
628 } | |
629 } | |
630 for(i=0; i<MX_SMALL-1; i++){ | |
631 if( mem3.aiSmall[i]==0 ) continue; | |
632 fprintf(out, "small(%2d):", i); | |
633 for(j = mem3.aiSmall[i]; j>0; j=mem3.aPool[j].u.list.next){ | |
634 fprintf(out, " %p(%d)", &mem3.aPool[j], | |
635 (mem3.aPool[j-1].u.hdr.size4x/4)*8-8); | |
636 } | |
637 fprintf(out, "\n"); | |
638 } | |
639 for(i=0; i<N_HASH; i++){ | |
640 if( mem3.aiHash[i]==0 ) continue; | |
641 fprintf(out, "hash(%2d):", i); | |
642 for(j = mem3.aiHash[i]; j>0; j=mem3.aPool[j].u.list.next){ | |
643 fprintf(out, " %p(%d)", &mem3.aPool[j], | |
644 (mem3.aPool[j-1].u.hdr.size4x/4)*8-8); | |
645 } | |
646 fprintf(out, "\n"); | |
647 } | |
648 fprintf(out, "master=%d\n", mem3.iMaster); | |
649 fprintf(out, "nowUsed=%d\n", mem3.nPool*8 - mem3.szMaster*8); | |
650 fprintf(out, "mxUsed=%d\n", mem3.nPool*8 - mem3.mnMaster*8); | |
651 sqlite3_mutex_leave(mem3.mutex); | |
652 if( out==stdout ){ | |
653 fflush(stdout); | |
654 }else{ | |
655 fclose(out); | |
656 } | |
657 #else | |
658 UNUSED_PARAMETER(zFilename); | |
659 #endif | |
660 } | |
661 | |
662 /* | |
663 ** This routine is the only routine in this file with external | |
664 ** linkage. | |
665 ** | |
666 ** Populate the low-level memory allocation function pointers in | |
667 ** sqlite3GlobalConfig.m with pointers to the routines in this file. The | |
668 ** arguments specify the block of memory to manage. | |
669 ** | |
670 ** This routine is only called by sqlite3_config(), and therefore | |
671 ** is not required to be threadsafe (it is not). | |
672 */ | |
673 const sqlite3_mem_methods *sqlite3MemGetMemsys3(void){ | |
674 static const sqlite3_mem_methods mempoolMethods = { | |
675 memsys3Malloc, | |
676 memsys3Free, | |
677 memsys3Realloc, | |
678 memsys3Size, | |
679 memsys3Roundup, | |
680 memsys3Init, | |
681 memsys3Shutdown, | |
682 0 | |
683 }; | |
684 return &mempoolMethods; | |
685 } | |
686 | |
687 #endif /* SQLITE_ENABLE_MEMSYS3 */ | |
OLD | NEW |