⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 obmalloc.c

📁 python s60 1.4.5版本的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
				return;
			}
			if (nf == 1) {
				/* Case 2.  Put ao at the head of
				 * usable_arenas.  Note that because
				 * ao->nfreepools was 0 before, ao isn't
				 * currently on the usable_arenas list.
				 */
				ao->nextarena = usable_arenas;
				ao->prevarena = NULL;
				if (usable_arenas)
					usable_arenas->prevarena = ao;
				usable_arenas = ao;
				assert(usable_arenas->address != 0);

				UNLOCK();
				return;
			}
			/* If this arena is now out of order, we need to keep
			 * the list sorted.  The list is kept sorted so that
			 * the "most full" arenas are used first, which allows
			 * the nearly empty arenas to be completely freed.  In
			 * a few un-scientific tests, it seems like this
			 * approach allowed a lot more memory to be freed.
			 */
			if (ao->nextarena == NULL ||
				     nf <= ao->nextarena->nfreepools) {
				/* Case 4.  Nothing to do. */
				UNLOCK();
				return;
			}
			/* Case 3:  We have to move the arena towards the end
			 * of the list, because it has more free pools than
			 * the arena to its right.
			 * First unlink ao from usable_arenas.
			 */
			if (ao->prevarena != NULL) {
				/* ao isn't at the head of the list */
				assert(ao->prevarena->nextarena == ao);
				ao->prevarena->nextarena = ao->nextarena;
			}
			else {
				/* ao is at the head of the list */
				assert(usable_arenas == ao);
				usable_arenas = ao->nextarena;
			}
			ao->nextarena->prevarena = ao->prevarena;

			/* Locate the new insertion point by iterating over
			 * the list, using our nextarena pointer.
			 */
			while (ao->nextarena != NULL &&
					nf > ao->nextarena->nfreepools) {
				ao->prevarena = ao->nextarena;
				ao->nextarena = ao->nextarena->nextarena;
			}

			/* Insert ao at this point. */
			assert(ao->nextarena == NULL ||
				ao->prevarena == ao->nextarena->prevarena);
			assert(ao->prevarena->nextarena == ao->nextarena);

			ao->prevarena->nextarena = ao;
			if (ao->nextarena != NULL)
				ao->nextarena->prevarena = ao;

			/* Verify that the swaps worked. */
			assert(ao->nextarena == NULL ||
				  nf <= ao->nextarena->nfreepools);
			assert(ao->prevarena == NULL ||
				  nf > ao->prevarena->nfreepools);
			assert(ao->nextarena == NULL ||
				ao->nextarena->prevarena == ao);
			assert((usable_arenas == ao &&
				ao->prevarena == NULL) ||
				ao->prevarena->nextarena == ao);

			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
		 * targets optimal filling when several pools contain
		 * blocks of the same size class.
		 */
		--pool->ref.count;
		assert(pool->ref.count > 0);	/* else the pool is empty */
		size = pool->szidx;
		next = usedpools[size + size];
		prev = next->prevpool;
		/* insert pool before next:   prev <-> pool <-> next */
		pool->nextpool = next;
		pool->prevpool = prev;
		next->prevpool = pool;
		prev->nextpool = pool;
		UNLOCK();
		return;
	}

	/* We didn't allocate this address. */
	_SYSTEM_FREE(p);
}

/* 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.
 */

/*undef PyObject_Realloc*/
void *
_THIS_REALLOC(void *p, size_t nbytes)
{
	void *bp;
	poolp pool;
	size_t size;

	if (p == NULL)
		return PyObject_Malloc(nbytes);

	pool = POOL_ADDR(p);
	if (Py_ADDRESS_IN_RANGE(p, pool)) {
		/* We're in charge of this block */
		size = INDEX2SIZE(pool->szidx);
		if (nbytes <= size) {
			/* The block is staying the same or shrinking.  If
			 * it's shrinking, there's a tradeoff:  it costs
			 * cycles to copy the block to a smaller size class,
			 * but it wastes memory not to copy it.  The
			 * compromise here is to copy on shrink only if at
			 * least 25% of size can be shaved off.
			 */
			if (4 * nbytes > 3 * size) {
				/* It's the same,
				 * or shrinking and new/old > 3/4.
				 */
				return p;
			}
			size = nbytes;
		}
		bp = PyObject_Malloc(nbytes);
		if (bp != NULL) {
			memcpy(bp, p, size);
			PyObject_Free(p);
		}
		return bp;
	}
	/* We're not managing this block.  If nbytes <=
	 * SMALL_REQUEST_THRESHOLD, it's tempting to try to take over this
	 * block.  However, if we do, we need to copy the valid data from
	 * the C-managed block to one of our blocks, and there's no portable
	 * way to know how much of the memory space starting at p is valid.
	 * As bug 1185883 pointed out the hard way, it's possible that the
	 * C-managed block is "at the end" of allocated VM space, so that
	 * a memory fault can occur if we try to copy nbytes bytes starting
	 * at p.  Instead we punt:  let C continue to manage this block.
         */
	if (nbytes)
		return _SYSTEM_REALLOC(p, nbytes);
	/* C doesn't define the result of realloc(p, 0) (it may or may not
	 * return NULL then), but Python's docs promise that nbytes==0 never
	 * returns NULL.  We don't pass 0 to realloc(), to avoid that endcase
	 * to begin with.  Even then, we can't be sure that realloc() won't
	 * return NULL.
	 */
	bp = _SYSTEM_REALLOC(p, 1);
   	return bp ? bp : p;
}

#else	/* ! WITH_PYMALLOC */

/*==========================================================================*/
/* pymalloc not enabled:  Redirect the entry points to malloc.  These will
 * only be used by extensions that are compiled with pymalloc enabled. */

void *
PyObject_Malloc(size_t n)
{
	return PyMem_MALLOC(n);
}

void *
PyObject_Realloc(void *p, size_t n)
{
	return PyMem_REALLOC(p, n);
}

void
PyObject_Free(void *p)
{
	PyMem_FREE(p);
}
#endif /* WITH_PYMALLOC */

#ifdef PYMALLOC_DEBUG
/*==========================================================================*/
/* A x-platform debugging allocator.  This doesn't manage memory directly,
 * it wraps a real allocator, adding extra debugging info to the memory blocks.
 */

/* Special bytes broadcast into debug memory blocks at appropriate times.
 * Strings of these are unlikely to be valid addresses, floats, ints or
 * 7-bit ASCII.
 */
#undef CLEANBYTE
#undef DEADBYTE
#undef FORBIDDENBYTE
#define CLEANBYTE      0xCB    /* clean (newly allocated) memory */
#define DEADBYTE       0xDB    /* dead (newly freed) memory */
#define FORBIDDENBYTE  0xFB    /* untouchable bytes at each end of a block */

static size_t serialno = 0;	/* incremented on each debug {m,re}alloc */

/* serialno is always incremented via calling this routine.  The point is
 * to supply a single place to set a breakpoint.
 */
static void
bumpserialno(void)
{
	++serialno;
}

#define SST SIZEOF_SIZE_T

/* Read sizeof(size_t) bytes at p as a big-endian size_t. */
static size_t
read_size_t(const void *p)
{
	const uchar *q = (const uchar *)p;
	size_t result = *q++;
	int i;

	for (i = SST; --i > 0; ++q)
		result = (result << 8) | *q;
	return result;
}

/* Write n as a big-endian size_t, MSB at address p, LSB at
 * p + sizeof(size_t) - 1.
 */
static void
write_size_t(void *p, size_t n)
{
	uchar *q = (uchar *)p + SST - 1;
	int i;

	for (i = SST; --i >= 0; --q) {
		*q = (uchar)(n & 0xff);
		n >>= 8;
	}
}

#ifdef Py_DEBUG
/* Is target in the list?  The list is traversed via the nextpool pointers.
 * The list may be NULL-terminated, or circular.  Return 1 if target is in
 * list, else 0.
 */
static int
pool_is_in_list(const poolp target, poolp list)
{
	poolp origlist = list;
	assert(target != NULL);
	if (list == NULL)
		return 0;
	do {
		if (target == list)
			return 1;
		list = list->nextpool;
	} while (list != NULL && list != origlist);
	return 0;
}

#else
#define pool_is_in_list(X, Y) 1

#endif	/* Py_DEBUG */

/* Let S = sizeof(size_t).  The debug malloc asks for 4*S extra bytes and
   fills them with useful stuff, here calling the underlying malloc's result p:

p[0: S]
    Number of bytes originally asked for.  This is a size_t, big-endian (easier
    to read in a memory dump).
p[S: 2*S]
    Copies of FORBIDDENBYTE.  Used to catch under- writes and reads.
p[2*S: 2*S+n]
    The requested memory, filled with copies of CLEANBYTE.
    Used to catch reference to uninitialized memory.
    &p[2*S] is returned.  Note that this is 8-byte aligned if pymalloc
    handled the request itself.
p[2*S+n: 2*S+n+S]
    Copies of FORBIDDENBYTE.  Used to catch over- writes and reads.
p[2*S+n+S: 2*S+n+2*S]
    A serial number, incremented by 1 on each call to _PyObject_DebugMalloc
    and _PyObject_DebugRealloc.
    This is a big-endian size_t.
    If "bad memory" is detected later, the serial number gives an
    excellent way to set a breakpoint on the next run, to capture the
    instant at which this block was passed out.
*/

void *
_PyObject_DebugMalloc(size_t nbytes)
{
	uchar *p;	/* base address of malloc'ed block */
	uchar *tail;	/* p + 2*SST + nbytes == pointer to tail pad bytes */
	size_t total;	/* nbytes + 4*SST */

	bumpserialno();
	total = nbytes + 4*SST;
	if (total < nbytes)
		/* overflow:  can't represent total as a size_t */
		return NULL;

	p = (uchar *)PyObject_Malloc(total);
	if (p == NULL)
		return NULL;

	write_size_t(p, nbytes);
	memset(p + SST, FORBIDDENBYTE, SST);

	if (nbytes > 0)
		memset(p + 2*SST, CLEANBYTE, nbytes);

	tail = p + 2*SST + nbytes;
	memset(tail, FORBIDDENBYTE, SST);
	write_size_t(tail + SST, serialno);

	return p + 2*SST;
}

/* The debug free first checks the 2*SST bytes on each end for sanity (in
   particular, that the FORBIDDENBYTEs are still intact).
   Then fills the original bytes with DEADBYTE.
   Then calls the underlying free.
*/
void
_PyObject_DebugFree(void *p)
{
	uchar *q = (uchar *)p - 2*SST;  /* address returned from malloc */
	size_t nbytes;

	if (p == NULL)
		return;
	_PyObject_DebugCheckAddress(p);
	nbytes = read_size_t(q);
	if (nbytes > 0)
		memset(q, DEADBYTE, nbytes);
	PyObject_Free(q);
}

void *
_PyObject_DebugRealloc(void *p, size_t nbytes)
{
	uchar *q = (uchar *)p;
	uchar *tail;
	size_t total;	/* nbytes + 4*SST */
	size_t original_nbytes;
	int i;

	if (p == NULL)
		return _PyObject_DebugMalloc(nbytes);

	_PyObject_DebugCheckAddress(p);
	bumpserialno();
	original_nbytes = read_size_t(q - 2*SST);
	total = nbytes + 4*SST;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -