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