/ Check-in [30ff6bb0]
Login

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

Overview
Comment:Fix the allocator in mem5.c so that it can be enabled at run time using the sqlite3_config() function. (CVS 5304)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 30ff6bb0b2d1068d28e86ac90bb9f454e4537a2d
User & Date: danielk1977 2008-06-25 14:26:08
Context
2008-06-25
14:31
Test enhancements, especially to the new compound-SELECT merge logic. (CVS 5305) check-in: edf7f518 user: drh tags: trunk
14:26
Fix the allocator in mem5.c so that it can be enabled at run time using the sqlite3_config() function. (CVS 5304) check-in: 30ff6bb0 user: danielk1977 tags: trunk
10:34
Fix up some details to do with the mem3.c (memsys3) allocator. If the library is compiled with SQLITE_ENABLE_MEMSYS3, the memsys3 allocator can be selected at runtime. (CVS 5303) check-in: 9c6c8e01 user: danielk1977 tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/main.c.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
152
153
154
155
156
157
158








159
160
161
162
163
164
165
**
*************************************************************************
** Main file for the SQLite library.  The routines in this file
** implement the programmer interface to the library.  Routines in
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.460 2008/06/25 10:34:35 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

#ifdef SQLITE_ENABLE_FTS3
# include "fts3.h"
#endif
................................................................................
#ifdef SQLITE_ENABLE_MEMSYS3
    case SQLITE_CONFIG_MEMSYS3: {
      u8 *pMem = va_arg(ap, u8*);
      int nMem = va_arg(ap, int);
      sqlite3MemSetMemsys3(pMem, nMem);
      break;
    }








#endif
    case SQLITE_CONFIG_MALLOC: {
      /* Specify an alternative malloc implementation */
      sqlite3Config.m = *va_arg(ap, sqlite3_mem_methods*);
      break;
    }
    case SQLITE_CONFIG_GETMALLOC: {







|







 







>
>
>
>
>
>
>
>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
**
*************************************************************************
** Main file for the SQLite library.  The routines in this file
** implement the programmer interface to the library.  Routines in
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.461 2008/06/25 14:26:08 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

#ifdef SQLITE_ENABLE_FTS3
# include "fts3.h"
#endif
................................................................................
#ifdef SQLITE_ENABLE_MEMSYS3
    case SQLITE_CONFIG_MEMSYS3: {
      u8 *pMem = va_arg(ap, u8*);
      int nMem = va_arg(ap, int);
      sqlite3MemSetMemsys3(pMem, nMem);
      break;
    }
#endif
#ifdef SQLITE_ENABLE_MEMSYS5
    case SQLITE_CONFIG_MEMSYS5: {
      u8 *pMem = va_arg(ap, u8*);
      int nMem = va_arg(ap, int);
      sqlite3MemSetMemsys5(pMem, nMem);
      break;
    }
#endif
    case SQLITE_CONFIG_MALLOC: {
      /* Specify an alternative malloc implementation */
      sqlite3Config.m = *va_arg(ap, sqlite3_mem_methods*);
      break;
    }
    case SQLITE_CONFIG_GETMALLOC: {

Changes to src/mem5.c.

9
10
11
12
13
14
15
16
17
18



19
20
21

22
23

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
..
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
...
126
127
128
129
130
131
132
133
134
135
136
137

138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
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
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
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
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474























475
476
477
478
479
480
481
482
483
484
485
486
487
...
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516




















517
518























**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains the C functions that implement a memory
** allocation subsystem for use by SQLite. 
**
** This version of the memory allocation subsystem omits all
** use of malloc().  All dynamically allocatable memory is
** contained in a static array, mem.aPool[].  The size of this
** fixed memory pool is SQLITE_POW2_MEMORY_SIZE bytes.



**
** This version of the memory allocation subsystem is used if
** and only if SQLITE_POW2_MEMORY_SIZE is defined.

**
** $Id: mem5.c,v 1.6 2008/06/18 17:09:10 danielk1977 Exp $

*/
#include "sqliteInt.h"

/*
** This version of the memory allocator is used only when 
** SQLITE_POW2_MEMORY_SIZE is defined.
*/
#ifdef SQLITE_POW2_MEMORY_SIZE

/*
** Log2 of the minimum size of an allocation.  For example, if
** 4 then all allocations will be rounded up to at least 16 bytes.
** If 5 then all allocations will be rounded up to at least 32 bytes.
*/
#ifndef SQLITE_POW2_LOGMIN
................................................................................
** size of the array is a power of 2.
*/
typedef struct Mem5Block Mem5Block;
struct Mem5Block {
  union {
    char aData[POW2_MIN];
    struct {
      int next;       /* Index in mem.aPool[] of next free chunk */
      int prev;       /* Index in mem.aPool[] of previous free chunk */
    } list;
  } u;
};

/*
** Number of blocks of memory available for allocation.
*/
#define NBLOCK (SQLITE_POW2_MEMORY_SIZE/POW2_MIN)

/*
** The size in blocks of an POW2_MAX allocation
*/
#define SZ_MAX (1<<(NSIZE-1))

/*
** Masks used for mem.aCtrl[] elements.
*/
#define CTRL_LOGSIZE  0x1f    /* Log2 Size of this block relative to POW2_MIN */
#define CTRL_FREE     0x20    /* True if not checked out */

/*
** All of the static variables used by this module are collected
** into a single structure named "mem".  This is to keep the
** static variables organized and to reduce namespace pollution
** when this module is combined with other in the amalgamation.
*/
static struct {
  /*
  ** The alarm callback and its arguments.  The mem.mutex lock will
  ** be held while the callback is running.  Recursive calls into
  ** the memory subsystem are allowed, but no new callbacks will be
  ** issued.  The alarmBusy variable is set to prevent recursive
  ** callbacks.
  */
  sqlite3_int64 alarmThreshold;
  void (*alarmCallback)(void*, sqlite3_int64,int);
................................................................................
  */
  int aiFreelist[NSIZE];

  /*
  ** Space for tracking which blocks are checked out and the size
  ** of each block.  One byte per block.
  */
  u8 aCtrl[NBLOCK];

  /*
  ** Memory available for allocation
  */

  Mem5Block aPool[NBLOCK];
} mem;

/*
** Unlink the chunk at mem.aPool[i] from list it is currently
** on.  It should be found on mem.aiFreelist[iLogsize].
*/
static void memsys5Unlink(int i, int iLogsize){
  int next, prev;
  assert( i>=0 && i<NBLOCK );
  assert( iLogsize>=0 && iLogsize<NSIZE );
  assert( (mem.aCtrl[i] & CTRL_LOGSIZE)==iLogsize );
  assert( sqlite3_mutex_held(mem.mutex) );

  next = mem.aPool[i].u.list.next;
  prev = mem.aPool[i].u.list.prev;
  if( prev<0 ){
    mem.aiFreelist[iLogsize] = next;
  }else{
    mem.aPool[prev].u.list.next = next;
  }
  if( next>=0 ){
    mem.aPool[next].u.list.prev = prev;
  }
}

/*
** Link the chunk at mem.aPool[i] so that is on the iLogsize
** free list.
*/
static void memsys5Link(int i, int iLogsize){
  int x;
  assert( sqlite3_mutex_held(mem.mutex) );
  assert( i>=0 && i<NBLOCK );
  assert( iLogsize>=0 && iLogsize<NSIZE );
  assert( (mem.aCtrl[i] & CTRL_LOGSIZE)==iLogsize );

  mem.aPool[i].u.list.next = x = mem.aiFreelist[iLogsize];
  mem.aPool[i].u.list.prev = -1;
  if( x>=0 ){
    assert( x<NBLOCK );
    mem.aPool[x].u.list.prev = i;
  }
  mem.aiFreelist[iLogsize] = i;
}

/*
** Enter the mutex mem.mutex. Allocate it if it is not already allocated.
**
** Also:  Initialize the memory allocation subsystem the first time
** this routine is called.
*/
static void memsys5Enter(void){
  if( mem.mutex==0 ){
    int i;
    assert( sizeof(Mem5Block)==POW2_MIN );
    assert( (SQLITE_POW2_MEMORY_SIZE % POW2_MAX)==0 );
    assert( SQLITE_POW2_MEMORY_SIZE>=POW2_MAX );
    mem.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
    sqlite3_mutex_enter(mem.mutex);
    for(i=0; i<NSIZE; i++) mem.aiFreelist[i] = -1;
    for(i=0; i<=NBLOCK-SZ_MAX; i += SZ_MAX){
      mem.aCtrl[i] = (NSIZE-1) | CTRL_FREE;
      memsys5Link(i, NSIZE-1);
    }
  }else{
    sqlite3_mutex_enter(mem.mutex);
  }
}

/*
** Return the amount of memory currently checked out.
*/
sqlite3_int64 sqlite3_memory_used(void){
  return mem.currentOut;
}

/*
** Return the maximum amount of memory that has ever been
** checked out since either the beginning of this process
** or since the most recent reset.
*/
sqlite3_int64 sqlite3_memory_highwater(int resetFlag){
  sqlite3_int64 n;
  memsys5Enter();
  n = mem.maxOut;
  if( resetFlag ){
    mem.maxOut = mem.currentOut;
  }
  sqlite3_mutex_leave(mem.mutex);  
  return n;
}


/*
** Trigger the alarm 
*/
static void memsys5Alarm(int nByte){
  void (*xCallback)(void*,sqlite3_int64,int);
  sqlite3_int64 nowUsed;
  void *pArg;
  if( mem.alarmCallback==0 || mem.alarmBusy  ) return;
  mem.alarmBusy = 1;
  xCallback = mem.alarmCallback;
  nowUsed = mem.currentOut;
  pArg = mem.alarmArg;
  sqlite3_mutex_leave(mem.mutex);
  xCallback(pArg, nowUsed, nByte);
  sqlite3_mutex_enter(mem.mutex);
  mem.alarmBusy = 0;
}

/*
** Change the alarm callback.
**
** This is a no-op for the static memory allocator.  The purpose
** of the memory alarm is to support sqlite3_soft_heap_limit().
** But with this memory allocator, the soft_heap_limit is really
** a hard limit that is fixed at SQLITE_POW2_MEMORY_SIZE.
*/
int sqlite3_memory_alarm(
  void(*xCallback)(void *pArg, sqlite3_int64 used,int N),
  void *pArg,
  sqlite3_int64 iThreshold
){
  memsys5Enter();
  mem.alarmCallback = xCallback;
  mem.alarmArg = pArg;
  mem.alarmThreshold = iThreshold;
  sqlite3_mutex_leave(mem.mutex);
  return SQLITE_OK;
}

/*
** Return the size of an outstanding allocation, in bytes.  The
** size returned omits the 8-byte header overhead.  This only
** works for chunks that are currently checked out.
*/
int sqlite3MallocSize(void *p){
  int iSize = 0;
  if( p ){
    int i = ((Mem5Block*)p) - mem.aPool;
    assert( i>=0 && i<NBLOCK );
    iSize = 1 << ((mem.aCtrl[i]&CTRL_LOGSIZE) + SQLITE_POW2_LOGMIN);
  }
  return iSize;
}

/*
** Initialize the memmory allocation subsystem.
*/
int sqlite3MallocInit(void){
  return SQLITE_OK;
}

/*
** Find the first entry on the freelist iLogsize.  Unlink that
** entry and return its index. 
*/
static int memsys5UnlinkFirst(int iLogsize){
  int i;
  int iFirst;

  assert( iLogsize>=0 && iLogsize<NSIZE );
  i = iFirst = mem.aiFreelist[iLogsize];
  assert( iFirst>=0 );
  while( i>0 ){
    if( i<iFirst ) iFirst = i;
    i = mem.aPool[i].u.list.next;
  }
  memsys5Unlink(iFirst, iLogsize);
  return iFirst;
}

/*
** Return a block of memory of at least nBytes in size.
** Return NULL if unable.
*/
static void *memsys5Malloc(int nByte){
  int i;           /* Index of a mem.aPool[] slot */
  int iBin;        /* Index into mem.aiFreelist[] */
  int iFullSz;     /* Size of allocation rounded up to power of 2 */
  int iLogsize;    /* Log2 of iFullSz/POW2_MIN */

  assert( sqlite3_mutex_held(mem.mutex) );

  /* Keep track of the maximum allocation request.  Even unfulfilled
  ** requests are counted */
  if( nByte>mem.maxRequest ){
    mem.maxRequest = nByte;
  }

  /* Simulate a memory allocation fault */
  if( sqlite3FaultStep(SQLITE_FAULTINJECTOR_MALLOC) ) return 0;

  /* Round nByte up to the next valid power of two */
  if( nByte>POW2_MAX ) return 0;
  for(iFullSz=POW2_MIN, iLogsize=0; iFullSz<nByte; iFullSz *= 2, iLogsize++){}

  /* If we will be over the memory alarm threshold after this allocation,
  ** then trigger the memory overflow alarm */
  if( mem.alarmCallback!=0 && mem.currentOut+iFullSz>=mem.alarmThreshold ){
    memsys5Alarm(iFullSz);
  }

  /* Make sure mem.aiFreelist[iLogsize] contains at least one free
  ** block.  If not, then split a block of the next larger power of
  ** two in order to create a new free block of size iLogsize.
  */
  for(iBin=iLogsize; mem.aiFreelist[iBin]<0 && iBin<NSIZE; iBin++){}
  if( iBin>=NSIZE ) return 0;
  i = memsys5UnlinkFirst(iBin);
  while( iBin>iLogsize ){
    int newSize;

    iBin--;
    newSize = 1 << iBin;
    mem.aCtrl[i+newSize] = CTRL_FREE | iBin;
    memsys5Link(i+newSize, iBin);
  }
  mem.aCtrl[i] = iLogsize;

  /* Update allocator performance statistics. */
  mem.nAlloc++;
  mem.totalAlloc += iFullSz;
  mem.totalExcess += iFullSz - nByte;
  mem.currentCount++;
  mem.currentOut += iFullSz;
  if( mem.maxCount<mem.currentCount ) mem.maxCount = mem.currentCount;
  if( mem.maxOut<mem.currentOut ) mem.maxOut = mem.currentOut;

  /* Return a pointer to the allocated memory. */
  return (void*)&mem.aPool[i];
}

/*
** Free an outstanding memory allocation.
*/
void memsys5Free(void *pOld){
  u32 size, iLogsize;
  int i;

  i = ((Mem5Block*)pOld) - mem.aPool;
  assert( sqlite3_mutex_held(mem.mutex) );
  assert( i>=0 && i<NBLOCK );
  assert( (mem.aCtrl[i] & CTRL_FREE)==0 );
  iLogsize = mem.aCtrl[i] & CTRL_LOGSIZE;
  size = 1<<iLogsize;
  assert( i+size-1<NBLOCK );
  mem.aCtrl[i] |= CTRL_FREE;
  mem.aCtrl[i+size-1] |= CTRL_FREE;
  assert( mem.currentCount>0 );
  assert( mem.currentOut>=0 );
  mem.currentCount--;
  mem.currentOut -= size*POW2_MIN;
  assert( mem.currentOut>0 || mem.currentCount==0 );
  assert( mem.currentCount>0 || mem.currentOut==0 );

  mem.aCtrl[i] = CTRL_FREE | iLogsize;
  while( iLogsize<NSIZE-1 ){
    int iBuddy;

    if( (i>>iLogsize) & 1 ){
      iBuddy = i - size;
    }else{
      iBuddy = i + size;
    }
    assert( iBuddy>=0 && iBuddy<NBLOCK );
    if( mem.aCtrl[iBuddy]!=(CTRL_FREE | iLogsize) ) break;
    memsys5Unlink(iBuddy, iLogsize);
    iLogsize++;
    if( iBuddy<i ){
      mem.aCtrl[iBuddy] = CTRL_FREE | iLogsize;
      mem.aCtrl[i] = 0;
      i = iBuddy;
    }else{
      mem.aCtrl[i] = CTRL_FREE | iLogsize;
      mem.aCtrl[iBuddy] = 0;
    }
    size *= 2;
  }
  memsys5Link(i, iLogsize);
}

/*
** Allocate nBytes of memory
*/
void *sqlite3_malloc(int nBytes){
  sqlite3_int64 *p = 0;
  if( nBytes>0 ){
    memsys5Enter();
    p = memsys5Malloc(nBytes);
    sqlite3_mutex_leave(mem.mutex);
  }
  return (void*)p; 
}

/*
** Free memory.
*/
void sqlite3_free(void *pPrior){
  if( pPrior==0 ){
    return;
  }
  assert( mem.mutex!=0 );
  sqlite3_mutex_enter(mem.mutex);
  memsys5Free(pPrior);
  sqlite3_mutex_leave(mem.mutex);  
}

/*
** Change the size of an existing memory allocation
*/
void *sqlite3_realloc(void *pPrior, int nBytes){
  int nOld;
  void *p;
  if( pPrior==0 ){
    return sqlite3_malloc(nBytes);
  }
  if( nBytes<=0 ){
    sqlite3_free(pPrior);
    return 0;
  }
  assert( mem.mutex!=0 );
  nOld = sqlite3MallocSize(pPrior);
  if( nBytes<=nOld ){
    return pPrior;
  }
  sqlite3_mutex_enter(mem.mutex);
  p = memsys5Malloc(nBytes);
  if( p ){
    memcpy(p, pPrior, nOld);
    memsys5Free(pPrior);
  }
  sqlite3_mutex_leave(mem.mutex);
  return p;
}
























/*
** Open the file indicated and write a log of all unfreed memory 
** allocations into that log.
*/
void sqlite3MemdebugDump(const char *zFilename){
#ifdef SQLITE_DEBUG
  FILE *out;
  int i, j, n;

  if( zFilename==0 || zFilename[0]==0 ){
    out = stdout;
  }else{
................................................................................
      fprintf(stderr, "** Unable to output memory debug output log: %s **\n",
                      zFilename);
      return;
    }
  }
  memsys5Enter();
  for(i=0; i<NSIZE; i++){
    for(n=0, j=mem.aiFreelist[i]; j>=0; j = mem.aPool[j].u.list.next, n++){}
    fprintf(out, "freelist items of size %d: %d\n", POW2_MIN << i, n);
  }
  fprintf(out, "mem.nAlloc       = %llu\n", mem.nAlloc);
  fprintf(out, "mem.totalAlloc   = %llu\n", mem.totalAlloc);
  fprintf(out, "mem.totalExcess  = %llu\n", mem.totalExcess);
  fprintf(out, "mem.currentOut   = %u\n", mem.currentOut);
  fprintf(out, "mem.currentCount = %u\n", mem.currentCount);
  fprintf(out, "mem.maxOut       = %u\n", mem.maxOut);
  fprintf(out, "mem.maxCount     = %u\n", mem.maxCount);
  fprintf(out, "mem.maxRequest   = %u\n", mem.maxRequest);
  sqlite3_mutex_leave(mem.mutex);
  if( out==stdout ){
    fflush(stdout);
  }else{
    fclose(out);
  }
#endif
}






















#endif /* !SQLITE_POW2_MEMORY_SIZE */






























|
|
|
>
>
>

|
<
>

<
>







|







 







|
|




<
<
<
<
<






|






|





|







 







|




>
|
|


|
|



|

|
<

|
|

|

|


|




|




|
|

|

|
|

|
|

|



|





<
<
<
<
<
<
<
<
<
<
<
|
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<



<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




|


|
|
|




<
<
<
<
<
<
<









|



|









|
|
|



<
<


|
|


<
<
<




<
<
<
<
<
<
|



|







|


|


|
|
|
|
|
|
|


|





|



|
<
|
|
|

|
|
|
|
|
|
|
|
|

|








|
|



|
|


|
|









|



|
|







|



|
|
|
<





|



|


|


<
|



|
|


|

|


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>





|







 







|


|
|
|
|
|
|
|
|
|








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

24
25

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
..
62
63
64
65
66
67
68
69
70
71
72
73
74





75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
...
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148

149
150
151
152
153
154
155
156
157
158
159
160
161
162
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





























191












192
193
194





















195
196
197
198
199
200
201
202
203
204
205
206
207
208







209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237


238
239
240
241
242
243



244
245
246
247






248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
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
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348

349
350
351
352
353
354
355
356
357
358
359
360
361
362
363

364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
...
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462

463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains the C functions that implement a memory
** allocation subsystem for use by SQLite. 
**
** This version of the memory allocation subsystem omits all
** use of malloc(). The SQLite user supplies a block of memory
** before calling sqlite3_initialize() from which allocations
** are made and returned by the xMalloc() and xRealloc() 
** implementations. Once sqlite3_initialize() has been called,
** the amount of memory available to SQLite is fixed and cannot
** be changed.
**
** This version of the memory allocation subsystem is included

** in the build only if SQLITE_ENABLE_MEMSYS5 is defined.
**

** $Id: mem5.c,v 1.7 2008/06/25 14:26:08 danielk1977 Exp $
*/
#include "sqliteInt.h"

/*
** This version of the memory allocator is used only when 
** SQLITE_POW2_MEMORY_SIZE is defined.
*/
#ifdef SQLITE_ENABLE_MEMSYS5

/*
** Log2 of the minimum size of an allocation.  For example, if
** 4 then all allocations will be rounded up to at least 16 bytes.
** If 5 then all allocations will be rounded up to at least 32 bytes.
*/
#ifndef SQLITE_POW2_LOGMIN
................................................................................
** size of the array is a power of 2.
*/
typedef struct Mem5Block Mem5Block;
struct Mem5Block {
  union {
    char aData[POW2_MIN];
    struct {
      int next;       /* Index in mem5.aPool[] of next free chunk */
      int prev;       /* Index in mem5.aPool[] of previous free chunk */
    } list;
  } u;
};






/*
** The size in blocks of an POW2_MAX allocation
*/
#define SZ_MAX (1<<(NSIZE-1))

/*
** Masks used for mem5.aCtrl[] elements.
*/
#define CTRL_LOGSIZE  0x1f    /* Log2 Size of this block relative to POW2_MIN */
#define CTRL_FREE     0x20    /* True if not checked out */

/*
** All of the static variables used by this module are collected
** into a single structure named "mem5".  This is to keep the
** static variables organized and to reduce namespace pollution
** when this module is combined with other in the amalgamation.
*/
static struct {
  /*
  ** The alarm callback and its arguments.  The mem5.mutex lock will
  ** be held while the callback is running.  Recursive calls into
  ** the memory subsystem are allowed, but no new callbacks will be
  ** issued.  The alarmBusy variable is set to prevent recursive
  ** callbacks.
  */
  sqlite3_int64 alarmThreshold;
  void (*alarmCallback)(void*, sqlite3_int64,int);
................................................................................
  */
  int aiFreelist[NSIZE];

  /*
  ** Space for tracking which blocks are checked out and the size
  ** of each block.  One byte per block.
  */
  u8 *aCtrl;

  /*
  ** Memory available for allocation
  */
  int nBlock;
  Mem5Block *aPool;
} mem5;

/*
** Unlink the chunk at mem5.aPool[i] from list it is currently
** on.  It should be found on mem5.aiFreelist[iLogsize].
*/
static void memsys5Unlink(int i, int iLogsize){
  int next, prev;
  assert( i>=0 && i<mem5.nBlock );
  assert( iLogsize>=0 && iLogsize<NSIZE );
  assert( (mem5.aCtrl[i] & CTRL_LOGSIZE)==iLogsize );


  next = mem5.aPool[i].u.list.next;
  prev = mem5.aPool[i].u.list.prev;
  if( prev<0 ){
    mem5.aiFreelist[iLogsize] = next;
  }else{
    mem5.aPool[prev].u.list.next = next;
  }
  if( next>=0 ){
    mem5.aPool[next].u.list.prev = prev;
  }
}

/*
** Link the chunk at mem5.aPool[i] so that is on the iLogsize
** free list.
*/
static void memsys5Link(int i, int iLogsize){
  int x;
  assert( sqlite3_mutex_held(mem5.mutex) );
  assert( i>=0 && i<mem5.nBlock );
  assert( iLogsize>=0 && iLogsize<NSIZE );
  assert( (mem5.aCtrl[i] & CTRL_LOGSIZE)==iLogsize );

  mem5.aPool[i].u.list.next = x = mem5.aiFreelist[iLogsize];
  mem5.aPool[i].u.list.prev = -1;
  if( x>=0 ){
    assert( x<mem5.nBlock );
    mem5.aPool[x].u.list.prev = i;
  }
  mem5.aiFreelist[iLogsize] = i;
}

/*
** Enter the mutex mem5.mutex. Allocate it if it is not already allocated.
**
** Also:  Initialize the memory allocation subsystem the first time
** this routine is called.
*/
static void memsys5Enter(void){











}
































static void memsys5Leave(void){












}

/*





















** Return the size of an outstanding allocation, in bytes.  The
** size returned omits the 8-byte header overhead.  This only
** works for chunks that are currently checked out.
*/
static int memsys5Size(void *p){
  int iSize = 0;
  if( p ){
    int i = ((Mem5Block*)p) - mem5.aPool;
    assert( i>=0 && i<mem5.nBlock );
    iSize = 1 << ((mem5.aCtrl[i]&CTRL_LOGSIZE) + SQLITE_POW2_LOGMIN);
  }
  return iSize;
}








/*
** Find the first entry on the freelist iLogsize.  Unlink that
** entry and return its index. 
*/
static int memsys5UnlinkFirst(int iLogsize){
  int i;
  int iFirst;

  assert( iLogsize>=0 && iLogsize<NSIZE );
  i = iFirst = mem5.aiFreelist[iLogsize];
  assert( iFirst>=0 );
  while( i>0 ){
    if( i<iFirst ) iFirst = i;
    i = mem5.aPool[i].u.list.next;
  }
  memsys5Unlink(iFirst, iLogsize);
  return iFirst;
}

/*
** Return a block of memory of at least nBytes in size.
** Return NULL if unable.
*/
static void *memsys5MallocUnsafe(int nByte){
  int i;           /* Index of a mem5.aPool[] slot */
  int iBin;        /* Index into mem5.aiFreelist[] */
  int iFullSz;     /* Size of allocation rounded up to power of 2 */
  int iLogsize;    /* Log2 of iFullSz/POW2_MIN */



  /* Keep track of the maximum allocation request.  Even unfulfilled
  ** requests are counted */
  if( nByte>mem5.maxRequest ){
    mem5.maxRequest = nByte;
  }




  /* Round nByte up to the next valid power of two */
  if( nByte>POW2_MAX ) return 0;
  for(iFullSz=POW2_MIN, iLogsize=0; iFullSz<nByte; iFullSz *= 2, iLogsize++){}







  /* Make sure mem5.aiFreelist[iLogsize] contains at least one free
  ** block.  If not, then split a block of the next larger power of
  ** two in order to create a new free block of size iLogsize.
  */
  for(iBin=iLogsize; mem5.aiFreelist[iBin]<0 && iBin<NSIZE; iBin++){}
  if( iBin>=NSIZE ) return 0;
  i = memsys5UnlinkFirst(iBin);
  while( iBin>iLogsize ){
    int newSize;

    iBin--;
    newSize = 1 << iBin;
    mem5.aCtrl[i+newSize] = CTRL_FREE | iBin;
    memsys5Link(i+newSize, iBin);
  }
  mem5.aCtrl[i] = iLogsize;

  /* Update allocator performance statistics. */
  mem5.nAlloc++;
  mem5.totalAlloc += iFullSz;
  mem5.totalExcess += iFullSz - nByte;
  mem5.currentCount++;
  mem5.currentOut += iFullSz;
  if( mem5.maxCount<mem5.currentCount ) mem5.maxCount = mem5.currentCount;
  if( mem5.maxOut<mem5.currentOut ) mem5.maxOut = mem5.currentOut;

  /* Return a pointer to the allocated memory. */
  return (void*)&mem5.aPool[i];
}

/*
** Free an outstanding memory allocation.
*/
static void memsys5FreeUnsafe(void *pOld){
  u32 size, iLogsize;
  int i;

  i = ((Mem5Block*)pOld) - mem5.aPool;

  assert( i>=0 && i<mem5.nBlock );
  assert( (mem5.aCtrl[i] & CTRL_FREE)==0 );
  iLogsize = mem5.aCtrl[i] & CTRL_LOGSIZE;
  size = 1<<iLogsize;
  assert( i+size-1<mem5.nBlock );
  mem5.aCtrl[i] |= CTRL_FREE;
  mem5.aCtrl[i+size-1] |= CTRL_FREE;
  assert( mem5.currentCount>0 );
  assert( mem5.currentOut>=0 );
  mem5.currentCount--;
  mem5.currentOut -= size*POW2_MIN;
  assert( mem5.currentOut>0 || mem5.currentCount==0 );
  assert( mem5.currentCount>0 || mem5.currentOut==0 );

  mem5.aCtrl[i] = CTRL_FREE | iLogsize;
  while( iLogsize<NSIZE-1 ){
    int iBuddy;

    if( (i>>iLogsize) & 1 ){
      iBuddy = i - size;
    }else{
      iBuddy = i + size;
    }
    assert( iBuddy>=0 && iBuddy<mem5.nBlock );
    if( mem5.aCtrl[iBuddy]!=(CTRL_FREE | iLogsize) ) break;
    memsys5Unlink(iBuddy, iLogsize);
    iLogsize++;
    if( iBuddy<i ){
      mem5.aCtrl[iBuddy] = CTRL_FREE | iLogsize;
      mem5.aCtrl[i] = 0;
      i = iBuddy;
    }else{
      mem5.aCtrl[i] = CTRL_FREE | iLogsize;
      mem5.aCtrl[iBuddy] = 0;
    }
    size *= 2;
  }
  memsys5Link(i, iLogsize);
}

/*
** Allocate nBytes of memory
*/
static void *memsys5Malloc(int nBytes){
  sqlite3_int64 *p = 0;
  if( nBytes>0 ){
    memsys5Enter();
    p = memsys5MallocUnsafe(nBytes);
    memsys5Leave();
  }
  return (void*)p; 
}

/*
** Free memory.
*/
static void memsys5Free(void *pPrior){
  if( pPrior==0 ){
    return;
  }
  memsys5Enter();
  memsys5FreeUnsafe(pPrior);
  memsys5Leave();  

}

/*
** Change the size of an existing memory allocation
*/
static void *memsys5Realloc(void *pPrior, int nBytes){
  int nOld;
  void *p;
  if( pPrior==0 ){
    return memsys5Malloc(nBytes);
  }
  if( nBytes<=0 ){
    memsys5Free(pPrior);
    return 0;
  }

  nOld = memsys5Size(pPrior);
  if( nBytes<=nOld ){
    return pPrior;
  }
  memsys5Enter();
  p = memsys5MallocUnsafe(nBytes);
  if( p ){
    memcpy(p, pPrior, nOld);
    memsys5FreeUnsafe(pPrior);
  }
  memsys5Leave();
  return p;
}

/*
** Round up a request size to the next valid allocation size.
*/
static int memsys5Roundup(int n){
  int iFullSz;
  for(iFullSz=POW2_MIN; iFullSz<n; iFullSz *= 2);
  return iFullSz;
}

/*
** Initialize this module.
*/
static int memsys5Init(void *NotUsed){
  return SQLITE_OK;
}

/*
** Deinitialize this module.
*/
static void memsys5Shutdown(void *NotUsed){
  return;
}

/*
** Open the file indicated and write a log of all unfreed memory 
** allocations into that log.
*/
void sqlite3Memsys5Dump(const char *zFilename){
#ifdef SQLITE_DEBUG
  FILE *out;
  int i, j, n;

  if( zFilename==0 || zFilename[0]==0 ){
    out = stdout;
  }else{
................................................................................
      fprintf(stderr, "** Unable to output memory debug output log: %s **\n",
                      zFilename);
      return;
    }
  }
  memsys5Enter();
  for(i=0; i<NSIZE; i++){
    for(n=0, j=mem5.aiFreelist[i]; j>=0; j = mem5.aPool[j].u.list.next, n++){}
    fprintf(out, "freelist items of size %d: %d\n", POW2_MIN << i, n);
  }
  fprintf(out, "mem5.nAlloc       = %llu\n", mem5.nAlloc);
  fprintf(out, "mem5.totalAlloc   = %llu\n", mem5.totalAlloc);
  fprintf(out, "mem5.totalExcess  = %llu\n", mem5.totalExcess);
  fprintf(out, "mem5.currentOut   = %u\n", mem5.currentOut);
  fprintf(out, "mem5.currentCount = %u\n", mem5.currentCount);
  fprintf(out, "mem5.maxOut       = %u\n", mem5.maxOut);
  fprintf(out, "mem5.maxCount     = %u\n", mem5.maxCount);
  fprintf(out, "mem5.maxRequest   = %u\n", mem5.maxRequest);
  memsys5Leave();
  if( out==stdout ){
    fflush(stdout);
  }else{
    fclose(out);
  }
#endif
}

/*
** This routine is the only routine in this file with external 
** linkage.
**
** Populate the low-level memory allocation function pointers in
** sqlite3Config.m with pointers to the routines in this file. The
** arguments specify the block of memory to manage.
**
** This routine is only called by sqlite3_config(), and therefore
** is not required to be threadsafe (it is not).
*/
void sqlite3MemSetMemsys5(u8 *zByte, int nByte){
  static const sqlite3_mem_methods memsys5Methods = {
     memsys5Malloc,
     memsys5Free,
     memsys5Realloc,
     memsys5Size,
     memsys5Roundup,
     memsys5Init,
     memsys5Shutdown,
     0

  };
  int i;

  mem5.nBlock = (nByte / (sizeof(Mem5Block)+sizeof(u8)));
  mem5.nBlock -= (mem5.nBlock%SZ_MAX);
  mem5.aPool = (Mem5Block *)zByte;
  mem5.aCtrl = (u8 *)&mem5.aPool[mem5.nBlock];

  assert( sizeof(Mem5Block)==POW2_MIN );
  assert( mem5.nBlock>=SZ_MAX );
  assert( (mem5.nBlock%SZ_MAX)==0 );

  for(i=0; i<NSIZE; i++) mem5.aiFreelist[i] = -1;
  for(i=0; i<=mem5.nBlock-SZ_MAX; i += SZ_MAX){
    mem5.aCtrl[i] = (NSIZE-1) | CTRL_FREE;
    memsys5Link(i, NSIZE-1);
  }

  /* Configure the functions to call to allocate memory. */
  sqlite3_config(SQLITE_CONFIG_MALLOC, &memsys5Methods);
}

#endif /* SQLITE_ENABLE_MEMSYS5 */

Changes to src/sqlite.h.in.

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
....
1111
1112
1113
1114
1115
1116
1117








1118
1119
1120
1121
1122
1123
1124
....
1125
1126
1127
1128
1129
1130
1131

1132
1133
1134
1135
1136
1137
1138
** on how SQLite interfaces are suppose to operate.
**
** The name of this file under configuration management is "sqlite.h.in".
** The makefile makes some minor changes to this file (such as inserting
** the version number) and changes its name to "sqlite3.h" as
** part of the build process.
**
** @(#) $Id: sqlite.h.in,v 1.356 2008/06/25 10:34:35 danielk1977 Exp $
*/
#ifndef _SQLITE3_H_
#define _SQLITE3_H_
#include <stdarg.h>     /* Needed for the definition of va_list */

/*
** Make sure we can call this stuff from C++.
................................................................................
** This options must be passed two arguments, a pointer to a large blob of
** allocated memory (type char*) and the size of the block of memory in bytes
** (type int). The memsys3 allocator manages this block of memory and uses
** it to satisfy all requests for dynamic memory made by the library. The
** caller must ensure that the block of memory remains valid for as long
** as the memsys3 allocator is in use.</dd>
**








** </dl>
*/
#define SQLITE_CONFIG_SINGLETHREAD  1  /* nil */
#define SQLITE_CONFIG_MULTITHREAD   2  /* nil */
#define SQLITE_CONFIG_SERIALIZED    3  /* nil */
#define SQLITE_CONFIG_MALLOC        4  /* sqlite3_mem_methods* */
#define SQLITE_CONFIG_GETMALLOC     5  /* sqlite3_mem_methods* */
................................................................................
#define SQLITE_CONFIG_SCRATCH       6  /* void*, int sz, int N */
#define SQLITE_CONFIG_PAGECACHE     7  /* void*, int sz, int N */
#define SQLITE_CONFIG_HEAP          8  /* void*, int nByte, int min */
#define SQLITE_CONFIG_MEMSTATUS     9  /* boolean */
#define SQLITE_CONFIG_MUTEX        10  /* sqlite3_mutex_methods* */
#define SQLITE_CONFIG_GETMUTEX     11  /* sqlite3_mutex_methods* */
#define SQLITE_CONFIG_MEMSYS3      12  /* u8*, int */


/*
** CAPI3REF: Enable Or Disable Extended Result Codes {F12200}
**
** The sqlite3_extended_result_codes() routine enables or disables the
** [extended result codes] feature of SQLite. The extended result
** codes are disabled by default for historical compatibility considerations.







|







 







>
>
>
>
>
>
>
>







 







>







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
....
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
....
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
** on how SQLite interfaces are suppose to operate.
**
** The name of this file under configuration management is "sqlite.h.in".
** The makefile makes some minor changes to this file (such as inserting
** the version number) and changes its name to "sqlite3.h" as
** part of the build process.
**
** @(#) $Id: sqlite.h.in,v 1.357 2008/06/25 14:26:08 danielk1977 Exp $
*/
#ifndef _SQLITE3_H_
#define _SQLITE3_H_
#include <stdarg.h>     /* Needed for the definition of va_list */

/*
** Make sure we can call this stuff from C++.
................................................................................
** This options must be passed two arguments, a pointer to a large blob of
** allocated memory (type char*) and the size of the block of memory in bytes
** (type int). The memsys3 allocator manages this block of memory and uses
** it to satisfy all requests for dynamic memory made by the library. The
** caller must ensure that the block of memory remains valid for as long
** as the memsys3 allocator is in use.</dd>
**
** <dt>SQLITE_CONFIG_MEMSYS5</dt>
** <dd>This option is only available if SQLite is compiled with the 
** SQLITE_ENABLE_MEMSYS5 symbol defined. If available, then it is similar
** to the SQLITE_CONFIG_MEMSYS3 option. The "memsys5" allocator differs
** from the "memsys3" allocator in that it rounds all allocations up to
** the next largest power of two. Although this is sometimes more wasteful
** than the procudures used by memsys3, it guarantees an upper limit on
** internal fragmentation.</dd>
** </dl>
*/
#define SQLITE_CONFIG_SINGLETHREAD  1  /* nil */
#define SQLITE_CONFIG_MULTITHREAD   2  /* nil */
#define SQLITE_CONFIG_SERIALIZED    3  /* nil */
#define SQLITE_CONFIG_MALLOC        4  /* sqlite3_mem_methods* */
#define SQLITE_CONFIG_GETMALLOC     5  /* sqlite3_mem_methods* */
................................................................................
#define SQLITE_CONFIG_SCRATCH       6  /* void*, int sz, int N */
#define SQLITE_CONFIG_PAGECACHE     7  /* void*, int sz, int N */
#define SQLITE_CONFIG_HEAP          8  /* void*, int nByte, int min */
#define SQLITE_CONFIG_MEMSTATUS     9  /* boolean */
#define SQLITE_CONFIG_MUTEX        10  /* sqlite3_mutex_methods* */
#define SQLITE_CONFIG_GETMUTEX     11  /* sqlite3_mutex_methods* */
#define SQLITE_CONFIG_MEMSYS3      12  /* u8*, int */
#define SQLITE_CONFIG_MEMSYS5      13  /* u8*, int */

/*
** CAPI3REF: Enable Or Disable Extended Result Codes {F12200}
**
** The sqlite3_extended_result_codes() routine enables or disables the
** [extended result codes] feature of SQLite. The extended result
** codes are disabled by default for historical compatibility considerations.

Changes to src/sqliteInt.h.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
....
1800
1801
1802
1803
1804
1805
1806

1807
1808
1809
1810
1811
1812
1813
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.727 2008/06/25 10:34:35 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** Include the configuration header output by 'configure' if we're using the
** autoconf-based build
................................................................................
int sqlite3MallocSize(void *);
void *sqlite3ScratchMalloc(int);
void sqlite3ScratchFree(void*);
void *sqlite3PageMalloc(int);
void sqlite3PageFree(void*);
void sqlite3MemSetDefault(void);
void sqlite3MemSetMemsys3(u8 *pBlock, int nBlock);

void sqlite3BenignMallocHooks(void (*)(void), void (*)(void));

#ifndef SQLITE_MUTEX_NOOP
  sqlite3_mutex_methods *sqlite3DefaultMutex(void);
  sqlite3_mutex *sqlite3MutexAlloc(int);
  int sqlite3MutexInit(void);
  int sqlite3MutexEnd(void);







|







 







>







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
....
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.728 2008/06/25 14:26:08 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** Include the configuration header output by 'configure' if we're using the
** autoconf-based build
................................................................................
int sqlite3MallocSize(void *);
void *sqlite3ScratchMalloc(int);
void sqlite3ScratchFree(void*);
void *sqlite3PageMalloc(int);
void sqlite3PageFree(void*);
void sqlite3MemSetDefault(void);
void sqlite3MemSetMemsys3(u8 *pBlock, int nBlock);
void sqlite3MemSetMemsys5(u8 *pBlock, int nBlock);
void sqlite3BenignMallocHooks(void (*)(void), void (*)(void));

#ifndef SQLITE_MUTEX_NOOP
  sqlite3_mutex_methods *sqlite3DefaultMutex(void);
  sqlite3_mutex *sqlite3MutexAlloc(int);
  int sqlite3MutexInit(void);
  int sqlite3MutexEnd(void);

Changes to src/test_malloc.c.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
927
928
929
930
931
932
933


934

935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965


966

967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982



983
984


985





986


987
988
989
990
991
992
993
....
1065
1066
1067
1068
1069
1070
1071

1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092




1093
1094
1095

1096
1097
1098
1099
1100
**    May you share freely, never taking more than you give.
**
*************************************************************************
**
** This file contains code used to implement test interfaces to the
** memory allocation subsystem.
**
** $Id: test_malloc.c,v 1.30 2008/06/25 10:34:35 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>

................................................................................
  Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
  Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N));
  Tcl_SetObjResult(interp, pResult);
  return TCL_OK;
}

/*


** Usage:    sqlite3_config_memsys3 NBYTE

**
*/
static int test_config_memsys3(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  int sz, rc;
  Tcl_Obj *pResult;
  static char buf[1000000];
  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "NBYTE");
    return TCL_ERROR;
  }
  if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
  if( sz<=0 ){
    sqlite3_mem_methods m;
    memset(&m, 0, sizeof(sqlite3_mem_methods));
    rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &m);
  }else{
    if( sz>sizeof(buf) ){
      sz = sizeof(buf);
    }
    rc = sqlite3_config(SQLITE_CONFIG_MEMSYS3, buf, sz);
  }
  Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
  return TCL_OK;
}

/*


** Usage:    sqlite3_dump_memsys3  FILENAME

**
** Write a summary of unfreed memsys3 allocations to FILENAME.
*/
static int test_dump_memsys3(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
    return TCL_ERROR;
  }
#if defined(SQLITE_MEMDEBUG) || defined(SQLITE_MEMORY_SIZE) \
     || defined(SQLITE_POW2_MEMORY_SIZE)
  {



    extern void sqlite3Memsys3Dump(const char*);
    sqlite3Memsys3Dump(Tcl_GetString(objv[1]));


  }





#endif


  return TCL_OK;
}

/*
** Usage:    sqlite3_status  OPCODE  RESETFLAG
**
** Return a list of three elements which are the sqlite3_status() return
................................................................................
/*
** Register commands with the TCL interpreter.
*/
int Sqlitetest_malloc_Init(Tcl_Interp *interp){
  static struct {
     char *zName;
     Tcl_ObjCmdProc *xProc;

  } aObjCmd[] = {
     { "sqlite3_malloc",             test_malloc                   },
     { "sqlite3_realloc",            test_realloc                  },
     { "sqlite3_free",               test_free                     },
     { "memset",                     test_memset                   },
     { "memget",                     test_memget                   },
     { "sqlite3_memory_used",        test_memory_used              },
     { "sqlite3_memory_highwater",   test_memory_highwater         },
     { "sqlite3_memdebug_backtrace", test_memdebug_backtrace       },
     { "sqlite3_memdebug_dump",      test_memdebug_dump            },
     { "sqlite3_memdebug_fail",      test_memdebug_fail            },
     { "sqlite3_memdebug_pending",   test_memdebug_pending         },
     { "sqlite3_memdebug_settitle",  test_memdebug_settitle        },
     { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count },
     { "sqlite3_memdebug_log",       test_memdebug_log             },
     { "sqlite3_config_scratch",     test_config_scratch           },
     { "sqlite3_config_pagecache",   test_config_pagecache         },
     { "sqlite3_config_memsys3",     test_config_memsys3           },
     { "sqlite3_dump_memsys3",       test_dump_memsys3             },
     { "sqlite3_status",             test_status                   },
     { "install_malloc_faultsim",    test_install_malloc_faultsim  },




  };
  int i;
  for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){

    Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0);
  }
  return TCL_OK;
}
#endif







|







 







>
>
|
>



|





<
|













|






>
>
|
>













<
<
|
>
>
>
|
|
>
>
|
>
>
>
>
>

>
>







 







>

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
<
|
|
>
>
>
>



>
|




9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946

947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984


985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
....
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104


1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
**    May you share freely, never taking more than you give.
**
*************************************************************************
**
** This file contains code used to implement test interfaces to the
** memory allocation subsystem.
**
** $Id: test_malloc.c,v 1.31 2008/06/25 14:26:09 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>

................................................................................
  Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
  Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N));
  Tcl_SetObjResult(interp, pResult);
  return TCL_OK;
}

/*
** Usage:    
** 
**   sqlite3_config_memsys3 NBYTE
**   sqlite3_config_memsys5 NBYTE
**
*/
static int test_config_memsys3(
  void * clientData, 
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  int sz, rc;

  static char buf[1048576];
  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "NBYTE");
    return TCL_ERROR;
  }
  if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
  if( sz<=0 ){
    sqlite3_mem_methods m;
    memset(&m, 0, sizeof(sqlite3_mem_methods));
    rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &m);
  }else{
    if( sz>sizeof(buf) ){
      sz = sizeof(buf);
    }
    rc = sqlite3_config((int)clientData, buf, sz);
  }
  Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
  return TCL_OK;
}

/*
** Usage:    
**
**   sqlite3_dump_memsys3  FILENAME
**   sqlite3_dump_memsys5  FILENAME
**
** Write a summary of unfreed memsys3 allocations to FILENAME.
*/
static int test_dump_memsys3(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
    return TCL_ERROR;
  }



  switch( (int)clientData ){
    case SQLITE_CONFIG_MEMSYS3: {
#ifdef SQLITE_ENABLE_MEMSYS3
      extern void sqlite3Memsys3Dump(const char*);
      sqlite3Memsys3Dump(Tcl_GetString(objv[1]));
      break;
#endif
    }
    case SQLITE_CONFIG_MEMSYS5: {
#ifdef SQLITE_ENABLE_MEMSYS5
      extern void sqlite3Memsys5Dump(const char*);
      sqlite3Memsys5Dump(Tcl_GetString(objv[1]));
      break;
#endif
    }
  }
  return TCL_OK;
}

/*
** Usage:    sqlite3_status  OPCODE  RESETFLAG
**
** Return a list of three elements which are the sqlite3_status() return
................................................................................
/*
** Register commands with the TCL interpreter.
*/
int Sqlitetest_malloc_Init(Tcl_Interp *interp){
  static struct {
     char *zName;
     Tcl_ObjCmdProc *xProc;
     int clientData;
  } aObjCmd[] = {
     { "sqlite3_malloc",             test_malloc                   ,0. },
     { "sqlite3_realloc",            test_realloc                  ,0. },
     { "sqlite3_free",               test_free                     ,0. },
     { "memset",                     test_memset                   ,0. },
     { "memget",                     test_memget                   ,0. },
     { "sqlite3_memory_used",        test_memory_used              ,0. },
     { "sqlite3_memory_highwater",   test_memory_highwater         ,0. },
     { "sqlite3_memdebug_backtrace", test_memdebug_backtrace       ,0. },
     { "sqlite3_memdebug_dump",      test_memdebug_dump            ,0. },
     { "sqlite3_memdebug_fail",      test_memdebug_fail            ,0. },
     { "sqlite3_memdebug_pending",   test_memdebug_pending         ,0. },
     { "sqlite3_memdebug_settitle",  test_memdebug_settitle        ,0. },
     { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count ,0. },
     { "sqlite3_memdebug_log",       test_memdebug_log             ,0. },
     { "sqlite3_config_scratch",     test_config_scratch           ,0. },
     { "sqlite3_config_pagecache",   test_config_pagecache         ,0. },


     { "sqlite3_status",             test_status                   ,0. },
     { "install_malloc_faultsim",    test_install_malloc_faultsim  ,0. },
     { "sqlite3_config_memsys3", test_config_memsys3, SQLITE_CONFIG_MEMSYS3 },
     { "sqlite3_config_memsys5", test_config_memsys3, SQLITE_CONFIG_MEMSYS5 },
     { "sqlite3_dump_memsys3",   test_dump_memsys3  , SQLITE_CONFIG_MEMSYS3 },
     { "sqlite3_dump_memsys5",   test_dump_memsys3  , SQLITE_CONFIG_MEMSYS5 }
  };
  int i;
  for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
    ClientData c = (ClientData)aObjCmd[i].clientData;
    Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, c, 0);
  }
  return TCL_OK;
}
#endif

Changes to test/permutations.test.

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
...
348
349
350
351
352
353
354
























355
356
357
358
359
360
361
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# $Id: permutations.test,v 1.5 2008/06/25 10:34:35 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Argument processing.
#
set ::testmode [lindex $argv 0]
................................................................................
  catch {db close}
  sqlite3_reset_auto_extension
  sqlite3_shutdown
  sqlite3_config_memsys3 0
  install_malloc_faultsim 1 
  sqlite3_initialize
}

























# run_tests "crash_safe_append" -description {
#   Run crash.test with persistent journals on a SAFE_APPEND file-system.
# } -initialize {
#   rename crashsql sa_crashsql
#   proc crashsql {args} {
#     set options [lrange $args 0 [expr {[llength $args]-2}]]







|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
...
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# $Id: permutations.test,v 1.6 2008/06/25 14:26:09 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Argument processing.
#
set ::testmode [lindex $argv 0]
................................................................................
  catch {db close}
  sqlite3_reset_auto_extension
  sqlite3_shutdown
  sqlite3_config_memsys3 0
  install_malloc_faultsim 1 
  sqlite3_initialize
}

run_tests "memsys5" -description {
  Run tests using the allocator in mem3.c.
} -exclude {
  incrblob2.test manydb.test  autovacuum.test bigrow.test
  collate5.test  delete3.test index2.test     ioerr.test  join3.test 
  pagesize.test  bitvec.test  capi3.test      memsubsys1.test  limit.test
  memdb.test     capi3c.test  func.test
} -initialize {
  catch {db close}
  sqlite3_reset_auto_extension
  sqlite3_shutdown
  sqlite3_config_memsys5 1000000
  install_malloc_faultsim 1 
  sqlite3_initialize
  autoinstall_test_functions
} -shutdown {
  catch {db close}
  sqlite3_reset_auto_extension
  sqlite3_shutdown
  sqlite3_config_memsys5 0
  install_malloc_faultsim 1 
  sqlite3_initialize
}

# run_tests "crash_safe_append" -description {
#   Run crash.test with persistent journals on a SAFE_APPEND file-system.
# } -initialize {
#   rename crashsql sa_crashsql
#   proc crashsql {args} {
#     set options [lrange $args 0 [expr {[llength $args]-2}]]