xref: /sqlite-3.40.0/src/mem1.c (revision 85b623f2)
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.c,v 1.14 2007/11/29 18:36:49 drh Exp $
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 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 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 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 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 = malloc(nBytes+8);
156     if( p==0 ){
157       sqlite3MemsysAlarm(nBytes);
158       p = 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 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 = 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 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 = 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 = realloc(p, nBytes+8);
214   if( p==0 ){
215     sqlite3MemsysAlarm(nBytes);
216     p = pPrior;
217     p--;
218     p = 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 */
233