~ubuntu-branches/ubuntu/raring/tcl8.5/raring

« back to all changes in this revision

Viewing changes to generic/tclAlloc.c

  • Committer: Bazaar Package Importer
  • Author(s): Sergei Golovan
  • Date: 2007-10-26 22:04:32 UTC
  • Revision ID: james.westby@ubuntu.com-20071026220432-57je4z35i4ll6uit
Tags: upstream-0.b2
ImportĀ upstreamĀ versionĀ 0.b2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * tclAlloc.c --
 
3
 *
 
4
 *      This is a very fast storage allocator. It allocates blocks of a small
 
5
 *      number of different sizes, and keeps free lists of each size. Blocks
 
6
 *      that don't exactly fit are passed up to the next larger size. Blocks
 
7
 *      over a certain size are directly allocated from the system.
 
8
 *
 
9
 * Copyright (c) 1983 Regents of the University of California.
 
10
 * Copyright (c) 1996-1997 Sun Microsystems, Inc.
 
11
 * Copyright (c) 1998-1999 by Scriptics Corporation.
 
12
 *
 
13
 * Portions contributed by Chris Kingsley, Jack Jansen and Ray Johnson.
 
14
 *
 
15
 * See the file "license.terms" for information on usage and redistribution of
 
16
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 
17
 *
 
18
 * RCS: @(#) $Id: tclAlloc.c,v 1.25 2007/06/29 03:17:05 das Exp $
 
19
 */
 
20
 
 
21
/*
 
22
 * Windows and Unix use an alternative allocator when building with threads
 
23
 * that has significantly reduced lock contention.
 
24
 */
 
25
 
 
26
#include "tclInt.h"
 
27
#if !defined(TCL_THREADS) || !defined(USE_THREAD_ALLOC)
 
28
 
 
29
#if USE_TCLALLOC
 
30
 
 
31
#ifdef TCL_DEBUG
 
32
#   define DEBUG
 
33
/* #define MSTATS */
 
34
#   define RCHECK
 
35
#endif
 
36
 
 
37
/*
 
38
 * We should really make use of AC_CHECK_TYPE(caddr_t) here, but it can wait
 
39
 * until Tcl uses config.h properly.
 
40
 */
 
41
 
 
42
#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__BORLANDC__)
 
43
typedef unsigned long caddr_t;
 
44
#endif
 
45
 
 
46
/*
 
47
 * Alignment for allocated memory.
 
48
 */
 
49
 
 
50
#if defined(__APPLE__)
 
51
#define ALLOCALIGN      16
 
52
#else
 
53
#define ALLOCALIGN      8
 
54
#endif
 
55
 
 
56
/*
 
57
 * The overhead on a block is at least 8 bytes. When free, this space contains
 
58
 * a pointer to the next free block, and the bottom two bits must be zero.
 
59
 * When in use, the first byte is set to MAGIC, and the second byte is the
 
60
 * size index. The remaining bytes are for alignment. If range checking is
 
61
 * enabled then a second word holds the size of the requested block, less 1,
 
62
 * rounded up to a multiple of sizeof(RMAGIC). The order of elements is
 
63
 * critical: ov.magic must overlay the low order bits of ov.next, and ov.magic
 
64
 * can not be a valid ov.next bit pattern.
 
65
 */
 
66
 
 
67
union overhead {
 
68
    union overhead *next;               /* when free */
 
69
    unsigned char padding[ALLOCALIGN];  /* align struct to ALLOCALIGN bytes */
 
70
    struct {
 
71
        unsigned char magic0;           /* magic number */
 
72
        unsigned char index;            /* bucket # */
 
73
        unsigned char unused;           /* unused */
 
74
        unsigned char magic1;           /* other magic number */
 
75
#ifdef RCHECK
 
76
        unsigned short rmagic;          /* range magic number */
 
77
        unsigned long size;             /* actual block size */
 
78
        unsigned short unused2;         /* padding to 8-byte align */
 
79
#endif
 
80
    } ovu;
 
81
#define overMagic0      ovu.magic0
 
82
#define overMagic1      ovu.magic1
 
83
#define bucketIndex     ovu.index
 
84
#define rangeCheckMagic ovu.rmagic
 
85
#define realBlockSize   ovu.size
 
86
};
 
87
 
 
88
 
 
89
#define MAGIC           0xef    /* magic # on accounting info */
 
90
#define RMAGIC          0x5555  /* magic # on range info */
 
91
 
 
92
#ifdef RCHECK
 
93
#define RSLOP           sizeof (unsigned short)
 
94
#else
 
95
#define RSLOP           0
 
96
#endif
 
97
 
 
98
#define OVERHEAD (sizeof(union overhead) + RSLOP)
 
99
 
 
100
/*
 
101
 * Macro to make it easier to refer to the end-of-block guard magic.
 
102
 */
 
103
 
 
104
#define BLOCK_END(overPtr) \
 
105
    (*(unsigned short *)((caddr_t)((overPtr) + 1) + (overPtr)->realBlockSize))
 
106
 
 
107
/*
 
108
 * nextf[i] is the pointer to the next free block of size 2^(i+3). The
 
109
 * smallest allocatable block is MINBLOCK bytes. The overhead information
 
110
 * precedes the data area returned to the user.
 
111
 */
 
112
 
 
113
#define MINBLOCK        ((sizeof(union overhead) + (ALLOCALIGN-1)) & ~(ALLOCALIGN-1))
 
114
#define NBUCKETS        (13 - (MINBLOCK >> 4))
 
115
#define MAXMALLOC       (1<<(NBUCKETS+2))
 
116
static union overhead *nextf[NBUCKETS];
 
117
 
 
118
/*
 
119
 * The following structure is used to keep track of all system memory
 
120
 * currently owned by Tcl. When finalizing, all this memory will be returned
 
121
 * to the system.
 
122
 */
 
123
 
 
124
struct block {
 
125
    struct block *nextPtr;      /* Linked list. */
 
126
    struct block *prevPtr;      /* Linked list for big blocks, ensures 8-byte
 
127
                                 * alignment for suballocated blocks. */
 
128
};
 
129
 
 
130
static struct block *blockList; /* Tracks the suballocated blocks. */
 
131
static struct block bigBlocks={ /* Big blocks aren't suballocated. */
 
132
    &bigBlocks, &bigBlocks
 
133
};
 
134
 
 
135
/*
 
136
 * The allocator is protected by a special mutex that must be explicitly
 
137
 * initialized. Futhermore, because Tcl_Alloc may be used before anything else
 
138
 * in Tcl, we make this module self-initializing after all with the allocInit
 
139
 * variable.
 
140
 */
 
141
 
 
142
#ifdef TCL_THREADS
 
143
static Tcl_Mutex *allocMutexPtr;
 
144
#endif
 
145
static int allocInit = 0;
 
146
 
 
147
#ifdef MSTATS
 
148
 
 
149
/*
 
150
 * numMallocs[i] is the difference between the number of mallocs and frees for
 
151
 * a given block size.
 
152
 */
 
153
 
 
154
static  unsigned int numMallocs[NBUCKETS+1];
 
155
#include <stdio.h>
 
156
#endif
 
157
 
 
158
#if defined(DEBUG) || defined(RCHECK)
 
159
#define ASSERT(p)       if (!(p)) Tcl_Panic(# p)
 
160
#define RANGE_ASSERT(p) if (!(p)) Tcl_Panic(# p)
 
161
#else
 
162
#define ASSERT(p)
 
163
#define RANGE_ASSERT(p)
 
164
#endif
 
165
 
 
166
/*
 
167
 * Prototypes for functions used only in this file.
 
168
 */
 
169
 
 
170
static void             MoreCore(int bucket);
 
171
 
 
172
/*
 
173
 *-------------------------------------------------------------------------
 
174
 *
 
175
 * TclInitAlloc --
 
176
 *
 
177
 *      Initialize the memory system.
 
178
 *
 
179
 * Results:
 
180
 *      None.
 
181
 *
 
182
 * Side effects:
 
183
 *      Initialize the mutex used to serialize allocations.
 
184
 *
 
185
 *-------------------------------------------------------------------------
 
186
 */
 
187
 
 
188
void
 
189
TclInitAlloc(void)
 
190
{
 
191
    if (!allocInit) {
 
192
        allocInit = 1;
 
193
#ifdef TCL_THREADS
 
194
        allocMutexPtr = Tcl_GetAllocMutex();
 
195
#endif
 
196
    }
 
197
}
 
198
 
 
199
/*
 
200
 *-------------------------------------------------------------------------
 
201
 *
 
202
 * TclFinalizeAllocSubsystem --
 
203
 *
 
204
 *      Release all resources being used by this subsystem, including
 
205
 *      aggressively freeing all memory allocated by TclpAlloc() that has not
 
206
 *      yet been released with TclpFree().
 
207
 *
 
208
 *      After this function is called, all memory allocated with TclpAlloc()
 
209
 *      should be considered unusable.
 
210
 *
 
211
 * Results:
 
212
 *      None.
 
213
 *
 
214
 * Side effects:
 
215
 *      This subsystem is self-initializing, since memory can be allocated
 
216
 *      before Tcl is formally initialized. After this call, this subsystem
 
217
 *      has been reset to its initial state and is usable again.
 
218
 *
 
219
 *-------------------------------------------------------------------------
 
220
 */
 
221
 
 
222
void
 
223
TclFinalizeAllocSubsystem(void)
 
224
{
 
225
    unsigned int i;
 
226
    struct block *blockPtr, *nextPtr;
 
227
 
 
228
    Tcl_MutexLock(allocMutexPtr);
 
229
    for (blockPtr = blockList; blockPtr != NULL; blockPtr = nextPtr) {
 
230
        nextPtr = blockPtr->nextPtr;
 
231
        TclpSysFree(blockPtr);
 
232
    }
 
233
    blockList = NULL;
 
234
 
 
235
    for (blockPtr = bigBlocks.nextPtr; blockPtr != &bigBlocks; ) {
 
236
        nextPtr = blockPtr->nextPtr;
 
237
        TclpSysFree(blockPtr);
 
238
        blockPtr = nextPtr;
 
239
    }
 
240
    bigBlocks.nextPtr = &bigBlocks;
 
241
    bigBlocks.prevPtr = &bigBlocks;
 
242
 
 
243
    for (i=0 ; i<NBUCKETS ; i++) {
 
244
        nextf[i] = NULL;
 
245
#ifdef MSTATS
 
246
        numMallocs[i] = 0;
 
247
#endif
 
248
    }
 
249
#ifdef MSTATS
 
250
    numMallocs[i] = 0;
 
251
#endif
 
252
    Tcl_MutexUnlock(allocMutexPtr);
 
253
}
 
254
 
 
255
/*
 
256
 *----------------------------------------------------------------------
 
257
 *
 
258
 * TclpAlloc --
 
259
 *
 
260
 *      Allocate more memory.
 
261
 *
 
262
 * Results:
 
263
 *      None.
 
264
 *
 
265
 * Side effects:
 
266
 *      None.
 
267
 *
 
268
 *----------------------------------------------------------------------
 
269
 */
 
270
 
 
271
char *
 
272
TclpAlloc(
 
273
    unsigned int numBytes)      /* Number of bytes to allocate. */
 
274
{
 
275
    register union overhead *overPtr;
 
276
    register long bucket;
 
277
    register unsigned amount;
 
278
    struct block *bigBlockPtr;
 
279
 
 
280
    if (!allocInit) {
 
281
        /*
 
282
         * We have to make the "self initializing" because Tcl_Alloc may be
 
283
         * used before any other part of Tcl. E.g., see main() for tclsh!
 
284
         */
 
285
 
 
286
        TclInitAlloc();
 
287
    }
 
288
    Tcl_MutexLock(allocMutexPtr);
 
289
 
 
290
    /*
 
291
     * First the simple case: we simple allocate big blocks directly.
 
292
     */
 
293
 
 
294
    if (numBytes + OVERHEAD >= MAXMALLOC) {
 
295
        bigBlockPtr = (struct block *) TclpSysAlloc((unsigned)
 
296
                (sizeof(struct block) + OVERHEAD + numBytes), 0);
 
297
        if (bigBlockPtr == NULL) {
 
298
            Tcl_MutexUnlock(allocMutexPtr);
 
299
            return NULL;
 
300
        }
 
301
        bigBlockPtr->nextPtr = bigBlocks.nextPtr;
 
302
        bigBlocks.nextPtr = bigBlockPtr;
 
303
        bigBlockPtr->prevPtr = &bigBlocks;
 
304
        bigBlockPtr->nextPtr->prevPtr = bigBlockPtr;
 
305
 
 
306
        overPtr = (union overhead *) (bigBlockPtr + 1);
 
307
        overPtr->overMagic0 = overPtr->overMagic1 = MAGIC;
 
308
        overPtr->bucketIndex = 0xff;
 
309
#ifdef MSTATS
 
310
        numMallocs[NBUCKETS]++;
 
311
#endif
 
312
 
 
313
#ifdef RCHECK
 
314
        /*
 
315
         * Record allocated size of block and bound space with magic numbers.
 
316
         */
 
317
 
 
318
        overPtr->realBlockSize = (numBytes + RSLOP - 1) & ~(RSLOP - 1);
 
319
        overPtr->rangeCheckMagic = RMAGIC;
 
320
        BLOCK_END(overPtr) = RMAGIC;
 
321
#endif
 
322
 
 
323
        Tcl_MutexUnlock(allocMutexPtr);
 
324
        return (void *)(overPtr+1);
 
325
    }
 
326
 
 
327
    /*
 
328
     * Convert amount of memory requested into closest block size stored in
 
329
     * hash buckets which satisfies request. Account for space used per block
 
330
     * for accounting.
 
331
     */
 
332
 
 
333
    amount = MINBLOCK;          /* size of first bucket */
 
334
    bucket = MINBLOCK >> 4;
 
335
 
 
336
    while (numBytes + OVERHEAD > amount) {
 
337
        amount <<= 1;
 
338
        if (amount == 0) {
 
339
            Tcl_MutexUnlock(allocMutexPtr);
 
340
            return NULL;
 
341
        }
 
342
        bucket++;
 
343
    }
 
344
    ASSERT(bucket < NBUCKETS);
 
345
 
 
346
    /*
 
347
     * If nothing in hash bucket right now, request more memory from the
 
348
     * system.
 
349
     */
 
350
 
 
351
    if ((overPtr = nextf[bucket]) == NULL) {
 
352
        MoreCore(bucket);
 
353
        if ((overPtr = nextf[bucket]) == NULL) {
 
354
            Tcl_MutexUnlock(allocMutexPtr);
 
355
            return NULL;
 
356
        }
 
357
    }
 
358
 
 
359
    /*
 
360
     * Remove from linked list
 
361
     */
 
362
 
 
363
    nextf[bucket] = overPtr->next;
 
364
    overPtr->overMagic0 = overPtr->overMagic1 = MAGIC;
 
365
    overPtr->bucketIndex = (unsigned char) bucket;
 
366
 
 
367
#ifdef MSTATS
 
368
    numMallocs[bucket]++;
 
369
#endif
 
370
 
 
371
#ifdef RCHECK
 
372
    /*
 
373
     * Record allocated size of block and bound space with magic numbers.
 
374
     */
 
375
 
 
376
    overPtr->realBlockSize = (numBytes + RSLOP - 1) & ~(RSLOP - 1);
 
377
    overPtr->rangeCheckMagic = RMAGIC;
 
378
    BLOCK_END(overPtr) = RMAGIC;
 
379
#endif
 
380
 
 
381
    Tcl_MutexUnlock(allocMutexPtr);
 
382
    return ((char *)(overPtr + 1));
 
383
}
 
384
 
 
385
/*
 
386
 *----------------------------------------------------------------------
 
387
 *
 
388
 * MoreCore --
 
389
 *
 
390
 *      Allocate more memory to the indicated bucket.
 
391
 *
 
392
 *      Assumes Mutex is already held.
 
393
 *
 
394
 * Results:
 
395
 *      None.
 
396
 *
 
397
 * Side effects:
 
398
 *      Attempts to get more memory from the system.
 
399
 *
 
400
 *----------------------------------------------------------------------
 
401
 */
 
402
 
 
403
static void
 
404
MoreCore(
 
405
    int bucket)                 /* What bucket to allocat to. */
 
406
{
 
407
    register union overhead *overPtr;
 
408
    register long size;         /* size of desired block */
 
409
    long amount;                /* amount to allocate */
 
410
    int numBlocks;              /* how many blocks we get */
 
411
    struct block *blockPtr;
 
412
 
 
413
    /*
 
414
     * sbrk_size <= 0 only for big, FLUFFY, requests (about 2^30 bytes on a
 
415
     * VAX, I think) or for a negative arg.
 
416
     */
 
417
 
 
418
    size = 1 << (bucket + 3);
 
419
    ASSERT(size > 0);
 
420
 
 
421
    amount = MAXMALLOC;
 
422
    numBlocks = amount / size;
 
423
    ASSERT(numBlocks*size == amount);
 
424
 
 
425
    blockPtr = (struct block *) TclpSysAlloc((unsigned)
 
426
            (sizeof(struct block) + amount), 1);
 
427
    /* no more room! */
 
428
    if (blockPtr == NULL) {
 
429
        return;
 
430
    }
 
431
    blockPtr->nextPtr = blockList;
 
432
    blockList = blockPtr;
 
433
 
 
434
    overPtr = (union overhead *) (blockPtr + 1);
 
435
 
 
436
    /*
 
437
     * Add new memory allocated to that on free list for this hash bucket.
 
438
     */
 
439
 
 
440
    nextf[bucket] = overPtr;
 
441
    while (--numBlocks > 0) {
 
442
        overPtr->next = (union overhead *)((caddr_t)overPtr + size);
 
443
        overPtr = (union overhead *)((caddr_t)overPtr + size);
 
444
    }
 
445
    overPtr->next = NULL;
 
446
}
 
447
 
 
448
/*
 
449
 *----------------------------------------------------------------------
 
450
 *
 
451
 * TclpFree --
 
452
 *
 
453
 *      Free memory.
 
454
 *
 
455
 * Results:
 
456
 *      None.
 
457
 *
 
458
 * Side effects:
 
459
 *      None.
 
460
 *
 
461
 *----------------------------------------------------------------------
 
462
 */
 
463
 
 
464
void
 
465
TclpFree(
 
466
    char *oldPtr)               /* Pointer to memory to free. */
 
467
{
 
468
    register long size;
 
469
    register union overhead *overPtr;
 
470
    struct block *bigBlockPtr;
 
471
 
 
472
    if (oldPtr == NULL) {
 
473
        return;
 
474
    }
 
475
 
 
476
    Tcl_MutexLock(allocMutexPtr);
 
477
    overPtr = (union overhead *)((caddr_t)oldPtr - sizeof (union overhead));
 
478
 
 
479
    ASSERT(overPtr->overMagic0 == MAGIC);       /* make sure it was in use */
 
480
    ASSERT(overPtr->overMagic1 == MAGIC);
 
481
    if (overPtr->overMagic0 != MAGIC || overPtr->overMagic1 != MAGIC) {
 
482
        Tcl_MutexUnlock(allocMutexPtr);
 
483
        return;
 
484
    }
 
485
 
 
486
    RANGE_ASSERT(overPtr->rangeCheckMagic == RMAGIC);
 
487
    RANGE_ASSERT(BLOCK_END(overPtr) == RMAGIC);
 
488
    size = overPtr->bucketIndex;
 
489
    if (size == 0xff) {
 
490
#ifdef MSTATS
 
491
        numMallocs[NBUCKETS]--;
 
492
#endif
 
493
 
 
494
        bigBlockPtr = (struct block *) overPtr - 1;
 
495
        bigBlockPtr->prevPtr->nextPtr = bigBlockPtr->nextPtr;
 
496
        bigBlockPtr->nextPtr->prevPtr = bigBlockPtr->prevPtr;
 
497
        TclpSysFree(bigBlockPtr);
 
498
 
 
499
        Tcl_MutexUnlock(allocMutexPtr);
 
500
        return;
 
501
    }
 
502
    ASSERT(size < NBUCKETS);
 
503
    overPtr->next = nextf[size];        /* also clobbers overMagic */
 
504
    nextf[size] = overPtr;
 
505
 
 
506
#ifdef MSTATS
 
507
    numMallocs[size]--;
 
508
#endif
 
509
 
 
510
    Tcl_MutexUnlock(allocMutexPtr);
 
511
}
 
512
 
 
513
/*
 
514
 *----------------------------------------------------------------------
 
515
 *
 
516
 * TclpRealloc --
 
517
 *
 
518
 *      Reallocate memory.
 
519
 *
 
520
 * Results:
 
521
 *      None.
 
522
 *
 
523
 * Side effects:
 
524
 *      None.
 
525
 *
 
526
 *----------------------------------------------------------------------
 
527
 */
 
528
 
 
529
char *
 
530
TclpRealloc(
 
531
    char *oldPtr,               /* Pointer to alloced block. */
 
532
    unsigned int numBytes)      /* New size of memory. */
 
533
{
 
534
    int i;
 
535
    union overhead *overPtr;
 
536
    struct block *bigBlockPtr;
 
537
    int expensive;
 
538
    unsigned long maxSize;
 
539
 
 
540
    if (oldPtr == NULL) {
 
541
        return TclpAlloc(numBytes);
 
542
    }
 
543
 
 
544
    Tcl_MutexLock(allocMutexPtr);
 
545
 
 
546
    overPtr = (union overhead *)((caddr_t)oldPtr - sizeof (union overhead));
 
547
 
 
548
    ASSERT(overPtr->overMagic0 == MAGIC);       /* make sure it was in use */
 
549
    ASSERT(overPtr->overMagic1 == MAGIC);
 
550
    if (overPtr->overMagic0 != MAGIC || overPtr->overMagic1 != MAGIC) {
 
551
        Tcl_MutexUnlock(allocMutexPtr);
 
552
        return NULL;
 
553
    }
 
554
 
 
555
    RANGE_ASSERT(overPtr->rangeCheckMagic == RMAGIC);
 
556
    RANGE_ASSERT(BLOCK_END(overPtr) == RMAGIC);
 
557
    i = overPtr->bucketIndex;
 
558
 
 
559
    /*
 
560
     * If the block isn't in a bin, just realloc it.
 
561
     */
 
562
 
 
563
    if (i == 0xff) {
 
564
        struct block *prevPtr, *nextPtr;
 
565
        bigBlockPtr = (struct block *) overPtr - 1;
 
566
        prevPtr = bigBlockPtr->prevPtr;
 
567
        nextPtr = bigBlockPtr->nextPtr;
 
568
        bigBlockPtr = (struct block *) TclpSysRealloc(bigBlockPtr,
 
569
                sizeof(struct block) + OVERHEAD + numBytes);
 
570
        if (bigBlockPtr == NULL) {
 
571
            Tcl_MutexUnlock(allocMutexPtr);
 
572
            return NULL;
 
573
        }
 
574
 
 
575
        if (prevPtr->nextPtr != bigBlockPtr) {
 
576
            /*
 
577
             * If the block has moved, splice the new block into the list
 
578
             * where the old block used to be.
 
579
             */
 
580
 
 
581
            prevPtr->nextPtr = bigBlockPtr;
 
582
            nextPtr->prevPtr = bigBlockPtr;
 
583
        }
 
584
 
 
585
        overPtr = (union overhead *) (bigBlockPtr + 1);
 
586
 
 
587
#ifdef MSTATS
 
588
        numMallocs[NBUCKETS]++;
 
589
#endif
 
590
 
 
591
#ifdef RCHECK
 
592
        /*
 
593
         * Record allocated size of block and update magic number bounds.
 
594
         */
 
595
 
 
596
        overPtr->realBlockSize = (numBytes + RSLOP - 1) & ~(RSLOP - 1);
 
597
        BLOCK_END(overPtr) = RMAGIC;
 
598
#endif
 
599
 
 
600
        Tcl_MutexUnlock(allocMutexPtr);
 
601
        return (char *)(overPtr+1);
 
602
    }
 
603
    maxSize = 1 << (i+3);
 
604
    expensive = 0;
 
605
    if (numBytes+OVERHEAD > maxSize) {
 
606
        expensive = 1;
 
607
    } else if (i>0 && numBytes+OVERHEAD < maxSize/2) {
 
608
        expensive = 1;
 
609
    }
 
610
 
 
611
    if (expensive) {
 
612
        void *newPtr;
 
613
 
 
614
        Tcl_MutexUnlock(allocMutexPtr);
 
615
 
 
616
        newPtr = TclpAlloc(numBytes);
 
617
        if (newPtr == NULL) {
 
618
            return NULL;
 
619
        }
 
620
        maxSize -= OVERHEAD;
 
621
        if (maxSize < numBytes) {
 
622
            numBytes = maxSize;
 
623
        }
 
624
        memcpy(newPtr, oldPtr, (size_t) numBytes);
 
625
        TclpFree(oldPtr);
 
626
        return newPtr;
 
627
    }
 
628
 
 
629
    /*
 
630
     * Ok, we don't have to copy, it fits as-is
 
631
     */
 
632
 
 
633
#ifdef RCHECK
 
634
    overPtr->realBlockSize = (numBytes + RSLOP - 1) & ~(RSLOP - 1);
 
635
    BLOCK_END(overPtr) = RMAGIC;
 
636
#endif
 
637
 
 
638
    Tcl_MutexUnlock(allocMutexPtr);
 
639
    return(oldPtr);
 
640
}
 
641
 
 
642
/*
 
643
 *----------------------------------------------------------------------
 
644
 *
 
645
 * mstats --
 
646
 *
 
647
 *      Prints two lines of numbers, one showing the length of the free list
 
648
 *      for each size category, the second showing the number of mallocs -
 
649
 *      frees for each size category.
 
650
 *
 
651
 * Results:
 
652
 *      None.
 
653
 *
 
654
 * Side effects:
 
655
 *      None.
 
656
 *
 
657
 *----------------------------------------------------------------------
 
658
 */
 
659
 
 
660
#ifdef MSTATS
 
661
void
 
662
mstats(
 
663
    char *s)                    /* Where to write info. */
 
664
{
 
665
    register int i, j;
 
666
    register union overhead *overPtr;
 
667
    int totalFree = 0, totalUsed = 0;
 
668
 
 
669
    Tcl_MutexLock(allocMutexPtr);
 
670
 
 
671
    fprintf(stderr, "Memory allocation statistics %s\nTclpFree:\t", s);
 
672
    for (i = 0; i < NBUCKETS; i++) {
 
673
        for (j=0, overPtr=nextf[i]; overPtr; overPtr=overPtr->next, j++) {
 
674
            fprintf(stderr, " %d", j);
 
675
        }
 
676
        totalFree += j * (1 << (i + 3));
 
677
    }
 
678
 
 
679
    fprintf(stderr, "\nused:\t");
 
680
    for (i = 0; i < NBUCKETS; i++) {
 
681
        fprintf(stderr, " %d", numMallocs[i]);
 
682
        totalUsed += numMallocs[i] * (1 << (i + 3));
 
683
    }
 
684
 
 
685
    fprintf(stderr, "\n\tTotal small in use: %d, total free: %d\n",
 
686
            totalUsed, totalFree);
 
687
    fprintf(stderr, "\n\tNumber of big (>%d) blocks in use: %d\n",
 
688
            MAXMALLOC, numMallocs[NBUCKETS]);
 
689
 
 
690
    Tcl_MutexUnlock(allocMutexPtr);
 
691
}
 
692
#endif
 
693
 
 
694
#else   /* !USE_TCLALLOC */
 
695
 
 
696
/*
 
697
 *----------------------------------------------------------------------
 
698
 *
 
699
 * TclpAlloc --
 
700
 *
 
701
 *      Allocate more memory.
 
702
 *
 
703
 * Results:
 
704
 *      None.
 
705
 *
 
706
 * Side effects:
 
707
 *      None.
 
708
 *
 
709
 *----------------------------------------------------------------------
 
710
 */
 
711
 
 
712
char *
 
713
TclpAlloc(
 
714
    unsigned int numBytes)      /* Number of bytes to allocate. */
 
715
{
 
716
    return (char*) malloc(numBytes);
 
717
}
 
718
 
 
719
/*
 
720
 *----------------------------------------------------------------------
 
721
 *
 
722
 * TclpFree --
 
723
 *
 
724
 *      Free memory.
 
725
 *
 
726
 * Results:
 
727
 *      None.
 
728
 *
 
729
 * Side effects:
 
730
 *      None.
 
731
 *
 
732
 *----------------------------------------------------------------------
 
733
 */
 
734
 
 
735
void
 
736
TclpFree(
 
737
    char *oldPtr)               /* Pointer to memory to free. */
 
738
{
 
739
    free(oldPtr);
 
740
    return;
 
741
}
 
742
 
 
743
/*
 
744
 *----------------------------------------------------------------------
 
745
 *
 
746
 * TclpRealloc --
 
747
 *
 
748
 *      Reallocate memory.
 
749
 *
 
750
 * Results:
 
751
 *      None.
 
752
 *
 
753
 * Side effects:
 
754
 *      None.
 
755
 *
 
756
 *----------------------------------------------------------------------
 
757
 */
 
758
 
 
759
char *
 
760
TclpRealloc(
 
761
    char *oldPtr,               /* Pointer to alloced block. */
 
762
    unsigned int numBytes)      /* New size of memory. */
 
763
{
 
764
    return (char*) realloc(oldPtr, numBytes);
 
765
}
 
766
 
 
767
#endif /* !USE_TCLALLOC */
 
768
#endif /* !TCL_THREADS */
 
769
 
 
770
/*
 
771
 * Local Variables:
 
772
 * mode: c
 
773
 * c-basic-offset: 4
 
774
 * fill-column: 78
 
775
 * End:
 
776
 */