cinap_lenrekadd hg and python4bb9e2215 years agoHistory
1745 lines · 56.8 KB · C
RawDownload
#endif /* Allocate a new arena.  If we run out of memory, return NULL.  Else * allocate a new arena, and return the address of an arena_object * describing the new arena.  It's expected that the caller will set * `usable_arenas` to the return value. */static struct arena_object*new_arena(void){	struct arena_object* arenaobj;	uint excess;	/* number of bytes above pool alignment */ #ifdef PYMALLOC_DEBUG	if (Py_GETENV("PYTHONMALLOCSTATS"))		_PyObject_DebugMallocStats();#endif	if (unused_arena_objects == NULL) {		uint i;		uint numarenas;		size_t nbytes; 		/* Double the number of arena objects on each allocation.		 * Note that it's possible for `numarenas` to overflow.		 */		numarenas = maxarenas ? maxarenas << 1 : INITIAL_ARENA_OBJECTS;		if (numarenas <= maxarenas)			return NULL;	/* overflow */		nbytes = numarenas * sizeof(*arenas);		if (nbytes / sizeof(*arenas) != numarenas)			return NULL;	/* overflow */		arenaobj = (struct arena_object *)realloc(arenas, nbytes);		if (arenaobj == NULL)			return NULL;		arenas = arenaobj; 		/* We might need to fix pointers that were copied.  However,		 * new_arena only gets called when all the pages in the		 * previous arenas are full.  Thus, there are *no* pointers		 * into the old array. Thus, we don't have to worry about		 * invalid pointers.  Just to be sure, some asserts:		 */		assert(usable_arenas == NULL);		assert(unused_arena_objects == NULL); 		/* Put the new arenas on the unused_arena_objects list. */		for (i = maxarenas; i < numarenas; ++i) {			arenas[i].address = 0;	/* mark as unassociated */			arenas[i].nextarena = i < numarenas - 1 ?					       &arenas[i+1] : NULL;		} 		/* Update globals. */		unused_arena_objects = &arenas[maxarenas];		maxarenas = numarenas;	} 	/* Take the next available arena object off the head of the list. */	assert(unused_arena_objects != NULL);	arenaobj = unused_arena_objects;	unused_arena_objects = arenaobj->nextarena;	assert(arenaobj->address == 0);	arenaobj->address = (uptr)malloc(ARENA_SIZE);	if (arenaobj->address == 0) {		/* The allocation failed: return NULL after putting the		 * arenaobj back.		 */		arenaobj->nextarena = unused_arena_objects;		unused_arena_objects = arenaobj;		return NULL;	} 	++narenas_currently_allocated;#ifdef PYMALLOC_DEBUG	++ntimes_arena_allocated;	if (narenas_currently_allocated > narenas_highwater)		narenas_highwater = narenas_currently_allocated;#endif	arenaobj->freepools = NULL;	/* pool_address <- first pool-aligned address in the arena	   nfreepools <- number of whole pools that fit after alignment */	arenaobj->pool_address = (block*)arenaobj->address;	arenaobj->nfreepools = ARENA_SIZE / POOL_SIZE;	assert(POOL_SIZE * arenaobj->nfreepools == ARENA_SIZE);	excess = (uint)(arenaobj->address & POOL_SIZE_MASK);	if (excess != 0) {		--arenaobj->nfreepools;		arenaobj->pool_address += POOL_SIZE - excess;	}	arenaobj->ntotalpools = arenaobj->nfreepools; 	return arenaobj;} /*Py_ADDRESS_IN_RANGE(P, POOL) Return true if and only if P is an address that was allocated by pymalloc.POOL must be the pool address associated with P, i.e., POOL = POOL_ADDR(P)(the caller is asked to compute this because the macro expands POOL more thanonce, and for efficiency it's best for the caller to assign POOL_ADDR(P) to avariable and pass the latter to the macro; because Py_ADDRESS_IN_RANGE iscalled on every alloc/realloc/free, micro-efficiency is important here). Tricky:  Let B be the arena base address associated with the pool, B =arenas[(POOL)->arenaindex].address.  Then P belongs to the arena if and only if 	B <= P < B + ARENA_SIZE Subtracting B throughout, this is true iff 	0 <= P-B < ARENA_SIZE By using unsigned arithmetic, the "0 <=" half of the test can be skipped. Obscure:  A PyMem "free memory" function can call the pymalloc free or reallocbefore the first arena has been allocated.  `arenas` is still NULL in thatcase.  We're relying on that maxarenas is also 0 in that case, so that(POOL)->arenaindex < maxarenas  must be false, saving us from trying to indexinto a NULL arenas. Details:  given P and POOL, the arena_object corresponding to P is AO =arenas[(POOL)->arenaindex].  Suppose obmalloc controls P.  Then (barring wildstores, etc), POOL is the correct address of P's pool, AO.address is thecorrect base address of the pool's arena, and P must be within ARENA_SIZE ofAO.address.  In addition, AO.address is not 0 (no arena can start at address 0(NULL)).  Therefore Py_ADDRESS_IN_RANGE correctly reports that obmalloccontrols P. Now suppose obmalloc does not control P (e.g., P was obtained via a directcall to the system malloc() or realloc()).  (POOL)->arenaindex may be anythingin this case -- it may even be uninitialized trash.  If the trash arenaindexis >= maxarenas, the macro correctly concludes at once that obmalloc doesn'tcontrol P. Else arenaindex is < maxarena, and AO is read up.  If AO corresponds to anallocated arena, obmalloc controls all the memory in slice AO.address :AO.address+ARENA_SIZE.  By case assumption, P is not controlled by obmalloc,so P doesn't lie in that slice, so the macro correctly reports that P is notcontrolled by obmalloc. Finally, if P is not controlled by obmalloc and AO corresponds to an unusedarena_object (one not currently associated with an allocated arena),AO.address is 0, and the second test in the macro reduces to: 	P < ARENA_SIZE If P >= ARENA_SIZE (extremely likely), the macro again correctly concludesthat P is not controlled by obmalloc.  However, if P < ARENA_SIZE, this partof the test still passes, and the third clause (AO.address != 0) is necessaryto get the correct result:  AO.address is 0 in this case, so the macrocorrectly reports that P is not controlled by obmalloc (despite that P lies inslice AO.address : AO.address + ARENA_SIZE). Note:  The third (AO.address != 0) clause was added in Python 2.5.  Before2.5, arenas were never free()'ed, and an arenaindex < maxarena alwayscorresponded to a currently-allocated arena, so the "P is not controlled byobmalloc, AO corresponds to an unused arena_object, and P < ARENA_SIZE" casewas impossible. Note that the logic is excruciating, and reading up possibly uninitializedmemory when P is not controlled by obmalloc (to get at (POOL)->arenaindex)creates problems for some memory debuggers.  The overwhelming advantage isthat this test determines whether an arbitrary address is controlled byobmalloc in a small constant time, independent of the number of arenasobmalloc controls.  Since this test is needed at every entry point, it'sextremely desirable that it be this fast.*/#define Py_ADDRESS_IN_RANGE(P, POOL)			\	((POOL)->arenaindex < maxarenas &&		\	 (uptr)(P) - arenas[(POOL)->arenaindex].address < (uptr)ARENA_SIZE && \	 arenas[(POOL)->arenaindex].address != 0)  /* This is only useful when running memory debuggers such as * Purify or Valgrind.  Uncomment to use. *#define Py_USING_MEMORY_DEBUGGER */ #ifdef Py_USING_MEMORY_DEBUGGER /* Py_ADDRESS_IN_RANGE may access uninitialized memory by design * This leads to thousands of spurious warnings when using * Purify or Valgrind.  By making a function, we can easily * suppress the uninitialized memory reads in this one function. * So we won't ignore real errors elsewhere. * * Disable the macro and use a function. */ #undef Py_ADDRESS_IN_RANGE #if defined(__GNUC__) && ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) || \			  (__GNUC__ >= 4))#define Py_NO_INLINE __attribute__((__noinline__))#else#define Py_NO_INLINE#endif /* Don't make static, to try to ensure this isn't inlined. */int Py_ADDRESS_IN_RANGE(void *P, poolp pool) Py_NO_INLINE;#undef Py_NO_INLINE#endif /*==========================================================================*/ /* 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, * which minimizes the number of jumps in the most common cases, * improves branching prediction and instruction scheduling (small * block allocations typically result in a couple of instructions). * Unless the optimizer reorders everything, being too smart... */ #undef PyObject_Mallocvoid *PyObject_Malloc(size_t nbytes){	block *bp;	poolp pool;	poolp next;	uint size; 	/*	 * This implicitly redirects malloc(0).	 */	if ((nbytes - 1) < SMALL_REQUEST_THRESHOLD) {		LOCK();		/*		 * Most frequent paths first		 */		size = (uint)(nbytes - 1) >> ALIGNMENT_SHIFT;		pool = usedpools[size + size];		if (pool != pool->nextpool) {			/*			 * There is a used pool for this size class.			 * Pick up the head block of its free list.			 */			++pool->ref.count;			bp = pool->freeblock;			assert(bp != NULL);			if ((pool->freeblock = *(block **)bp) != NULL) {				UNLOCK();				return (void *)bp;			}			/*			 * Reached the end of the free list, try to extend it.			 */			if (pool->nextoffset <= pool->maxnextoffset) {				/* There is room for another block. */				pool->freeblock = (block*)pool +						  pool->nextoffset;				pool->nextoffset += INDEX2SIZE(size);				*(block **)(pool->freeblock) = NULL;				UNLOCK();				return (void *)bp;			}			/* Pool is full, unlink from used pools. */			next = pool->nextpool;			pool = pool->prevpool;			next->prevpool = pool;			pool->nextpool = next;			UNLOCK();			return (void *)bp;		} 		/* There isn't a pool of the right size class immediately		 * available:  use a free pool.		 */		if (usable_arenas == NULL) {			/* No arena has a free pool:  allocate a new arena. */#ifdef WITH_MEMORY_LIMITS			if (narenas_currently_allocated >= MAX_ARENAS) {				UNLOCK();				goto redirect;			}#endif			usable_arenas = new_arena();			if (usable_arenas == NULL) {				UNLOCK();				goto redirect;			}			usable_arenas->nextarena =				usable_arenas->prevarena = NULL;		}		assert(usable_arenas->address != 0); 		/* Try to get a cached free pool. */		pool = usable_arenas->freepools;		if (pool != NULL) {			/* Unlink from cached pools. */			usable_arenas->freepools = pool->nextpool; 			/* This arena already had the smallest nfreepools			 * value, so decreasing nfreepools doesn't change			 * that, and we don't need to rearrange the			 * usable_arenas list.  However, if the arena has			 * become wholly allocated, we need to remove its			 * arena_object from usable_arenas.			 */			--usable_arenas->nfreepools;			if (usable_arenas->nfreepools == 0) {				/* Wholly allocated:  remove. */				assert(usable_arenas->freepools == NULL);				assert(usable_arenas->nextarena == NULL ||				       usable_arenas->nextarena->prevarena ==					   usable_arenas); 				usable_arenas = usable_arenas->nextarena;				if (usable_arenas != NULL) {					usable_arenas->prevarena = NULL;					assert(usable_arenas->address != 0);				}			}			else {				/* nfreepools > 0:  it must be that freepools				 * isn't NULL, or that we haven't yet carved				 * off all the arena's pools for the first				 * time.				 */				assert(usable_arenas->freepools != NULL ||				       usable_arenas->pool_address <=				           (block*)usable_arenas->address +				               ARENA_SIZE - POOL_SIZE);			}		init_pool:			/* Frontlink to used pools. */			next = usedpools[size + size]; /* == prev */			pool->nextpool = next;			pool->prevpool = next;			next->nextpool = pool;			next->prevpool = pool;			pool->ref.count = 1;			if (pool->szidx == size) {				/* Luckily, this pool last contained blocks				 * of the same size class, so its header				 * and free list are already initialized.				 */				bp = pool->freeblock;				pool->freeblock = *(block **)bp;				UNLOCK();				return (void *)bp;			}			/*			 * Initialize the pool header, set up the free list to			 * contain just the second block, and return the first			 * block.			 */			pool->szidx = size;			size = INDEX2SIZE(size);			bp = (block *)pool + POOL_OVERHEAD;			pool->nextoffset = POOL_OVERHEAD + (size << 1);			pool->maxnextoffset = POOL_SIZE - size;			pool->freeblock = bp + size;			*(block **)(pool->freeblock) = NULL;			UNLOCK();			return (void *)bp;		} 		/* Carve off a new pool. */		assert(usable_arenas->nfreepools > 0);		assert(usable_arenas->freepools == NULL);		pool = (poolp)usable_arenas->pool_address;		assert((block*)pool <= (block*)usable_arenas->address +		                       ARENA_SIZE - POOL_SIZE);		pool->arenaindex = usable_arenas - arenas;		assert(&arenas[pool->arenaindex] == usable_arenas);		pool->szidx = DUMMY_SIZE_IDX;		usable_arenas->pool_address += POOL_SIZE;		--usable_arenas->nfreepools; 		if (usable_arenas->nfreepools == 0) {			assert(usable_arenas->nextarena == NULL ||			       usable_arenas->nextarena->prevarena ==			       	   usable_arenas);			/* Unlink the arena:  it is completely allocated. */			usable_arenas = usable_arenas->nextarena;			if (usable_arenas != NULL) {				usable_arenas->prevarena = NULL;				assert(usable_arenas->address != 0);			}		} 		goto init_pool;	}         /* The small block allocator ends here. */ redirect:	/* Redirect the original request to the underlying (libc) allocator.	 * We jump here on bigger requests, on error in the code above (as a	 * last chance to serve the request) or when the max memory limit	 * has been reached.	 */	if (nbytes == 0)		nbytes = 1;	return (void *)malloc(nbytes);} /* free */ #undef PyObject_FreevoidPyObject_Free(void *p){	poolp pool;	block *lastfree;	poolp next, prev;	uint size; 	if (p == NULL)	/* free(NULL) has no effect */		return; 	pool = POOL_ADDR(p);	if (Py_ADDRESS_IN_RANGE(p, pool)) {		/* We allocated this address. */		LOCK();		/* Link p to the start of the pool's freeblock list.  Since		 * the pool had at least the p block outstanding, the pool		 * 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		 * list in any case).		 */		assert(pool->ref.count > 0);	/* else it was empty */		*(block **)p = lastfree = pool->freeblock;		pool->freeblock = (block *)p;		if (lastfree) {			struct arena_object* ao;			uint nf;  /* ao->nfreepools */ 			/* freeblock wasn't NULL, so the pool wasn't full,			 * and the pool is in a usedpools[] list.			 */			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 freepools.  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 the pool to freepools.  This is a singly-linked			 * list, and pool->prevpool isn't used there.			 */			ao = &arenas[pool->arenaindex];			pool->nextpool = ao->freepools;			ao->freepools = pool;			nf = ++ao->nfreepools; 			/* All the rest is arena management.  We just freed			 * a pool, and there are 4 cases for arena mgmt:			 * 1. If all the pools are free, return the arena to			 *    the system free().			 * 2. If this is the only free pool in the arena,			 *    add the arena back to the `usable_arenas` list.			 * 3. If the "next" arena has a smaller count of free			 *    pools, we have to "slide this arena right" to			 *    restore that usable_arenas is sorted in order of			 *    nfreepools.			 * 4. Else there's nothing more to do.			 */			if (nf == ao->ntotalpools) {				/* Case 1.  First unlink ao from usable_arenas.				 */				assert(ao->prevarena == NULL ||				       ao->prevarena->address != 0);				assert(ao ->nextarena == NULL ||				       ao->nextarena->address != 0); 				/* Fix the pointer in the prevarena, or the				 * usable_arenas pointer.				 */				if (ao->prevarena == NULL) {					usable_arenas = ao->nextarena;					assert(usable_arenas == NULL ||					       usable_arenas->address != 0);				}				else {					assert(ao->prevarena->nextarena == ao);					ao->prevarena->nextarena =						ao->nextarena;				}				/* Fix the pointer in the nextarena. */				if (ao->nextarena != NULL) {					assert(ao->nextarena->prevarena == ao);					ao->nextarena->prevarena =						ao->prevarena;				}

Lines 501–1000 of 1745. Previous lines