tclAlloc.cGo 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 1.5.1 |