diff options
author | Tim Peters <tim.peters@gmail.com> | 2002-04-04 04:44:32 (GMT) |
---|---|---|
committer | Tim Peters <tim.peters@gmail.com> | 2002-04-04 04:44:32 (GMT) |
commit | 84c1b974675b9252e1f5764a399ff9455fbf73e0 (patch) | |
tree | 2a44ade5afd5e8535d582fe750520272ed93706c /Objects/obmalloc.c | |
parent | 243ea7166913a6cf9852373b2a3d965d6587477b (diff) | |
download | cpython-84c1b974675b9252e1f5764a399ff9455fbf73e0.zip cpython-84c1b974675b9252e1f5764a399ff9455fbf73e0.tar.gz cpython-84c1b974675b9252e1f5764a399ff9455fbf73e0.tar.bz2 |
_PyMalloc_{Malloc, Realloc}: Strive to meet the doc's promises about
what these do given a 0 size argument. This is so that when pymalloc
is enabled, we don't need to wrap pymalloc calls in goofy little
routines special-casing 0. Note that it's virtually impossible to meet
the doc's promise that malloc(0) will never return NULL; this makes a
best effort, but not an insane effort. The code does promise that
realloc(not-NULL, 0) will never return NULL (malloc(0) is much harder).
_PyMalloc_Realloc: Changed to take over all requests for 0 bytes, and
rearranged to be a little quicker in expected cases.
All over the place: when resorting to the platform allocator, call
free/malloc/realloc directly, without indirecting thru macros. This
should avoid needing a nightmarish pile of #ifdef-ery if PYMALLOC_DEBUG
is changed so that pymalloc takes over all Py(Mem, Object} memory
operations (which would add useful debugging info to PyMem_xyz
allocations too).
Diffstat (limited to 'Objects/obmalloc.c')
-rw-r--r-- | Objects/obmalloc.c | 86 |
1 files changed, 44 insertions, 42 deletions
diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c index 9353ba8..93c74ab 100644 --- a/Objects/obmalloc.c +++ b/Objects/obmalloc.c @@ -442,7 +442,7 @@ static block * new_arena(void) { uint excess; /* number of bytes above pool alignment */ - block *bp = (block *)PyMem_MALLOC(ARENA_SIZE); + block *bp = (block *)malloc(ARENA_SIZE); if (bp == NULL) return NULL; @@ -460,7 +460,7 @@ new_arena(void) /* Make room for a new entry in the arenas vector. */ if (arenas == NULL) { assert(narenas == 0 && maxarenas == 0); - arenas = (uptr *)PyMem_MALLOC(16 * sizeof(*arenas)); + arenas = (uptr *)malloc(16 * sizeof(*arenas)); if (arenas == NULL) goto error; maxarenas = 16; @@ -509,7 +509,7 @@ new_arena(void) uint newmax = maxarenas << 1; if (newmax <= maxarenas) /* overflow */ goto error; - p = (uptr *)PyMem_MALLOC(newmax * sizeof(*arenas)); + p = (uptr *)malloc(newmax * sizeof(*arenas)); if (p == NULL) goto error; memcpy(p, arenas, narenas * sizeof(*arenas)); @@ -525,7 +525,7 @@ new_arena(void) return bp; error: - PyMem_FREE(bp); + free(bp); nfreepools = 0; return NULL; } @@ -552,7 +552,9 @@ error: /*==========================================================================*/ -/* malloc */ +/* malloc. Note that nbytes==0 tries to return a non-NULL pointer, distinct + * from all other currently live pointers. This may not be possible. + */ /* * The basic blocks are ordered by decreasing execution frequency, @@ -571,7 +573,7 @@ _PyMalloc_Malloc(size_t nbytes) uint size; /* - * This implicitly redirects malloc(0) + * This implicitly redirects malloc(0). */ if ((nbytes - 1) < SMALL_REQUEST_THRESHOLD) { LOCK(); @@ -698,7 +700,7 @@ redirect: * last chance to serve the request) or when the max memory limit * has been reached. */ - return (void *)PyMem_MALLOC(nbytes); + return (void *)malloc(nbytes ? nbytes : 1); } /* free */ @@ -782,63 +784,63 @@ _PyMalloc_Free(void *p) /* We didn't allocate this address. */ INCTHEIRS; - PyMem_FREE(p); + free(p); } -/* realloc */ +/* realloc. If p is NULL, this acts like malloc(nbytes). Else if nbytes==0, + * then as the Python docs promise, we do not treat this like free(p), and + * return a non-NULL result. + */ void * _PyMalloc_Realloc(void *p, size_t nbytes) { - block *bp; + void *bp; poolp pool; uint size; if (p == NULL) return _PyMalloc_Malloc(nbytes); - /* realloc(p, 0) on big blocks is redirected. */ pool = POOL_ADDR(p); if (ADDRESS_IN_RANGE(p, pool->arenaindex)) { /* We're in charge of this block */ INCMINE; size = (pool->szidx + 1) << ALIGNMENT_SHIFT; /* block size */ - if (size >= nbytes) { - /* Don't bother if a smaller size was requested - except for realloc(p, 0) == free(p), ret NULL */ - /* XXX but Python guarantees that *its* flavor of - resize(p, 0) will not do a free or return NULL */ - if (nbytes == 0) { - _PyMalloc_Free(p); - bp = NULL; - } - else - bp = (block *)p; + if (size >= nbytes) + /* Don't bother if a smaller size was requested. */ + return p; + /* We need more memory. */ + assert(nbytes != 0); + bp = (block *)_PyMalloc_Malloc(nbytes); + if (bp != NULL) { + memcpy(bp, p, size); + _PyMalloc_Free(p); } - else { - bp = (block *)_PyMalloc_Malloc(nbytes); - if (bp != NULL) { - memcpy(bp, p, size); - _PyMalloc_Free(p); - } + return bp; + } + /* We're not managing this block. */ + INCTHEIRS; + if (nbytes <= SMALL_REQUEST_THRESHOLD) { + /* Take over this block. */ + bp = _PyMalloc_Malloc(nbytes ? nbytes : 1); + if (bp != NULL) { + memcpy(bp, p, nbytes); + free(p); + } + else if (nbytes == 0) { + /* Meet the doc's promise that nbytes==0 will + * never return a NULL pointer when p isn't NULL. + */ + bp = p; } + } else { - /* We haven't allocated this block */ - INCTHEIRS; - if (nbytes <= SMALL_REQUEST_THRESHOLD && nbytes) { - /* small request */ - size = nbytes; - bp = (block *)_PyMalloc_Malloc(nbytes); - if (bp != NULL) { - memcpy(bp, p, size); - _PyMalloc_Free(p); - } - } - else - bp = (block *)PyMem_REALLOC(p, nbytes); + assert(nbytes != 0); + bp = realloc(p, nbytes); } - return (void *)bp; + return bp; } #else /* ! WITH_PYMALLOC */ |