diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c index 6b7b05e7ecb..8ec5dfccb88 100644 --- a/Objects/obmalloc.c +++ b/Objects/obmalloc.c @@ -261,8 +261,65 @@ SIMPLELOCK_DECL(_malloc_lock); #define LOCK_FINI() SIMPLELOCK_FINI(_malloc_lock) /* - * Pool table -- doubly linked lists of partially used pools - */ + * Pool table -- headed, circular, doubly-linked lists of partially used pools. + +This is involved. For an index i, usedpools[i+i] is the header for a list of +all partially used pools holding small blocks with "size class idx" i. So +usedpools[0] corresponds to blocks of size 8, usedpools[2] to blocks of size +16, and so on: index 2*i <-> blocks of size (i+1)<nextpool and p->prevpool are both p (meaning that the headed +circular list is empty). + +It's unclear why the usedpools setup is so convoluted. It could be to +minimize the amount of cache required to hold this heavily-referenced table +(which only *needs* the two interpool pointer members of a pool_header). OTOH, +referencing code has to remember to "double the index" and doing so isn't +free, usedpools[0] isn't a strictly legal pointer, and we're crucially relying +on that C doesn't insert any padding anywhere in a pool_header at or before +the prevpool member. +**************************************************************************** */ + #define PTA(x) ((poolp )((uchar *)&(usedpools[2*(x)]) - 2*sizeof(block *))) #define PT(x) PTA(x), PTA(x) @@ -619,8 +676,8 @@ _PyMalloc_Free(void *p) pool = POOL_ADDR(p); if (ADDRESS_IN_RANGE(p, pool->arenaindex)) { /* We allocated this address. */ - INCMINE; LOCK(); + INCMINE; /* * At this point, the pool is not empty */