/ Check-in [31eb4abc]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add asserts on sqlite3_mutex_held() to the zero-malloc memory allocator, in order to prove that the mutex is held when it is needed. (CVS 4534)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 31eb4abc89e9c0fd90fde5486d4008f9d09fdf4e
User & Date: drh 2007-11-07 15:13:25
Context
2007-11-11
18:36
Fix the code generation for UPDATE and DELETE so that BEFORE triggers that use RAISE(IGNORE) do not leave extra values on the stack. Ticket #2767 (CVS 4535) check-in: 3391f413 user: drh tags: trunk
2007-11-07
15:13
Add asserts on sqlite3_mutex_held() to the zero-malloc memory allocator, in order to prove that the mutex is held when it is needed. (CVS 4534) check-in: 31eb4abc user: drh tags: trunk
01:23
Changes the asynchronous I/O test module so that it can be appended to the end of the amalgamation. (CVS 4533) check-in: c1fe27de user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Show Whitespace Changes Patch

Changes to src/mem3.c.

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
...
129
130
131
132
133
134
135

136
137
138
139
140
141
142
...
147
148
149
150
151
152
153

154
155
156
157
158
159
160
...
163
164
165
166
167
168
169

170
171
172
173
174
175
176
...
177
178
179
180
181
182
183

184
185
186
187
188
189
190
...
255
256
257
258
259
260
261

262
263
264
265
266
267
268
...
279
280
281
282
283
284
285

286
287
288
289
290
291
292
293
294
295
296
297
298

299
300
301
302
303
304
305
...
336
337
338
339
340
341
342

343
344
345
346
347
348
349
...
370
371
372
373
374
375
376

377
378
379
380
381
382
383
...
447
448
449
450
451
452
453

454
455
456
457
458
459
460
** use of malloc().  All dynamically allocatable memory is
** contained in a static array, mem.aPool[].  The size of this
** fixed memory pool is SQLITE_MEMORY_SIZE bytes.
**
** This version of the memory allocation subsystem is used if
** and only if SQLITE_MEMORY_SIZE is defined.
**
** $Id: mem3.c,v 1.5 2007/10/20 16:36:31 drh Exp $
*/

/*
** This version of the memory allocator is used only when 
** SQLITE_MEMORY_SIZE is defined.
*/
#if defined(SQLITE_MEMORY_SIZE)
................................................................................
/*
** Unlink the chunk at mem.aPool[i] from list it is currently
** on.  *pRoot is the list that i is a member of.
*/
static void memsys3UnlinkFromList(int i, int *pRoot){
  int next = mem.aPool[i].u.list.next;
  int prev = mem.aPool[i].u.list.prev;

  if( prev==0 ){
    *pRoot = next;
  }else{
    mem.aPool[prev].u.list.next = next;
  }
  if( next ){
    mem.aPool[next].u.list.prev = prev;
................................................................................

/*
** Unlink the chunk at index i from 
** whatever list is currently a member of.
*/
static void memsys3Unlink(int i){
  int size, hash;

  size = mem.aPool[i-1].u.hdr.size;
  assert( size==mem.aPool[i+size-1].u.hdr.prevSize );
  assert( size>=2 );
  if( size <= MX_SMALL ){
    memsys3UnlinkFromList(i, &mem.aiSmall[size-2]);
  }else{
    hash = size % N_HASH;
................................................................................
}

/*
** Link the chunk at mem.aPool[i] so that is on the list rooted
** at *pRoot.
*/
static void memsys3LinkIntoList(int i, int *pRoot){

  mem.aPool[i].u.list.next = *pRoot;
  mem.aPool[i].u.list.prev = 0;
  if( *pRoot ){
    mem.aPool[*pRoot].u.list.prev = i;
  }
  *pRoot = i;
}
................................................................................

/*
** Link the chunk at index i into either the appropriate
** small chunk list, or into the large chunk hash table.
*/
static void memsys3Link(int i){
  int size, hash;

  size = mem.aPool[i-1].u.hdr.size;
  assert( size==mem.aPool[i+size-1].u.hdr.prevSize );
  assert( size>=2 );
  if( size <= MX_SMALL ){
    memsys3LinkIntoList(i, &mem.aiSmall[size-2]);
  }else{
    hash = size % N_HASH;
................................................................................

/*
** Called when we are unable to satisfy an allocation of nBytes.
*/
static void memsys3OutOfMemory(int nByte){
  if( !mem.alarmBusy ){
    mem.alarmBusy = 1;

    sqlite3_mutex_leave(mem.mutex);
    sqlite3_release_memory(nByte);
    sqlite3_mutex_enter(mem.mutex);
    mem.alarmBusy = 0;
  }
}

................................................................................

/*
** Chunk i is a free chunk that has been unlinked.  Adjust its 
** size parameters for check-out and return a pointer to the 
** user portion of the chunk.
*/
static void *memsys3Checkout(int i, int nBlock){

  assert( mem.aPool[i-1].u.hdr.size==nBlock );
  assert( mem.aPool[i+nBlock-1].u.hdr.prevSize==nBlock );
  mem.aPool[i-1].u.hdr.size = -nBlock;
  mem.aPool[i+nBlock-1].u.hdr.prevSize = -nBlock;
  return &mem.aPool[i];
}

/*
** Carve a piece off of the end of the mem.iMaster free chunk.
** Return a pointer to the new allocation.  Or, if the master chunk
** is not large enough, return 0.
*/
static void *memsys3FromMaster(int nBlock){

  assert( mem.szMaster>=nBlock );
  if( nBlock>=mem.szMaster-1 ){
    /* Use the entire master */
    void *p = memsys3Checkout(mem.iMaster, mem.szMaster);
    mem.iMaster = 0;
    mem.szMaster = 0;
    mem.mnMaster = 0;
................................................................................
** affairs, of course.  The calling routine must link the master
** chunk before invoking this routine, then must unlink the (possibly
** changed) master chunk once this routine has finished.
*/
static void memsys3Merge(int *pRoot){
  int iNext, prev, size, i;


  for(i=*pRoot; i>0; i=iNext){
    iNext = mem.aPool[i].u.list.next;
    size = mem.aPool[i-1].u.hdr.size;
    assert( size>0 );
    if( mem.aPool[i-1].u.hdr.prevSize>0 ){
      memsys3UnlinkFromList(i, pRoot);
      prev = i - mem.aPool[i-1].u.hdr.prevSize;
................................................................................
** Return NULL if unable.
*/
static void *memsys3Malloc(int nByte){
  int i;
  int nBlock;
  int toFree;


  assert( sizeof(Mem3Block)==8 );
  if( nByte<=0 ){
    nBlock = 2;
  }else{
    nBlock = (nByte + 15)/8;
  }
  assert( nBlock >= 2 );
................................................................................
/*
** Free an outstanding memory allocation.
*/
void memsys3Free(void *pOld){
  Mem3Block *p = (Mem3Block*)pOld;
  int i;
  int size;

  assert( p>mem.aPool && p<&mem.aPool[SQLITE_MEMORY_SIZE/8] );
  i = p - mem.aPool;
  size = -mem.aPool[i-1].u.hdr.size;
  assert( size>=2 );
  assert( mem.aPool[i+size-1].u.hdr.prevSize==-size );
  mem.aPool[i-1].u.hdr.size = size;
  mem.aPool[i+size-1].u.hdr.prevSize = size;







|







 







>







 







>







 







>







 







>







 







>







 







>













>







 







>







 







>







 







>







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
...
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
...
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
...
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
...
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
...
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
...
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
...
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
...
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
** use of malloc().  All dynamically allocatable memory is
** contained in a static array, mem.aPool[].  The size of this
** fixed memory pool is SQLITE_MEMORY_SIZE bytes.
**
** This version of the memory allocation subsystem is used if
** and only if SQLITE_MEMORY_SIZE is defined.
**
** $Id: mem3.c,v 1.6 2007/11/07 15:13:25 drh Exp $
*/

/*
** This version of the memory allocator is used only when 
** SQLITE_MEMORY_SIZE is defined.
*/
#if defined(SQLITE_MEMORY_SIZE)
................................................................................
/*
** Unlink the chunk at mem.aPool[i] from list it is currently
** on.  *pRoot is the list that i is a member of.
*/
static void memsys3UnlinkFromList(int i, int *pRoot){
  int next = mem.aPool[i].u.list.next;
  int prev = mem.aPool[i].u.list.prev;
  assert( sqlite3_mutex_held(mem.mutex) );
  if( prev==0 ){
    *pRoot = next;
  }else{
    mem.aPool[prev].u.list.next = next;
  }
  if( next ){
    mem.aPool[next].u.list.prev = prev;
................................................................................

/*
** Unlink the chunk at index i from 
** whatever list is currently a member of.
*/
static void memsys3Unlink(int i){
  int size, hash;
  assert( sqlite3_mutex_held(mem.mutex) );
  size = mem.aPool[i-1].u.hdr.size;
  assert( size==mem.aPool[i+size-1].u.hdr.prevSize );
  assert( size>=2 );
  if( size <= MX_SMALL ){
    memsys3UnlinkFromList(i, &mem.aiSmall[size-2]);
  }else{
    hash = size % N_HASH;
................................................................................
}

/*
** Link the chunk at mem.aPool[i] so that is on the list rooted
** at *pRoot.
*/
static void memsys3LinkIntoList(int i, int *pRoot){
  assert( sqlite3_mutex_held(mem.mutex) );
  mem.aPool[i].u.list.next = *pRoot;
  mem.aPool[i].u.list.prev = 0;
  if( *pRoot ){
    mem.aPool[*pRoot].u.list.prev = i;
  }
  *pRoot = i;
}
................................................................................

/*
** Link the chunk at index i into either the appropriate
** small chunk list, or into the large chunk hash table.
*/
static void memsys3Link(int i){
  int size, hash;
  assert( sqlite3_mutex_held(mem.mutex) );
  size = mem.aPool[i-1].u.hdr.size;
  assert( size==mem.aPool[i+size-1].u.hdr.prevSize );
  assert( size>=2 );
  if( size <= MX_SMALL ){
    memsys3LinkIntoList(i, &mem.aiSmall[size-2]);
  }else{
    hash = size % N_HASH;
................................................................................

/*
** Called when we are unable to satisfy an allocation of nBytes.
*/
static void memsys3OutOfMemory(int nByte){
  if( !mem.alarmBusy ){
    mem.alarmBusy = 1;
    assert( sqlite3_mutex_held(mem.mutex) );
    sqlite3_mutex_leave(mem.mutex);
    sqlite3_release_memory(nByte);
    sqlite3_mutex_enter(mem.mutex);
    mem.alarmBusy = 0;
  }
}

................................................................................

/*
** Chunk i is a free chunk that has been unlinked.  Adjust its 
** size parameters for check-out and return a pointer to the 
** user portion of the chunk.
*/
static void *memsys3Checkout(int i, int nBlock){
  assert( sqlite3_mutex_held(mem.mutex) );
  assert( mem.aPool[i-1].u.hdr.size==nBlock );
  assert( mem.aPool[i+nBlock-1].u.hdr.prevSize==nBlock );
  mem.aPool[i-1].u.hdr.size = -nBlock;
  mem.aPool[i+nBlock-1].u.hdr.prevSize = -nBlock;
  return &mem.aPool[i];
}

/*
** Carve a piece off of the end of the mem.iMaster free chunk.
** Return a pointer to the new allocation.  Or, if the master chunk
** is not large enough, return 0.
*/
static void *memsys3FromMaster(int nBlock){
  assert( sqlite3_mutex_held(mem.mutex) );
  assert( mem.szMaster>=nBlock );
  if( nBlock>=mem.szMaster-1 ){
    /* Use the entire master */
    void *p = memsys3Checkout(mem.iMaster, mem.szMaster);
    mem.iMaster = 0;
    mem.szMaster = 0;
    mem.mnMaster = 0;
................................................................................
** affairs, of course.  The calling routine must link the master
** chunk before invoking this routine, then must unlink the (possibly
** changed) master chunk once this routine has finished.
*/
static void memsys3Merge(int *pRoot){
  int iNext, prev, size, i;

  assert( sqlite3_mutex_held(mem.mutex) );
  for(i=*pRoot; i>0; i=iNext){
    iNext = mem.aPool[i].u.list.next;
    size = mem.aPool[i-1].u.hdr.size;
    assert( size>0 );
    if( mem.aPool[i-1].u.hdr.prevSize>0 ){
      memsys3UnlinkFromList(i, pRoot);
      prev = i - mem.aPool[i-1].u.hdr.prevSize;
................................................................................
** Return NULL if unable.
*/
static void *memsys3Malloc(int nByte){
  int i;
  int nBlock;
  int toFree;

  assert( sqlite3_mutex_held(mem.mutex) );
  assert( sizeof(Mem3Block)==8 );
  if( nByte<=0 ){
    nBlock = 2;
  }else{
    nBlock = (nByte + 15)/8;
  }
  assert( nBlock >= 2 );
................................................................................
/*
** Free an outstanding memory allocation.
*/
void memsys3Free(void *pOld){
  Mem3Block *p = (Mem3Block*)pOld;
  int i;
  int size;
  assert( sqlite3_mutex_held(mem.mutex) );
  assert( p>mem.aPool && p<&mem.aPool[SQLITE_MEMORY_SIZE/8] );
  i = p - mem.aPool;
  size = -mem.aPool[i-1].u.hdr.size;
  assert( size>=2 );
  assert( mem.aPool[i+size-1].u.hdr.prevSize==-size );
  mem.aPool[i-1].u.hdr.size = size;
  mem.aPool[i+size-1].u.hdr.prevSize = size;