mirror of https://github.com/python/cpython.git
_PyMalloc_Free(): As was already done for _PyMalloc_Malloc, rearranged
the code so that the most frequent cases come first. Added comments. Found a hidden assumption that a pool contains room for at least two blocks, and added an assert to catch a violation if it ever happens in a place where that matters. Gave the normal "I allocated this block" case a longer basic block to work with before it has to do its first branch (via breaking apart an embedded assignment in an "if", and hoisting common code out of both branches).
This commit is contained in:
parent
1e16db6d3b
commit
2c95c99a64
|
@ -667,6 +667,7 @@ void
|
||||||
_PyMalloc_Free(void *p)
|
_PyMalloc_Free(void *p)
|
||||||
{
|
{
|
||||||
poolp pool;
|
poolp pool;
|
||||||
|
block *lastfree;
|
||||||
poolp next, prev;
|
poolp next, prev;
|
||||||
uint size;
|
uint size;
|
||||||
|
|
||||||
|
@ -679,23 +680,57 @@ _PyMalloc_Free(void *p)
|
||||||
LOCK();
|
LOCK();
|
||||||
INCMINE;
|
INCMINE;
|
||||||
/*
|
/*
|
||||||
* At this point, the pool is not empty
|
* Link p to the start of the pool's freeblock list. Since
|
||||||
*/
|
* the pool had at least the p block outstanding, the pool
|
||||||
if ((*(block **)p = pool->freeblock) == NULL) {
|
* wasn't empty (so it's already in a usedpools[] list, or
|
||||||
/*
|
* was full and is in no list -- it's not in the freeblocks
|
||||||
* Pool was full
|
* list in any case).
|
||||||
*/
|
*/
|
||||||
|
*(block **)p = lastfree = pool->freeblock;
|
||||||
pool->freeblock = (block *)p;
|
pool->freeblock = (block *)p;
|
||||||
--pool->ref.count;
|
if (lastfree) {
|
||||||
/*
|
/*
|
||||||
* Frontlink to used pools
|
* freeblock wasn't NULL, so the pool wasn't full,
|
||||||
|
* and the pool is in a usedpools[] list.
|
||||||
|
*/
|
||||||
|
assert(pool->ref.count < pool.capacity);
|
||||||
|
if (--pool->ref.count != 0) {
|
||||||
|
/* pool isn't empty: leave it in usedpools */
|
||||||
|
UNLOCK();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Pool is now empty: unlink from usedpools, and
|
||||||
|
* link to the front of usedpools. This ensures that
|
||||||
|
* previously freed pools will be allocated later
|
||||||
|
* (being not referenced, they are perhaps paged out).
|
||||||
|
*/
|
||||||
|
next = pool->nextpool;
|
||||||
|
prev = pool->prevpool;
|
||||||
|
next->prevpool = prev;
|
||||||
|
prev->nextpool = next;
|
||||||
|
/* Link to freepools. This is a singly-linked list,
|
||||||
|
* and pool->prevpool isn't used there.
|
||||||
|
*/
|
||||||
|
pool->nextpool = freepools;
|
||||||
|
freepools = pool;
|
||||||
|
UNLOCK();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Pool was full, so doesn't currently live in any list:
|
||||||
|
* link it to the front of the appropriate usedpools[] list.
|
||||||
* This mimics LRU pool usage for new allocations and
|
* This mimics LRU pool usage for new allocations and
|
||||||
* targets optimal filling when several pools contain
|
* targets optimal filling when several pools contain
|
||||||
* blocks of the same size class.
|
* blocks of the same size class.
|
||||||
*/
|
*/
|
||||||
|
assert(pool->ref.count == pool->capacity); /* else not full */
|
||||||
|
--pool->ref.count;
|
||||||
|
assert(pool->ref.count > 0); /* else the pool is empty */
|
||||||
size = pool->szidx;
|
size = pool->szidx;
|
||||||
next = usedpools[size + size];
|
next = usedpools[size + size];
|
||||||
prev = next->prevpool;
|
prev = next->prevpool;
|
||||||
|
/* insert pool before next: prev <-> pool <-> next */
|
||||||
pool->nextpool = next;
|
pool->nextpool = next;
|
||||||
pool->prevpool = prev;
|
pool->prevpool = prev;
|
||||||
next->prevpool = pool;
|
next->prevpool = pool;
|
||||||
|
@ -703,33 +738,8 @@ _PyMalloc_Free(void *p)
|
||||||
UNLOCK();
|
UNLOCK();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
* Pool was not full
|
|
||||||
*/
|
|
||||||
pool->freeblock = (block *)p;
|
|
||||||
if (--pool->ref.count != 0) {
|
|
||||||
UNLOCK();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Pool is now empty, unlink from used pools
|
|
||||||
*/
|
|
||||||
next = pool->nextpool;
|
|
||||||
prev = pool->prevpool;
|
|
||||||
next->prevpool = prev;
|
|
||||||
prev->nextpool = next;
|
|
||||||
/*
|
|
||||||
* Frontlink to free pools
|
|
||||||
* This ensures that previously freed pools will be allocated
|
|
||||||
* later (being not referenced, they are perhaps paged out).
|
|
||||||
*/
|
|
||||||
pool->nextpool = freepools;
|
|
||||||
freepools = pool;
|
|
||||||
UNLOCK();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We did not allocate this address. */
|
/* We didn't allocate this address. */
|
||||||
INCTHEIRS;
|
INCTHEIRS;
|
||||||
PyMem_FREE(p);
|
PyMem_FREE(p);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue