|
1 /* |
|
2 ** 2007 August 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 ** $Id: mem1.cpp 1282 2008-11-13 09:31:33Z LarsPson $ |
|
16 */ |
|
17 |
|
18 /* |
|
19 ** This version of the memory allocator is the default. It is |
|
20 ** used when no other memory allocator is specified using compile-time |
|
21 ** macros. |
|
22 */ |
|
23 #if !defined(SQLITE_MEMDEBUG) && !defined(SQLITE_MEMORY_SIZE) \ |
|
24 && !defined(SQLITE_MMAP_HEAP_SIZE) |
|
25 |
|
26 /* |
|
27 ** We will eventually construct multiple memory allocation subsystems |
|
28 ** suitable for use in various contexts: |
|
29 ** |
|
30 ** * Normal multi-threaded builds |
|
31 ** * Normal single-threaded builds |
|
32 ** * Debugging builds |
|
33 ** |
|
34 ** This initial version is suitable for use in normal multi-threaded |
|
35 ** builds. We envision that alternative versions will be stored in |
|
36 ** separate source files. #ifdefs will be used to select the code from |
|
37 ** one of the various memN.c source files for use in any given build. |
|
38 */ |
|
39 #include "sqliteInt.h" |
|
40 |
|
41 /* |
|
42 ** All of the static variables used by this module are collected |
|
43 ** into a single structure named "mem". This is to keep the |
|
44 ** static variables organized and to reduce namespace pollution |
|
45 ** when this module is combined with other in the amalgamation. |
|
46 */ |
|
47 static struct { |
|
48 /* |
|
49 ** The alarm callback and its arguments. The mem.mutex lock will |
|
50 ** be held while the callback is running. Recursive calls into |
|
51 ** the memory subsystem are allowed, but no new callbacks will be |
|
52 ** issued. The alarmBusy variable is set to prevent recursive |
|
53 ** callbacks. |
|
54 */ |
|
55 sqlite3_int64 alarmThreshold; |
|
56 void (*alarmCallback)(void*, sqlite3_int64,int); |
|
57 void *alarmArg; |
|
58 int alarmBusy; |
|
59 |
|
60 /* |
|
61 ** Mutex to control access to the memory allocation subsystem. |
|
62 */ |
|
63 sqlite3_mutex *mutex; |
|
64 |
|
65 /* |
|
66 ** Current allocation and high-water mark. |
|
67 */ |
|
68 sqlite3_int64 nowUsed; |
|
69 sqlite3_int64 mxUsed; |
|
70 |
|
71 |
|
72 } mem; |
|
73 |
|
74 /* |
|
75 ** Enter the mutex mem.mutex. Allocate it if it is not already allocated. |
|
76 */ |
|
77 static void enterMem(void){ |
|
78 if( mem.mutex==0 ){ |
|
79 mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM); |
|
80 } |
|
81 sqlite3_mutex_enter(mem.mutex); |
|
82 } |
|
83 |
|
84 /* |
|
85 ** Return the amount of memory currently checked out. |
|
86 */ |
|
87 EXPORT_C sqlite3_int64 sqlite3_memory_used(void){ |
|
88 sqlite3_int64 n; |
|
89 enterMem(); |
|
90 n = mem.nowUsed; |
|
91 sqlite3_mutex_leave(mem.mutex); |
|
92 return n; |
|
93 } |
|
94 |
|
95 /* |
|
96 ** Return the maximum amount of memory that has ever been |
|
97 ** checked out since either the beginning of this process |
|
98 ** or since the most recent reset. |
|
99 */ |
|
100 EXPORT_C sqlite3_int64 sqlite3_memory_highwater(int resetFlag){ |
|
101 sqlite3_int64 n; |
|
102 enterMem(); |
|
103 n = mem.mxUsed; |
|
104 if( resetFlag ){ |
|
105 mem.mxUsed = mem.nowUsed; |
|
106 } |
|
107 sqlite3_mutex_leave(mem.mutex); |
|
108 return n; |
|
109 } |
|
110 |
|
111 /* |
|
112 ** Change the alarm callback |
|
113 */ |
|
114 EXPORT_C int sqlite3_memory_alarm( |
|
115 void(*xCallback)(void *pArg, sqlite3_int64 used,int N), |
|
116 void *pArg, |
|
117 sqlite3_int64 iThreshold |
|
118 ){ |
|
119 enterMem(); |
|
120 mem.alarmCallback = xCallback; |
|
121 mem.alarmArg = pArg; |
|
122 mem.alarmThreshold = iThreshold; |
|
123 sqlite3_mutex_leave(mem.mutex); |
|
124 return SQLITE_OK; |
|
125 } |
|
126 |
|
127 /* |
|
128 ** Trigger the alarm |
|
129 */ |
|
130 static void sqlite3MemsysAlarm(int nByte){ |
|
131 void (*xCallback)(void*,sqlite3_int64,int); |
|
132 sqlite3_int64 nowUsed; |
|
133 void *pArg; |
|
134 if( mem.alarmCallback==0 || mem.alarmBusy ) return; |
|
135 mem.alarmBusy = 1; |
|
136 xCallback = mem.alarmCallback; |
|
137 nowUsed = mem.nowUsed; |
|
138 pArg = mem.alarmArg; |
|
139 sqlite3_mutex_leave(mem.mutex); |
|
140 xCallback(pArg, nowUsed, nByte); |
|
141 sqlite3_mutex_enter(mem.mutex); |
|
142 mem.alarmBusy = 0; |
|
143 } |
|
144 |
|
145 /* |
|
146 ** Allocate nBytes of memory |
|
147 */ |
|
148 EXPORT_C void *sqlite3_malloc(int nBytes){ |
|
149 sqlite3_int64 *p = 0; |
|
150 if( nBytes>0 ){ |
|
151 enterMem(); |
|
152 if( mem.alarmCallback!=0 && mem.nowUsed+nBytes>=mem.alarmThreshold ){ |
|
153 sqlite3MemsysAlarm(nBytes); |
|
154 } |
|
155 p = (sqlite3_int64*)malloc(nBytes+8); |
|
156 if( p==0 ){ |
|
157 sqlite3MemsysAlarm(nBytes); |
|
158 p = (sqlite3_int64*)malloc(nBytes+8); |
|
159 } |
|
160 if( p ){ |
|
161 p[0] = nBytes; |
|
162 p++; |
|
163 mem.nowUsed += nBytes; |
|
164 if( mem.nowUsed>mem.mxUsed ){ |
|
165 mem.mxUsed = mem.nowUsed; |
|
166 } |
|
167 } |
|
168 sqlite3_mutex_leave(mem.mutex); |
|
169 } |
|
170 return (void*)p; |
|
171 } |
|
172 |
|
173 /* |
|
174 ** Free memory. |
|
175 */ |
|
176 EXPORT_C void sqlite3_free(void *pPrior){ |
|
177 sqlite3_int64 *p; |
|
178 int nByte; |
|
179 if( pPrior==0 ){ |
|
180 return; |
|
181 } |
|
182 assert( mem.mutex!=0 ); |
|
183 p = (sqlite3_int64*)pPrior; |
|
184 p--; |
|
185 nByte = (int)*p; |
|
186 sqlite3_mutex_enter(mem.mutex); |
|
187 mem.nowUsed -= nByte; |
|
188 free(p); |
|
189 sqlite3_mutex_leave(mem.mutex); |
|
190 } |
|
191 |
|
192 /* |
|
193 ** Change the size of an existing memory allocation |
|
194 */ |
|
195 EXPORT_C void *sqlite3_realloc(void *pPrior, int nBytes){ |
|
196 int nOld; |
|
197 sqlite3_int64 *p; |
|
198 if( pPrior==0 ){ |
|
199 return sqlite3_malloc(nBytes); |
|
200 } |
|
201 if( nBytes<=0 ){ |
|
202 sqlite3_free(pPrior); |
|
203 return 0; |
|
204 } |
|
205 p = (sqlite3_int64*)pPrior; |
|
206 p--; |
|
207 nOld = (int)p[0]; |
|
208 assert( mem.mutex!=0 ); |
|
209 sqlite3_mutex_enter(mem.mutex); |
|
210 if( mem.nowUsed+nBytes-nOld>=mem.alarmThreshold ){ |
|
211 sqlite3MemsysAlarm(nBytes-nOld); |
|
212 } |
|
213 p = (sqlite3_int64*)realloc(p, nBytes+8); |
|
214 if( p==0 ){ |
|
215 sqlite3MemsysAlarm(nBytes); |
|
216 p = (sqlite3_int64*)pPrior; |
|
217 p--; |
|
218 p = (sqlite3_int64*)realloc(p, nBytes+8); |
|
219 } |
|
220 if( p ){ |
|
221 p[0] = nBytes; |
|
222 p++; |
|
223 mem.nowUsed += nBytes-nOld; |
|
224 if( mem.nowUsed>mem.mxUsed ){ |
|
225 mem.mxUsed = mem.nowUsed; |
|
226 } |
|
227 } |
|
228 sqlite3_mutex_leave(mem.mutex); |
|
229 return (void*)p; |
|
230 } |
|
231 |
|
232 #endif /* !SQLITE_MEMDEBUG && !SQLITE_OMIT_MEMORY_ALLOCATION */ |