tclAlloc.c

Go to the documentation of this file.
00001 /*
00002  * tclAlloc.c --
00003  *
00004  *      This is a very fast storage allocator. It allocates blocks of a small
00005  *      number of different sizes, and keeps free lists of each size. Blocks
00006  *      that don't exactly fit are passed up to the next larger size. Blocks
00007  *      over a certain size are directly allocated from the system.
00008  *
00009  * Copyright (c) 1983 Regents of the University of California.
00010  * Copyright (c) 1996-1997 Sun Microsystems, Inc.
00011  * Copyright (c) 1998-1999 by Scriptics Corporation.
00012  *
00013  * Portions contributed by Chris Kingsley, Jack Jansen and Ray Johnson.
00014  *
00015  * See the file "license.terms" for information on usage and redistribution of
00016  * this file, and for a DISCLAIMER OF ALL WARRANTIES.
00017  *
00018  * RCS: @(#) $Id: tclAlloc.c,v 1.27 2007/12/17 15:28:27 msofer Exp $
00019  */
00020 
00021 /*
00022  * Windows and Unix use an alternative allocator when building with threads
00023  * that has significantly reduced lock contention.
00024  */
00025 
00026 #include "tclInt.h"
00027 #if !defined(TCL_THREADS) || !defined(USE_THREAD_ALLOC)
00028 
00029 #if USE_TCLALLOC
00030 
00031 #ifdef TCL_DEBUG
00032 #   define DEBUG
00033 /* #define MSTATS */
00034 #   define RCHECK
00035 #endif
00036 
00037 /*
00038  * We should really make use of AC_CHECK_TYPE(caddr_t) here, but it can wait
00039  * until Tcl uses config.h properly.
00040  */
00041 
00042 #if defined(_MSC_VER) || defined(__MINGW32__) || defined(__BORLANDC__)
00043 typedef unsigned long caddr_t;
00044 #endif
00045 
00046 /*
00047  * The overhead on a block is at least 8 bytes. When free, this space contains
00048  * a pointer to the next free block, and the bottom two bits must be zero.
00049  * When in use, the first byte is set to MAGIC, and the second byte is the
00050  * size index. The remaining bytes are for alignment. If range checking is
00051  * enabled then a second word holds the size of the requested block, less 1,
00052  * rounded up to a multiple of sizeof(RMAGIC). The order of elements is
00053  * critical: ov.magic must overlay the low order bits of ov.next, and ov.magic
00054  * can not be a valid ov.next bit pattern.
00055  */
00056 
00057 union overhead {
00058     union overhead *next;               /* when free */
00059     unsigned char padding[TCL_ALLOCALIGN];      /* align struct to TCL_ALLOCALIGN bytes */
00060     struct {
00061         unsigned char magic0;           /* magic number */
00062         unsigned char index;            /* bucket # */
00063         unsigned char unused;           /* unused */
00064         unsigned char magic1;           /* other magic number */
00065 #ifdef RCHECK
00066         unsigned short rmagic;          /* range magic number */
00067         unsigned long size;             /* actual block size */
00068         unsigned short unused2;         /* padding to 8-byte align */
00069 #endif
00070     } ovu;
00071 #define overMagic0      ovu.magic0
00072 #define overMagic1      ovu.magic1
00073 #define bucketIndex     ovu.index
00074 #define rangeCheckMagic ovu.rmagic
00075 #define realBlockSize   ovu.size
00076 };
00077 
00078 
00079 #define MAGIC           0xef    /* magic # on accounting info */
00080 #define RMAGIC          0x5555  /* magic # on range info */
00081 
00082 #ifdef RCHECK
00083 #define RSLOP           sizeof (unsigned short)
00084 #else
00085 #define RSLOP           0
00086 #endif
00087 
00088 #define OVERHEAD (sizeof(union overhead) + RSLOP)
00089 
00090 /*
00091  * Macro to make it easier to refer to the end-of-block guard magic.
00092  */
00093 
00094 #define BLOCK_END(overPtr) \
00095     (*(unsigned short *)((caddr_t)((overPtr) + 1) + (overPtr)->realBlockSize))
00096 
00097 /*
00098  * nextf[i] is the pointer to the next free block of size 2^(i+3). The
00099  * smallest allocatable block is MINBLOCK bytes. The overhead information
00100  * precedes the data area returned to the user.
00101  */
00102 
00103 #define MINBLOCK        ((sizeof(union overhead) + (TCL_ALLOCALIGN-1)) & ~(TCL_ALLOCALIGN-1))
00104 #define NBUCKETS        (13 - (MINBLOCK >> 4))
00105 #define MAXMALLOC       (1<<(NBUCKETS+2))
00106 static union overhead *nextf[NBUCKETS];
00107 
00108 /*
00109  * The following structure is used to keep track of all system memory
00110  * currently owned by Tcl. When finalizing, all this memory will be returned
00111  * to the system.
00112  */
00113 
00114 struct block {
00115     struct block *nextPtr;      /* Linked list. */
00116     struct block *prevPtr;      /* Linked list for big blocks, ensures 8-byte
00117                                  * alignment for suballocated blocks. */
00118 };
00119 
00120 static struct block *blockList; /* Tracks the suballocated blocks. */
00121 static struct block bigBlocks={ /* Big blocks aren't suballocated. */
00122     &bigBlocks, &bigBlocks
00123 };
00124 
00125 /*
00126  * The allocator is protected by a special mutex that must be explicitly
00127  * initialized. Futhermore, because Tcl_Alloc may be used before anything else
00128  * in Tcl, we make this module self-initializing after all with the allocInit
00129  * variable.
00130  */
00131 
00132 #ifdef TCL_THREADS
00133 static Tcl_Mutex *allocMutexPtr;
00134 #endif
00135 static int allocInit = 0;
00136 
00137 #ifdef MSTATS
00138 
00139 /*
00140  * numMallocs[i] is the difference between the number of mallocs and frees for
00141  * a given block size.
00142  */
00143 
00144 static  unsigned int numMallocs[NBUCKETS+1];
00145 #include <stdio.h>
00146 #endif
00147 
00148 #if defined(DEBUG) || defined(RCHECK)
00149 #define ASSERT(p)       if (!(p)) Tcl_Panic(# p)
00150 #define RANGE_ASSERT(p) if (!(p)) Tcl_Panic(# p)
00151 #else
00152 #define ASSERT(p)
00153 #define RANGE_ASSERT(p)
00154 #endif
00155 
00156 /*
00157  * Prototypes for functions used only in this file.
00158  */
00159 
00160 static void             MoreCore(int bucket);
00161 
00162 /*
00163  *-------------------------------------------------------------------------
00164  *
00165  * TclInitAlloc --
00166  *
00167  *      Initialize the memory system.
00168  *
00169  * Results:
00170  *      None.
00171  *
00172  * Side effects:
00173  *      Initialize the mutex used to serialize allocations.
00174  *
00175  *-------------------------------------------------------------------------
00176  */
00177 
00178 void
00179 TclInitAlloc(void)
00180 {
00181     if (!allocInit) {
00182         allocInit = 1;
00183 #ifdef TCL_THREADS
00184         allocMutexPtr = Tcl_GetAllocMutex();
00185 #endif
00186     }
00187 }
00188 
00189 /*
00190  *-------------------------------------------------------------------------
00191  *
00192  * TclFinalizeAllocSubsystem --
00193  *
00194  *      Release all resources being used by this subsystem, including
00195  *      aggressively freeing all memory allocated by TclpAlloc() that has not
00196  *      yet been released with TclpFree().
00197  *
00198  *      After this function is called, all memory allocated with TclpAlloc()
00199  *      should be considered unusable.
00200  *
00201  * Results:
00202  *      None.
00203  *
00204  * Side effects:
00205  *      This subsystem is self-initializing, since memory can be allocated
00206  *      before Tcl is formally initialized. After this call, this subsystem
00207  *      has been reset to its initial state and is usable again.
00208  *
00209  *-------------------------------------------------------------------------
00210  */
00211 
00212 void
00213 TclFinalizeAllocSubsystem(void)
00214 {
00215     unsigned int i;
00216     struct block *blockPtr, *nextPtr;
00217 
00218     Tcl_MutexLock(allocMutexPtr);
00219     for (blockPtr = blockList; blockPtr != NULL; blockPtr = nextPtr) {
00220         nextPtr = blockPtr->nextPtr;
00221         TclpSysFree(blockPtr);
00222     }
00223     blockList = NULL;
00224 
00225     for (blockPtr = bigBlocks.nextPtr; blockPtr != &bigBlocks; ) {
00226         nextPtr = blockPtr->nextPtr;
00227         TclpSysFree(blockPtr);
00228         blockPtr = nextPtr;
00229     }
00230     bigBlocks.nextPtr = &bigBlocks;
00231     bigBlocks.prevPtr = &bigBlocks;
00232 
00233     for (i=0 ; i<NBUCKETS ; i++) {
00234         nextf[i] = NULL;
00235 #ifdef MSTATS
00236         numMallocs[i] = 0;
00237 #endif
00238     }
00239 #ifdef MSTATS
00240     numMallocs[i] = 0;
00241 #endif
00242     Tcl_MutexUnlock(allocMutexPtr);
00243 }
00244 
00245 /*
00246  *----------------------------------------------------------------------
00247  *
00248  * TclpAlloc --
00249  *
00250  *      Allocate more memory.
00251  *
00252  * Results:
00253  *      None.
00254  *
00255  * Side effects:
00256  *      None.
00257  *
00258  *----------------------------------------------------------------------
00259  */
00260 
00261 char *
00262 TclpAlloc(
00263     unsigned int numBytes)      /* Number of bytes to allocate. */
00264 {
00265     register union overhead *overPtr;
00266     register long bucket;
00267     register unsigned amount;
00268     struct block *bigBlockPtr;
00269 
00270     if (!allocInit) {
00271         /*
00272          * We have to make the "self initializing" because Tcl_Alloc may be
00273          * used before any other part of Tcl. E.g., see main() for tclsh!
00274          */
00275 
00276         TclInitAlloc();
00277     }
00278     Tcl_MutexLock(allocMutexPtr);
00279 
00280     /*
00281      * First the simple case: we simple allocate big blocks directly.
00282      */
00283 
00284     if (numBytes + OVERHEAD >= MAXMALLOC) {
00285         bigBlockPtr = (struct block *) TclpSysAlloc((unsigned)
00286                 (sizeof(struct block) + OVERHEAD + numBytes), 0);
00287         if (bigBlockPtr == NULL) {
00288             Tcl_MutexUnlock(allocMutexPtr);
00289             return NULL;
00290         }
00291         bigBlockPtr->nextPtr = bigBlocks.nextPtr;
00292         bigBlocks.nextPtr = bigBlockPtr;
00293         bigBlockPtr->prevPtr = &bigBlocks;
00294         bigBlockPtr->nextPtr->prevPtr = bigBlockPtr;
00295 
00296         overPtr = (union overhead *) (bigBlockPtr + 1);
00297         overPtr->overMagic0 = overPtr->overMagic1 = MAGIC;
00298         overPtr->bucketIndex = 0xff;
00299 #ifdef MSTATS
00300         numMallocs[NBUCKETS]++;
00301 #endif
00302 
00303 #ifdef RCHECK
00304         /*
00305          * Record allocated size of block and bound space with magic numbers.
00306          */
00307 
00308         overPtr->realBlockSize = (numBytes + RSLOP - 1) & ~(RSLOP - 1);
00309         overPtr->rangeCheckMagic = RMAGIC;
00310         BLOCK_END(overPtr) = RMAGIC;
00311 #endif
00312 
00313         Tcl_MutexUnlock(allocMutexPtr);
00314         return (void *)(overPtr+1);
00315     }
00316 
00317     /*
00318      * Convert amount of memory requested into closest block size stored in
00319      * hash buckets which satisfies request. Account for space used per block
00320      * for accounting.
00321      */
00322 
00323     amount = MINBLOCK;          /* size of first bucket */
00324     bucket = MINBLOCK >> 4;
00325 
00326     while (numBytes + OVERHEAD > amount) {
00327         amount <<= 1;
00328         if (amount == 0) {
00329             Tcl_MutexUnlock(allocMutexPtr);
00330             return NULL;
00331         }
00332         bucket++;
00333     }
00334     ASSERT(bucket < NBUCKETS);
00335 
00336     /*
00337      * If nothing in hash bucket right now, request more memory from the
00338      * system.
00339      */
00340 
00341     if ((overPtr = nextf[bucket]) == NULL) {
00342         MoreCore(bucket);
00343         if ((overPtr = nextf[bucket]) == NULL) {
00344             Tcl_MutexUnlock(allocMutexPtr);
00345             return NULL;
00346         }
00347     }
00348 
00349     /*
00350      * Remove from linked list
00351      */
00352 
00353     nextf[bucket] = overPtr->next;
00354     overPtr->overMagic0 = overPtr->overMagic1 = MAGIC;
00355     overPtr->bucketIndex = (unsigned char) bucket;
00356 
00357 #ifdef MSTATS
00358     numMallocs[bucket]++;
00359 #endif
00360 
00361 #ifdef RCHECK
00362     /*
00363      * Record allocated size of block and bound space with magic numbers.
00364      */
00365 
00366     overPtr->realBlockSize = (numBytes + RSLOP - 1) & ~(RSLOP - 1);
00367     overPtr->rangeCheckMagic = RMAGIC;
00368     BLOCK_END(overPtr) = RMAGIC;
00369 #endif
00370 
00371     Tcl_MutexUnlock(allocMutexPtr);
00372     return ((char *)(overPtr + 1));
00373 }
00374 
00375 /*
00376  *----------------------------------------------------------------------
00377  *
00378  * MoreCore --
00379  *
00380  *      Allocate more memory to the indicated bucket.
00381  *
00382  *      Assumes Mutex is already held.
00383  *
00384  * Results:
00385  *      None.
00386  *
00387  * Side effects:
00388  *      Attempts to get more memory from the system.
00389  *
00390  *----------------------------------------------------------------------
00391  */
00392 
00393 static void
00394 MoreCore(
00395     int bucket)                 /* What bucket to allocat to. */
00396 {
00397     register union overhead *overPtr;
00398     register long size;         /* size of desired block */
00399     long amount;                /* amount to allocate */
00400     int numBlocks;              /* how many blocks we get */
00401     struct block *blockPtr;
00402 
00403     /*
00404      * sbrk_size <= 0 only for big, FLUFFY, requests (about 2^30 bytes on a
00405      * VAX, I think) or for a negative arg.
00406      */
00407 
00408     size = 1 << (bucket + 3);
00409     ASSERT(size > 0);
00410 
00411     amount = MAXMALLOC;
00412     numBlocks = amount / size;
00413     ASSERT(numBlocks*size == amount);
00414 
00415     blockPtr = (struct block *) TclpSysAlloc((unsigned)
00416             (sizeof(struct block) + amount), 1);
00417     /* no more room! */
00418     if (blockPtr == NULL) {
00419         return;
00420     }
00421     blockPtr->nextPtr = blockList;
00422     blockList = blockPtr;
00423 
00424     overPtr = (union overhead *) (blockPtr + 1);
00425 
00426     /*
00427      * Add new memory allocated to that on free list for this hash bucket.
00428      */
00429 
00430     nextf[bucket] = overPtr;
00431     while (--numBlocks > 0) {
00432         overPtr->next = (union overhead *)((caddr_t)overPtr + size);
00433         overPtr = (union overhead *)((caddr_t)overPtr + size);
00434     }
00435     overPtr->next = NULL;
00436 }
00437 
00438 /*
00439  *----------------------------------------------------------------------
00440  *
00441  * TclpFree --
00442  *
00443  *      Free memory.
00444  *
00445  * Results:
00446  *      None.
00447  *
00448  * Side effects:
00449  *      None.
00450  *
00451  *----------------------------------------------------------------------
00452  */
00453 
00454 void
00455 TclpFree(
00456     char *oldPtr)               /* Pointer to memory to free. */
00457 {
00458     register long size;
00459     register union overhead *overPtr;
00460     struct block *bigBlockPtr;
00461 
00462     if (oldPtr == NULL) {
00463         return;
00464     }
00465 
00466     Tcl_MutexLock(allocMutexPtr);
00467     overPtr = (union overhead *)((caddr_t)oldPtr - sizeof (union overhead));
00468 
00469     ASSERT(overPtr->overMagic0 == MAGIC);       /* make sure it was in use */
00470     ASSERT(overPtr->overMagic1 == MAGIC);
00471     if (overPtr->overMagic0 != MAGIC || overPtr->overMagic1 != MAGIC) {
00472         Tcl_MutexUnlock(allocMutexPtr);
00473         return;
00474     }
00475 
00476     RANGE_ASSERT(overPtr->rangeCheckMagic == RMAGIC);
00477     RANGE_ASSERT(BLOCK_END(overPtr) == RMAGIC);
00478     size = overPtr->bucketIndex;
00479     if (size == 0xff) {
00480 #ifdef MSTATS
00481         numMallocs[NBUCKETS]--;
00482 #endif
00483 
00484         bigBlockPtr = (struct block *) overPtr - 1;
00485         bigBlockPtr->prevPtr->nextPtr = bigBlockPtr->nextPtr;
00486         bigBlockPtr->nextPtr->prevPtr = bigBlockPtr->prevPtr;
00487         TclpSysFree(bigBlockPtr);
00488 
00489         Tcl_MutexUnlock(allocMutexPtr);
00490         return;
00491     }
00492     ASSERT(size < NBUCKETS);
00493     overPtr->next = nextf[size];        /* also clobbers overMagic */
00494     nextf[size] = overPtr;
00495 
00496 #ifdef MSTATS
00497     numMallocs[size]--;
00498 #endif
00499 
00500     Tcl_MutexUnlock(allocMutexPtr);
00501 }
00502 
00503 /*
00504  *----------------------------------------------------------------------
00505  *
00506  * TclpRealloc --
00507  *
00508  *      Reallocate memory.
00509  *
00510  * Results:
00511  *      None.
00512  *
00513  * Side effects:
00514  *      None.
00515  *
00516  *----------------------------------------------------------------------
00517  */
00518 
00519 char *
00520 TclpRealloc(
00521     char *oldPtr,               /* Pointer to alloced block. */
00522     unsigned int numBytes)      /* New size of memory. */
00523 {
00524     int i;
00525     union overhead *overPtr;
00526     struct block *bigBlockPtr;
00527     int expensive;
00528     unsigned long maxSize;
00529 
00530     if (oldPtr == NULL) {
00531         return TclpAlloc(numBytes);
00532     }
00533 
00534     Tcl_MutexLock(allocMutexPtr);
00535 
00536     overPtr = (union overhead *)((caddr_t)oldPtr - sizeof (union overhead));
00537 
00538     ASSERT(overPtr->overMagic0 == MAGIC);       /* make sure it was in use */
00539     ASSERT(overPtr->overMagic1 == MAGIC);
00540     if (overPtr->overMagic0 != MAGIC || overPtr->overMagic1 != MAGIC) {
00541         Tcl_MutexUnlock(allocMutexPtr);
00542         return NULL;
00543     }
00544 
00545     RANGE_ASSERT(overPtr->rangeCheckMagic == RMAGIC);
00546     RANGE_ASSERT(BLOCK_END(overPtr) == RMAGIC);
00547     i = overPtr->bucketIndex;
00548 
00549     /*
00550      * If the block isn't in a bin, just realloc it.
00551      */
00552 
00553     if (i == 0xff) {
00554         struct block *prevPtr, *nextPtr;
00555         bigBlockPtr = (struct block *) overPtr - 1;
00556         prevPtr = bigBlockPtr->prevPtr;
00557         nextPtr = bigBlockPtr->nextPtr;
00558         bigBlockPtr = (struct block *) TclpSysRealloc(bigBlockPtr,
00559                 sizeof(struct block) + OVERHEAD + numBytes);
00560         if (bigBlockPtr == NULL) {
00561             Tcl_MutexUnlock(allocMutexPtr);
00562             return NULL;
00563         }
00564 
00565         if (prevPtr->nextPtr != bigBlockPtr) {
00566             /*
00567              * If the block has moved, splice the new block into the list
00568              * where the old block used to be.
00569              */
00570 
00571             prevPtr->nextPtr = bigBlockPtr;
00572             nextPtr->prevPtr = bigBlockPtr;
00573         }
00574 
00575         overPtr = (union overhead *) (bigBlockPtr + 1);
00576 
00577 #ifdef MSTATS
00578         numMallocs[NBUCKETS]++;
00579 #endif
00580 
00581 #ifdef RCHECK
00582         /*
00583          * Record allocated size of block and update magic number bounds.
00584          */
00585 
00586         overPtr->realBlockSize = (numBytes + RSLOP - 1) & ~(RSLOP - 1);
00587         BLOCK_END(overPtr) = RMAGIC;
00588 #endif
00589 
00590         Tcl_MutexUnlock(allocMutexPtr);
00591         return (char *)(overPtr+1);
00592     }
00593     maxSize = 1 << (i+3);
00594     expensive = 0;
00595     if (numBytes+OVERHEAD > maxSize) {
00596         expensive = 1;
00597     } else if (i>0 && numBytes+OVERHEAD < maxSize/2) {
00598         expensive = 1;
00599     }
00600 
00601     if (expensive) {
00602         void *newPtr;
00603 
00604         Tcl_MutexUnlock(allocMutexPtr);
00605 
00606         newPtr = TclpAlloc(numBytes);
00607         if (newPtr == NULL) {
00608             return NULL;
00609         }
00610         maxSize -= OVERHEAD;
00611         if (maxSize < numBytes) {
00612             numBytes = maxSize;
00613         }
00614         memcpy(newPtr, oldPtr, (size_t) numBytes);
00615         TclpFree(oldPtr);
00616         return newPtr;
00617     }
00618 
00619     /*
00620      * Ok, we don't have to copy, it fits as-is
00621      */
00622 
00623 #ifdef RCHECK
00624     overPtr->realBlockSize = (numBytes + RSLOP - 1) & ~(RSLOP - 1);
00625     BLOCK_END(overPtr) = RMAGIC;
00626 #endif
00627 
00628     Tcl_MutexUnlock(allocMutexPtr);
00629     return(oldPtr);
00630 }
00631 
00632 /*
00633  *----------------------------------------------------------------------
00634  *
00635  * mstats --
00636  *
00637  *      Prints two lines of numbers, one showing the length of the free list
00638  *      for each size category, the second showing the number of mallocs -
00639  *      frees for each size category.
00640  *
00641  * Results:
00642  *      None.
00643  *
00644  * Side effects:
00645  *      None.
00646  *
00647  *----------------------------------------------------------------------
00648  */
00649 
00650 #ifdef MSTATS
00651 void
00652 mstats(
00653     char *s)                    /* Where to write info. */
00654 {
00655     register int i, j;
00656     register union overhead *overPtr;
00657     int totalFree = 0, totalUsed = 0;
00658 
00659     Tcl_MutexLock(allocMutexPtr);
00660 
00661     fprintf(stderr, "Memory allocation statistics %s\nTclpFree:\t", s);
00662     for (i = 0; i < NBUCKETS; i++) {
00663         for (j=0, overPtr=nextf[i]; overPtr; overPtr=overPtr->next, j++) {
00664             fprintf(stderr, " %d", j);
00665         }
00666         totalFree += j * (1 << (i + 3));
00667     }
00668 
00669     fprintf(stderr, "\nused:\t");
00670     for (i = 0; i < NBUCKETS; i++) {
00671         fprintf(stderr, " %d", numMallocs[i]);
00672         totalUsed += numMallocs[i] * (1 << (i + 3));
00673     }
00674 
00675     fprintf(stderr, "\n\tTotal small in use: %d, total free: %d\n",
00676             totalUsed, totalFree);
00677     fprintf(stderr, "\n\tNumber of big (>%d) blocks in use: %d\n",
00678             MAXMALLOC, numMallocs[NBUCKETS]);
00679 
00680     Tcl_MutexUnlock(allocMutexPtr);
00681 }
00682 #endif
00683 
00684 #else   /* !USE_TCLALLOC */
00685 
00686 /*
00687  *----------------------------------------------------------------------
00688  *
00689  * TclpAlloc --
00690  *
00691  *      Allocate more memory.
00692  *
00693  * Results:
00694  *      None.
00695  *
00696  * Side effects:
00697  *      None.
00698  *
00699  *----------------------------------------------------------------------
00700  */
00701 
00702 char *
00703 TclpAlloc(
00704     unsigned int numBytes)      /* Number of bytes to allocate. */
00705 {
00706     return (char*) malloc(numBytes);
00707 }
00708 
00709 /*
00710  *----------------------------------------------------------------------
00711  *
00712  * TclpFree --
00713  *
00714  *      Free memory.
00715  *
00716  * Results:
00717  *      None.
00718  *
00719  * Side effects:
00720  *      None.
00721  *
00722  *----------------------------------------------------------------------
00723  */
00724 
00725 void
00726 TclpFree(
00727     char *oldPtr)               /* Pointer to memory to free. */
00728 {
00729     free(oldPtr);
00730     return;
00731 }
00732 
00733 /*
00734  *----------------------------------------------------------------------
00735  *
00736  * TclpRealloc --
00737  *
00738  *      Reallocate memory.
00739  *
00740  * Results:
00741  *      None.
00742  *
00743  * Side effects:
00744  *      None.
00745  *
00746  *----------------------------------------------------------------------
00747  */
00748 
00749 char *
00750 TclpRealloc(
00751     char *oldPtr,               /* Pointer to alloced block. */
00752     unsigned int numBytes)      /* New size of memory. */
00753 {
00754     return (char*) realloc(oldPtr, numBytes);
00755 }
00756 
00757 #endif /* !USE_TCLALLOC */
00758 #endif /* !TCL_THREADS */
00759 
00760 /*
00761  * Local Variables:
00762  * mode: c
00763  * c-basic-offset: 4
00764  * fill-column: 78
00765  * End:
00766  */



Generated on Wed Mar 12 12:18:11 2008 by  doxygen 1.5.1