diff options
Diffstat (limited to 'libraries/sqlite/win32/mem2.c')
-rwxr-xr-x | libraries/sqlite/win32/mem2.c | 546 |
1 files changed, 546 insertions, 0 deletions
diff --git a/libraries/sqlite/win32/mem2.c b/libraries/sqlite/win32/mem2.c new file mode 100755 index 0000000..7c509ff --- /dev/null +++ b/libraries/sqlite/win32/mem2.c | |||
@@ -0,0 +1,546 @@ | |||
1 | /* | ||
2 | ** 2007 August 15 | ||
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 | ** $Id: mem2.c,v 1.14 2007/10/03 08:46:45 danielk1977 Exp $ | ||
16 | */ | ||
17 | |||
18 | /* | ||
19 | ** This version of the memory allocator is used only if the | ||
20 | ** SQLITE_MEMDEBUG macro is defined and SQLITE_OMIT_MEMORY_ALLOCATION | ||
21 | ** is not defined. | ||
22 | */ | ||
23 | #if defined(SQLITE_MEMDEBUG) && !defined(SQLITE_OMIT_MEMORY_ALLOCATION) | ||
24 | |||
25 | /* | ||
26 | ** We will eventually construct multiple memory allocation subsystems | ||
27 | ** suitable for use in various contexts: | ||
28 | ** | ||
29 | ** * Normal multi-threaded builds | ||
30 | ** * Normal single-threaded builds | ||
31 | ** * Debugging builds | ||
32 | ** | ||
33 | ** This version is suitable for use in debugging builds. | ||
34 | ** | ||
35 | ** Features: | ||
36 | ** | ||
37 | ** * Every allocate has guards at both ends. | ||
38 | ** * New allocations are initialized with randomness | ||
39 | ** * Allocations are overwritten with randomness when freed | ||
40 | ** * Optional logs of malloc activity generated | ||
41 | ** * Summary of outstanding allocations with backtraces to the | ||
42 | ** point of allocation. | ||
43 | ** * The ability to simulate memory allocation failure | ||
44 | */ | ||
45 | #include "sqliteInt.h" | ||
46 | #include <stdio.h> | ||
47 | |||
48 | /* | ||
49 | ** The backtrace functionality is only available with GLIBC | ||
50 | */ | ||
51 | #ifdef __GLIBC__ | ||
52 | extern int backtrace(void**,int); | ||
53 | extern void backtrace_symbols_fd(void*const*,int,int); | ||
54 | #else | ||
55 | # define backtrace(A,B) 0 | ||
56 | # define backtrace_symbols_fd(A,B,C) | ||
57 | #endif | ||
58 | |||
59 | /* | ||
60 | ** Each memory allocation looks like this: | ||
61 | ** | ||
62 | ** ------------------------------------------------------------------------ | ||
63 | ** | Title | backtrace pointers | MemBlockHdr | allocation | EndGuard | | ||
64 | ** ------------------------------------------------------------------------ | ||
65 | ** | ||
66 | ** The application code sees only a pointer to the allocation. We have | ||
67 | ** to back up from the allocation pointer to find the MemBlockHdr. The | ||
68 | ** MemBlockHdr tells us the size of the allocation and the number of | ||
69 | ** backtrace pointers. There is also a guard word at the end of the | ||
70 | ** MemBlockHdr. | ||
71 | */ | ||
72 | struct MemBlockHdr { | ||
73 | struct MemBlockHdr *pNext, *pPrev; /* Linked list of all unfreed memory */ | ||
74 | int iSize; /* Size of this allocation */ | ||
75 | char nBacktrace; /* Number of backtraces on this alloc */ | ||
76 | char nBacktraceSlots; /* Available backtrace slots */ | ||
77 | short nTitle; /* Bytes of title; includes '\0' */ | ||
78 | int iForeGuard; /* Guard word for sanity */ | ||
79 | }; | ||
80 | |||
81 | /* | ||
82 | ** Guard words | ||
83 | */ | ||
84 | #define FOREGUARD 0x80F5E153 | ||
85 | #define REARGUARD 0xE4676B53 | ||
86 | |||
87 | /* | ||
88 | ** All of the static variables used by this module are collected | ||
89 | ** into a single structure named "mem". This is to keep the | ||
90 | ** static variables organized and to reduce namespace pollution | ||
91 | ** when this module is combined with other in the amalgamation. | ||
92 | */ | ||
93 | static struct { | ||
94 | /* | ||
95 | ** The alarm callback and its arguments. The mem.mutex lock will | ||
96 | ** be held while the callback is running. Recursive calls into | ||
97 | ** the memory subsystem are allowed, but no new callbacks will be | ||
98 | ** issued. The alarmBusy variable is set to prevent recursive | ||
99 | ** callbacks. | ||
100 | */ | ||
101 | sqlite3_int64 alarmThreshold; | ||
102 | void (*alarmCallback)(void*, sqlite3_int64, int); | ||
103 | void *alarmArg; | ||
104 | int alarmBusy; | ||
105 | |||
106 | /* | ||
107 | ** Mutex to control access to the memory allocation subsystem. | ||
108 | */ | ||
109 | sqlite3_mutex *mutex; | ||
110 | |||
111 | /* | ||
112 | ** Current allocation and high-water mark. | ||
113 | */ | ||
114 | sqlite3_int64 nowUsed; | ||
115 | sqlite3_int64 mxUsed; | ||
116 | |||
117 | /* | ||
118 | ** Head and tail of a linked list of all outstanding allocations | ||
119 | */ | ||
120 | struct MemBlockHdr *pFirst; | ||
121 | struct MemBlockHdr *pLast; | ||
122 | |||
123 | /* | ||
124 | ** The number of levels of backtrace to save in new allocations. | ||
125 | */ | ||
126 | int nBacktrace; | ||
127 | |||
128 | /* | ||
129 | ** Title text to insert in front of each block | ||
130 | */ | ||
131 | int nTitle; /* Bytes of zTitle to save. Includes '\0' and padding */ | ||
132 | char zTitle[100]; /* The title text */ | ||
133 | |||
134 | /* | ||
135 | ** These values are used to simulate malloc failures. When | ||
136 | ** iFail is 1, simulate a malloc failures and reset the value | ||
137 | ** to iReset. | ||
138 | */ | ||
139 | int iFail; /* Decrement and fail malloc when this is 1 */ | ||
140 | int iReset; /* When malloc fails set iiFail to this value */ | ||
141 | int iFailCnt; /* Number of failures */ | ||
142 | int iBenignFailCnt; /* Number of benign failures */ | ||
143 | int iNextIsBenign; /* True if the next call to malloc may fail benignly */ | ||
144 | int iIsBenign; /* All malloc calls may fail benignly */ | ||
145 | |||
146 | /* | ||
147 | ** sqlite3MallocDisallow() increments the following counter. | ||
148 | ** sqlite3MallocAllow() decrements it. | ||
149 | */ | ||
150 | int disallow; /* Do not allow memory allocation */ | ||
151 | |||
152 | |||
153 | } mem; | ||
154 | |||
155 | |||
156 | /* | ||
157 | ** Enter the mutex mem.mutex. Allocate it if it is not already allocated. | ||
158 | */ | ||
159 | static void enterMem(void){ | ||
160 | if( mem.mutex==0 ){ | ||
161 | mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM); | ||
162 | } | ||
163 | sqlite3_mutex_enter(mem.mutex); | ||
164 | } | ||
165 | |||
166 | /* | ||
167 | ** Return the amount of memory currently checked out. | ||
168 | */ | ||
169 | sqlite3_int64 sqlite3_memory_used(void){ | ||
170 | sqlite3_int64 n; | ||
171 | enterMem(); | ||
172 | n = mem.nowUsed; | ||
173 | sqlite3_mutex_leave(mem.mutex); | ||
174 | return n; | ||
175 | } | ||
176 | |||
177 | /* | ||
178 | ** Return the maximum amount of memory that has ever been | ||
179 | ** checked out since either the beginning of this process | ||
180 | ** or since the most recent reset. | ||
181 | */ | ||
182 | sqlite3_int64 sqlite3_memory_highwater(int resetFlag){ | ||
183 | sqlite3_int64 n; | ||
184 | enterMem(); | ||
185 | n = mem.mxUsed; | ||
186 | if( resetFlag ){ | ||
187 | mem.mxUsed = mem.nowUsed; | ||
188 | } | ||
189 | sqlite3_mutex_leave(mem.mutex); | ||
190 | return n; | ||
191 | } | ||
192 | |||
193 | /* | ||
194 | ** Change the alarm callback | ||
195 | */ | ||
196 | int sqlite3_memory_alarm( | ||
197 | void(*xCallback)(void *pArg, sqlite3_int64 used, int N), | ||
198 | void *pArg, | ||
199 | sqlite3_int64 iThreshold | ||
200 | ){ | ||
201 | enterMem(); | ||
202 | mem.alarmCallback = xCallback; | ||
203 | mem.alarmArg = pArg; | ||
204 | mem.alarmThreshold = iThreshold; | ||
205 | sqlite3_mutex_leave(mem.mutex); | ||
206 | return SQLITE_OK; | ||
207 | } | ||
208 | |||
209 | /* | ||
210 | ** Trigger the alarm | ||
211 | */ | ||
212 | static void sqlite3MemsysAlarm(int nByte){ | ||
213 | void (*xCallback)(void*,sqlite3_int64,int); | ||
214 | sqlite3_int64 nowUsed; | ||
215 | void *pArg; | ||
216 | if( mem.alarmCallback==0 || mem.alarmBusy ) return; | ||
217 | mem.alarmBusy = 1; | ||
218 | xCallback = mem.alarmCallback; | ||
219 | nowUsed = mem.nowUsed; | ||
220 | pArg = mem.alarmArg; | ||
221 | sqlite3_mutex_leave(mem.mutex); | ||
222 | xCallback(pArg, nowUsed, nByte); | ||
223 | sqlite3_mutex_enter(mem.mutex); | ||
224 | mem.alarmBusy = 0; | ||
225 | } | ||
226 | |||
227 | /* | ||
228 | ** Given an allocation, find the MemBlockHdr for that allocation. | ||
229 | ** | ||
230 | ** This routine checks the guards at either end of the allocation and | ||
231 | ** if they are incorrect it asserts. | ||
232 | */ | ||
233 | static struct MemBlockHdr *sqlite3MemsysGetHeader(void *pAllocation){ | ||
234 | struct MemBlockHdr *p; | ||
235 | int *pInt; | ||
236 | |||
237 | p = (struct MemBlockHdr*)pAllocation; | ||
238 | p--; | ||
239 | assert( p->iForeGuard==FOREGUARD ); | ||
240 | assert( (p->iSize & 3)==0 ); | ||
241 | pInt = (int*)pAllocation; | ||
242 | assert( pInt[p->iSize/sizeof(int)]==REARGUARD ); | ||
243 | return p; | ||
244 | } | ||
245 | |||
246 | /* | ||
247 | ** This routine is called once the first time a simulated memory | ||
248 | ** failure occurs. The sole purpose of this routine is to provide | ||
249 | ** a convenient place to set a debugger breakpoint when debugging | ||
250 | ** errors related to malloc() failures. | ||
251 | */ | ||
252 | static void sqlite3MemsysFailed(void){ | ||
253 | mem.iFailCnt = 0; | ||
254 | mem.iBenignFailCnt = 0; | ||
255 | } | ||
256 | |||
257 | /* | ||
258 | ** Allocate nByte bytes of memory. | ||
259 | */ | ||
260 | void *sqlite3_malloc(int nByte){ | ||
261 | struct MemBlockHdr *pHdr; | ||
262 | void **pBt; | ||
263 | char *z; | ||
264 | int *pInt; | ||
265 | void *p = 0; | ||
266 | int totalSize; | ||
267 | |||
268 | if( nByte>0 ){ | ||
269 | enterMem(); | ||
270 | assert( mem.disallow==0 ); | ||
271 | if( mem.alarmCallback!=0 && mem.nowUsed+nByte>=mem.alarmThreshold ){ | ||
272 | sqlite3MemsysAlarm(nByte); | ||
273 | } | ||
274 | nByte = (nByte+3)&~3; | ||
275 | totalSize = nByte + sizeof(*pHdr) + sizeof(int) + | ||
276 | mem.nBacktrace*sizeof(void*) + mem.nTitle; | ||
277 | if( mem.iFail>0 ){ | ||
278 | if( mem.iFail==1 ){ | ||
279 | p = 0; | ||
280 | mem.iFail = mem.iReset; | ||
281 | if( mem.iFailCnt==0 ){ | ||
282 | sqlite3MemsysFailed(); /* A place to set a breakpoint */ | ||
283 | } | ||
284 | mem.iFailCnt++; | ||
285 | if( mem.iNextIsBenign || mem.iIsBenign ){ | ||
286 | mem.iBenignFailCnt++; | ||
287 | } | ||
288 | }else{ | ||
289 | p = malloc(totalSize); | ||
290 | mem.iFail--; | ||
291 | } | ||
292 | }else{ | ||
293 | p = malloc(totalSize); | ||
294 | if( p==0 ){ | ||
295 | sqlite3MemsysAlarm(nByte); | ||
296 | p = malloc(totalSize); | ||
297 | } | ||
298 | } | ||
299 | if( p ){ | ||
300 | z = p; | ||
301 | pBt = (void**)&z[mem.nTitle]; | ||
302 | pHdr = (struct MemBlockHdr*)&pBt[mem.nBacktrace]; | ||
303 | pHdr->pNext = 0; | ||
304 | pHdr->pPrev = mem.pLast; | ||
305 | if( mem.pLast ){ | ||
306 | mem.pLast->pNext = pHdr; | ||
307 | }else{ | ||
308 | mem.pFirst = pHdr; | ||
309 | } | ||
310 | mem.pLast = pHdr; | ||
311 | pHdr->iForeGuard = FOREGUARD; | ||
312 | pHdr->nBacktraceSlots = mem.nBacktrace; | ||
313 | pHdr->nTitle = mem.nTitle; | ||
314 | if( mem.nBacktrace ){ | ||
315 | void *aAddr[40]; | ||
316 | pHdr->nBacktrace = backtrace(aAddr, mem.nBacktrace+1)-1; | ||
317 | memcpy(pBt, &aAddr[1], pHdr->nBacktrace*sizeof(void*)); | ||
318 | }else{ | ||
319 | pHdr->nBacktrace = 0; | ||
320 | } | ||
321 | if( mem.nTitle ){ | ||
322 | memcpy(z, mem.zTitle, mem.nTitle); | ||
323 | } | ||
324 | pHdr->iSize = nByte; | ||
325 | pInt = (int*)&pHdr[1]; | ||
326 | pInt[nByte/sizeof(int)] = REARGUARD; | ||
327 | memset(pInt, 0x65, nByte); | ||
328 | mem.nowUsed += nByte; | ||
329 | if( mem.nowUsed>mem.mxUsed ){ | ||
330 | mem.mxUsed = mem.nowUsed; | ||
331 | } | ||
332 | p = (void*)pInt; | ||
333 | } | ||
334 | sqlite3_mutex_leave(mem.mutex); | ||
335 | } | ||
336 | mem.iNextIsBenign = 0; | ||
337 | return p; | ||
338 | } | ||
339 | |||
340 | /* | ||
341 | ** Free memory. | ||
342 | */ | ||
343 | void sqlite3_free(void *pPrior){ | ||
344 | struct MemBlockHdr *pHdr; | ||
345 | void **pBt; | ||
346 | char *z; | ||
347 | if( pPrior==0 ){ | ||
348 | return; | ||
349 | } | ||
350 | assert( mem.mutex!=0 ); | ||
351 | pHdr = sqlite3MemsysGetHeader(pPrior); | ||
352 | pBt = (void**)pHdr; | ||
353 | pBt -= pHdr->nBacktraceSlots; | ||
354 | sqlite3_mutex_enter(mem.mutex); | ||
355 | mem.nowUsed -= pHdr->iSize; | ||
356 | if( pHdr->pPrev ){ | ||
357 | assert( pHdr->pPrev->pNext==pHdr ); | ||
358 | pHdr->pPrev->pNext = pHdr->pNext; | ||
359 | }else{ | ||
360 | assert( mem.pFirst==pHdr ); | ||
361 | mem.pFirst = pHdr->pNext; | ||
362 | } | ||
363 | if( pHdr->pNext ){ | ||
364 | assert( pHdr->pNext->pPrev==pHdr ); | ||
365 | pHdr->pNext->pPrev = pHdr->pPrev; | ||
366 | }else{ | ||
367 | assert( mem.pLast==pHdr ); | ||
368 | mem.pLast = pHdr->pPrev; | ||
369 | } | ||
370 | z = (char*)pBt; | ||
371 | z -= pHdr->nTitle; | ||
372 | memset(z, 0x2b, sizeof(void*)*pHdr->nBacktraceSlots + sizeof(*pHdr) + | ||
373 | pHdr->iSize + sizeof(int) + pHdr->nTitle); | ||
374 | free(z); | ||
375 | sqlite3_mutex_leave(mem.mutex); | ||
376 | } | ||
377 | |||
378 | /* | ||
379 | ** Change the size of an existing memory allocation. | ||
380 | ** | ||
381 | ** For this debugging implementation, we *always* make a copy of the | ||
382 | ** allocation into a new place in memory. In this way, if the | ||
383 | ** higher level code is using pointer to the old allocation, it is | ||
384 | ** much more likely to break and we are much more liking to find | ||
385 | ** the error. | ||
386 | */ | ||
387 | void *sqlite3_realloc(void *pPrior, int nByte){ | ||
388 | struct MemBlockHdr *pOldHdr; | ||
389 | void *pNew; | ||
390 | if( pPrior==0 ){ | ||
391 | return sqlite3_malloc(nByte); | ||
392 | } | ||
393 | if( nByte<=0 ){ | ||
394 | sqlite3_free(pPrior); | ||
395 | return 0; | ||
396 | } | ||
397 | assert( mem.disallow==0 ); | ||
398 | pOldHdr = sqlite3MemsysGetHeader(pPrior); | ||
399 | pNew = sqlite3_malloc(nByte); | ||
400 | if( pNew ){ | ||
401 | memcpy(pNew, pPrior, nByte<pOldHdr->iSize ? nByte : pOldHdr->iSize); | ||
402 | if( nByte>pOldHdr->iSize ){ | ||
403 | memset(&((char*)pNew)[pOldHdr->iSize], 0x2b, nByte - pOldHdr->iSize); | ||
404 | } | ||
405 | sqlite3_free(pPrior); | ||
406 | } | ||
407 | return pNew; | ||
408 | } | ||
409 | |||
410 | /* | ||
411 | ** Set the number of backtrace levels kept for each allocation. | ||
412 | ** A value of zero turns of backtracing. The number is always rounded | ||
413 | ** up to a multiple of 2. | ||
414 | */ | ||
415 | void sqlite3_memdebug_backtrace(int depth){ | ||
416 | if( depth<0 ){ depth = 0; } | ||
417 | if( depth>20 ){ depth = 20; } | ||
418 | depth = (depth+1)&0xfe; | ||
419 | mem.nBacktrace = depth; | ||
420 | } | ||
421 | |||
422 | /* | ||
423 | ** Set the title string for subsequent allocations. | ||
424 | */ | ||
425 | void sqlite3_memdebug_settitle(const char *zTitle){ | ||
426 | int n = strlen(zTitle) + 1; | ||
427 | enterMem(); | ||
428 | if( n>=sizeof(mem.zTitle) ) n = sizeof(mem.zTitle)-1; | ||
429 | memcpy(mem.zTitle, zTitle, n); | ||
430 | mem.zTitle[n] = 0; | ||
431 | mem.nTitle = (n+3)&~3; | ||
432 | sqlite3_mutex_leave(mem.mutex); | ||
433 | } | ||
434 | |||
435 | /* | ||
436 | ** Open the file indicated and write a log of all unfreed memory | ||
437 | ** allocations into that log. | ||
438 | */ | ||
439 | void sqlite3_memdebug_dump(const char *zFilename){ | ||
440 | FILE *out; | ||
441 | struct MemBlockHdr *pHdr; | ||
442 | void **pBt; | ||
443 | out = fopen(zFilename, "w"); | ||
444 | if( out==0 ){ | ||
445 | fprintf(stderr, "** Unable to output memory debug output log: %s **\n", | ||
446 | zFilename); | ||
447 | return; | ||
448 | } | ||
449 | for(pHdr=mem.pFirst; pHdr; pHdr=pHdr->pNext){ | ||
450 | char *z = (char*)pHdr; | ||
451 | z -= pHdr->nBacktraceSlots*sizeof(void*) + pHdr->nTitle; | ||
452 | fprintf(out, "**** %d bytes at %p from %s ****\n", | ||
453 | pHdr->iSize, &pHdr[1], pHdr->nTitle ? z : "???"); | ||
454 | if( pHdr->nBacktrace ){ | ||
455 | fflush(out); | ||
456 | pBt = (void**)pHdr; | ||
457 | pBt -= pHdr->nBacktraceSlots; | ||
458 | backtrace_symbols_fd(pBt, pHdr->nBacktrace, fileno(out)); | ||
459 | fprintf(out, "\n"); | ||
460 | } | ||
461 | } | ||
462 | fclose(out); | ||
463 | } | ||
464 | |||
465 | /* | ||
466 | ** This routine is used to simulate malloc failures. | ||
467 | ** | ||
468 | ** After calling this routine, there will be iFail successful | ||
469 | ** memory allocations and then a failure. If iRepeat is 1 | ||
470 | ** all subsequent memory allocations will fail. If iRepeat is | ||
471 | ** 0, only a single allocation will fail. If iRepeat is negative | ||
472 | ** then the previous setting for iRepeat is unchanged. | ||
473 | ** | ||
474 | ** Each call to this routine overrides the previous. To disable | ||
475 | ** the simulated allocation failure mechanism, set iFail to -1. | ||
476 | ** | ||
477 | ** This routine returns the number of simulated failures that have | ||
478 | ** occurred since the previous call. | ||
479 | */ | ||
480 | int sqlite3_memdebug_fail(int iFail, int iRepeat, int *piBenign){ | ||
481 | int n = mem.iFailCnt; | ||
482 | if( piBenign ){ | ||
483 | *piBenign = mem.iBenignFailCnt; | ||
484 | } | ||
485 | mem.iFail = iFail+1; | ||
486 | if( iRepeat>=0 ){ | ||
487 | mem.iReset = iRepeat; | ||
488 | } | ||
489 | mem.iFailCnt = 0; | ||
490 | mem.iBenignFailCnt = 0; | ||
491 | return n; | ||
492 | } | ||
493 | |||
494 | int sqlite3_memdebug_pending(){ | ||
495 | return (mem.iFail-1); | ||
496 | } | ||
497 | |||
498 | /* | ||
499 | ** The following three functions are used to indicate to the test | ||
500 | ** infrastructure which malloc() calls may fail benignly without | ||
501 | ** affecting functionality. This can happen when resizing hash tables | ||
502 | ** (failing to resize a hash-table is a performance hit, but not an | ||
503 | ** error) or sometimes during a rollback operation. | ||
504 | ** | ||
505 | ** If the argument is true, sqlite3MallocBenignFailure() indicates that the | ||
506 | ** next call to allocate memory may fail benignly. | ||
507 | ** | ||
508 | ** If sqlite3MallocEnterBenignBlock() is called with a non-zero argument, | ||
509 | ** then all memory allocations requested before the next call to | ||
510 | ** sqlite3MallocLeaveBenignBlock() may fail benignly. | ||
511 | */ | ||
512 | void sqlite3MallocBenignFailure(int isBenign){ | ||
513 | if( isBenign ){ | ||
514 | mem.iNextIsBenign = 1; | ||
515 | } | ||
516 | } | ||
517 | void sqlite3MallocEnterBenignBlock(int isBenign){ | ||
518 | if( isBenign ){ | ||
519 | mem.iIsBenign = 1; | ||
520 | } | ||
521 | } | ||
522 | void sqlite3MallocLeaveBenignBlock(){ | ||
523 | mem.iIsBenign = 0; | ||
524 | } | ||
525 | |||
526 | /* | ||
527 | ** The following two routines are used to assert that no memory | ||
528 | ** allocations occur between one call and the next. The use of | ||
529 | ** these routines does not change the computed results in any way. | ||
530 | ** These routines are like asserts. | ||
531 | */ | ||
532 | void sqlite3MallocDisallow(void){ | ||
533 | assert( mem.mutex!=0 ); | ||
534 | sqlite3_mutex_enter(mem.mutex); | ||
535 | mem.disallow++; | ||
536 | sqlite3_mutex_leave(mem.mutex); | ||
537 | } | ||
538 | void sqlite3MallocAllow(void){ | ||
539 | assert( mem.mutex ); | ||
540 | sqlite3_mutex_enter(mem.mutex); | ||
541 | assert( mem.disallow>0 ); | ||
542 | mem.disallow--; | ||
543 | sqlite3_mutex_leave(mem.mutex); | ||
544 | } | ||
545 | |||
546 | #endif /* SQLITE_MEMDEBUG && !SQLITE_OMIT_MEMORY_ALLOCATION */ | ||