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

📄 malloc.c

📁 Dynamic Memory Allocation
💻 C
📖 第 1 页 / 共 2 页
字号:
	    px = delay_free;	else	    ifree(delay_free);    }    return (p);}/* * Allocate a page of fragments */static __inline intmalloc_make_chunks(int bits){    struct  pginfo *bp;    void *pp;    int i, k, l;    /* Allocate a new bucket */    pp = malloc_pages(malloc_pagesize);    if (pp == NULL)	return (0);    /* Find length of admin structure */    l = offsetof(struct pginfo, bits[0]);    l += sizeof bp->bits[0] *	(((malloc_pagesize >> bits)+MALLOC_BITS-1) / MALLOC_BITS);    /* Don't waste more than two chunks on this */    if ((1<<(bits)) <= l+l) {	bp = (struct  pginfo *)pp;    } else {	bp = (struct  pginfo *)imalloc(l);	if (bp == NULL) {	    ifree(pp);	    return (0);	}    }    bp->size = (1<<bits);    bp->shift = bits;    bp->total = bp->free = malloc_pagesize >> bits;    bp->page = pp;    /* set all valid bits in the bitmap */    k = bp->total;    i = 0;    /* Do a bunch at a time */    for(;k-i >= MALLOC_BITS; i += MALLOC_BITS)	bp->bits[i / MALLOC_BITS] = ~0;    for(; i < k; i++)        bp->bits[i/MALLOC_BITS] |= 1<<(i%MALLOC_BITS);    if (bp == bp->page) {	/* Mark the ones we stole for ourselves */	for(i=0;l > 0;i++) {	    bp->bits[i/MALLOC_BITS] &= ~(1<<(i%MALLOC_BITS));	    bp->free--;	    bp->total--;	    l -= (1 << bits);	}    }    /* MALLOC_LOCK */    page_dir[ptr2index(pp)] = bp;    bp->next = page_dir[bits];    page_dir[bits] = bp;    /* MALLOC_UNLOCK */    return (1);}/* * Allocate a fragment */static void *malloc_bytes(size_t size){    int i,j;    u_int u;    struct  pginfo *bp;    int k;    u_int *lp;    /* Don't bother with anything less than this */    if (size < malloc_minsize)	size = malloc_minsize;    /* Find the right bucket */    j = 1;    i = size-1;    while (i >>= 1)	j++;    /* If it's empty, make a page more of that size chunks */    if (page_dir[j] == NULL && !malloc_make_chunks(j))	return (NULL);    bp = page_dir[j];    /* Find first word of bitmap which isn't empty */    for (lp = bp->bits; !*lp; lp++)	;    /* Find that bit, and tweak it */    u = 1;    k = 0;    while (!(*lp & u)) {	u += u;	k++;    }    *lp ^= u;    /* If there are no more free, remove from free-list */    if (!--bp->free) {	page_dir[j] = bp->next;	bp->next = NULL;    }    /* Adjust to the real offset of that chunk */    k += (lp-bp->bits)*MALLOC_BITS;    k <<= bp->shift;    if (malloc_junk)	memset((u_char *)bp->page + k, SOME_JUNK, bp->size);    return ((u_char *)bp->page + k);}/* * Allocate a piece of memory */static void *imalloc(size_t size){    void *result;    if (suicide)	abort();    if ((size + malloc_pagesize) < size)	/* Check for overflow */	result = NULL;    else if ((size + malloc_pagesize) >= (uintptr_t)page_dir)	result = NULL;    else if (size <= malloc_maxsize)	result = malloc_bytes(size);    else	result = malloc_pages(size);    if (malloc_zero && result != NULL)	memset(result, 0, size);    return (result);}/* * Change the size of an allocation. */static void *irealloc(void *ptr, size_t size){    void *p;    u_long osize, index;    struct pginfo **mp;    int i;    if (suicide)	abort();    index = ptr2index(ptr);    if (index < malloc_pageshift) {	wrtwarning("junk pointer, too low to make sense\n");	return (NULL);    }    if (index > last_index) {	wrtwarning("junk pointer, too high to make sense\n");	return (NULL);    }    mp = &page_dir[index];    if (*mp == MALLOC_FIRST) {			/* Page allocation */	/* Check the pointer */	if ((u_long)ptr & malloc_pagemask) {	    wrtwarning("modified (page-) pointer\n");	    return (NULL);	}	/* Find the size in bytes */	for (osize = malloc_pagesize; *(++mp) == MALLOC_FOLLOW;)	    osize += malloc_pagesize;        if (!malloc_realloc && 			/* Unless we have to, */	  size <= osize && 			/* .. or are too small, */	  size > (osize - malloc_pagesize)) {	/* .. or can free a page, */	    if (malloc_junk)		memset((u_char *)ptr + size, SOME_JUNK, osize-size);	    return (ptr);			/* ..don't do anything else. */	}    } else if (*mp >= MALLOC_MAGIC) {		/* Chunk allocation */	/* Check the pointer for sane values */	if (((u_long)ptr & ((*mp)->size-1))) {	    wrtwarning("modified (chunk-) pointer\n");	    return (NULL);	}	/* Find the chunk index in the page */	i = ((u_long)ptr & malloc_pagemask) >> (*mp)->shift;	/* Verify that it isn't a free chunk already */        if ((*mp)->bits[i/MALLOC_BITS] & (1<<(i%MALLOC_BITS))) {	    wrtwarning("chunk is already free\n");	    return (NULL);	}	osize = (*mp)->size;	if (!malloc_realloc &&		/* Unless we have to, */	  size <= osize && 		/* ..or are too small, */	  (size > osize/2 ||	 	/* ..or could use a smaller size, */	  osize == malloc_minsize)) {	/* ..(if there is one) */	    if (malloc_junk)		memset((u_char *)ptr + size, SOME_JUNK, osize-size);	    return (ptr);		/* ..don't do anything else. */	}    } else {	wrtwarning("pointer to wrong page\n");	return (NULL);    }    p = imalloc(size);    if (p != NULL) {	/* copy the lesser of the two sizes, and free the old one */	if (!size || !osize)	    ;	else if (osize < size)	    memcpy(p, ptr, osize);	else	    memcpy(p, ptr, size);	ifree(ptr);    }    return (p);}/* * Free a sequence of pages */static __inline voidfree_pages(void *ptr, u_long index, struct pginfo const *info){    u_long i;    struct pgfree *pf, *pt=NULL;    u_long l;    void *tail;    if (info == MALLOC_FREE) {	wrtwarning("page is already free\n");	return;    }    if (info != MALLOC_FIRST) {	wrtwarning("pointer to wrong page\n");	return;    }    if ((u_long)ptr & malloc_pagemask) {	wrtwarning("modified (page-) pointer\n");	return;    }    /* Count how many pages and mark them free at the same time */    page_dir[index] = MALLOC_FREE;    for (i = 1; page_dir[index+i] == MALLOC_FOLLOW; i++)	page_dir[index + i] = MALLOC_FREE;    l = i << malloc_pageshift;    if (malloc_junk)	memset(ptr, SOME_JUNK, l);#if defined(MADV_FREE)    if (malloc_hint)	madvise(ptr, l, MADV_FREE);#endif    tail = (char *)ptr+l;    /* add to free-list */    if (px == NULL)	px = imalloc(sizeof *px);	/* This cannot fail... */    px->page = ptr;    px->end =  tail;    px->size = l;    if (free_list.next == NULL) {	/* Nothing on free list, put this at head */	px->next = free_list.next;	px->prev = &free_list;	free_list.next = px;	pf = px;	px = NULL;    } else {	/* Find the right spot, leave pf pointing to the modified entry. */	tail = (char *)ptr+l;	for(pf = free_list.next; pf->end < ptr && pf->next != NULL;	    pf = pf->next)	    ; /* Race ahead here */	if (pf->page > tail) {	    /* Insert before entry */	    px->next = pf;	    px->prev = pf->prev;	    pf->prev = px;	    px->prev->next = px;	    pf = px;	    px = NULL;	} else if (pf->end == ptr ) {	    /* Append to the previous entry */	    pf->end = (char *)pf->end + l;	    pf->size += l;	    if (pf->next != NULL && pf->end == pf->next->page ) {		/* And collapse the next too. */		pt = pf->next;		pf->end = pt->end;		pf->size += pt->size;		pf->next = pt->next;		if (pf->next != NULL)		    pf->next->prev = pf;	    }	} else if (pf->page == tail) {	    /* Prepend to entry */	    pf->size += l;	    pf->page = ptr;	} else if (pf->next == NULL) {	    /* Append at tail of chain */	    px->next = NULL;	    px->prev = pf;	    pf->next = px;	    pf = px;	    px = NULL;	} else {	    wrterror("freelist is destroyed\n");	}    }    /* Return something to OS ? */    if (pf->next == NULL &&			/* If we're the last one, */      pf->size > malloc_cache &&		/* ..and the cache is full, */      pf->end == malloc_brk &&			/* ..and none behind us, */      malloc_brk == sbrk(0)) {			/* ..and it's OK to do... */	/*	 * Keep the cache intact.  Notice that the '>' above guarantees that	 * the pf will always have at least one page afterwards.	 */	pf->end = (char *)pf->page + malloc_cache;	pf->size = malloc_cache;	brk(pf->end);	malloc_brk = pf->end;	index = ptr2index(pf->end);	for(i=index;i <= last_index;)	    page_dir[i++] = MALLOC_NOT_MINE;	last_index = index - 1;	/* XXX: We could realloc/shrink the pagedir here I guess. */    }    if (pt != NULL)	ifree(pt);}/* * Free a chunk, and possibly the page it's on, if the page becomes empty. */static __inline voidfree_bytes(void *ptr, u_long index, struct pginfo *info){    int i;    struct pginfo **mp;    void *vp;    /* Find the chunk number on the page */    i = ((u_long)ptr & malloc_pagemask) >> info->shift;    if (((u_long)ptr & (info->size-1))) {	wrtwarning("modified (chunk-) pointer\n");	return;    }    if (info->bits[i/MALLOC_BITS] & (1<<(i%MALLOC_BITS))) {	wrtwarning("chunk is already free\n");	return;    }    if (malloc_junk)	memset(ptr, SOME_JUNK, info->size);    info->bits[i/MALLOC_BITS] |= 1<<(i%MALLOC_BITS);    info->free++;    mp = page_dir + info->shift;    if (info->free == 1) {	/* Page became non-full */	mp = page_dir + info->shift;	/* Insert in address order */	while (*mp && (*mp)->next && (*mp)->next->page < info->page)	    mp = &(*mp)->next;	info->next = *mp;	*mp = info;	return;    }    if (info->free != info->total)	return;    /* Find & remove this page in the queue */    while (*mp != info) {	mp = &((*mp)->next);#ifdef MALLOC_EXTRA_SANITY	if (!*mp)		wrterror("(ES): Not on queue\n");#endif /* MALLOC_EXTRA_SANITY */    }    *mp = info->next;    /* Free the page & the info structure if need be */    page_dir[ptr2index(info->page)] = MALLOC_FIRST;    vp = info->page;		/* Order is important ! */    if(vp != (void*)info)	ifree(info);    ifree(vp);}static voidifree(void *ptr){    struct pginfo *info;    u_long index;    /* This is legal */    if (ptr == NULL)	return;    /* If we're already sinking, don't make matters any worse. */    if (suicide)	return;    index = ptr2index(ptr);    if (index < malloc_pageshift) {	wrtwarning("junk pointer, too low to make sense\n");	return;    }    if (index > last_index) {	wrtwarning("junk pointer, too high to make sense\n");	return;    }    info = page_dir[index];    if (info < MALLOC_MAGIC)        free_pages(ptr, index, info);    else	free_bytes(ptr, index, info);    return;}static void *pubrealloc(void *ptr, size_t size, const char *func){    void *r;    int err = 0;    static int malloc_active; /* Recusion flag for public interface. */    static unsigned malloc_started; /* Set when initialization has been done */    /*     * If a thread is inside our code with a functional lock held, and then     * catches a signal which calls us again, we would get a deadlock if the     * lock is not of a recursive type.     */    _MALLOC_LOCK();    malloc_func = func;    if (malloc_active > 0) {	if (malloc_active == 1) {	    wrtwarning("recursive call\n");	    malloc_active = 2;	}        _MALLOC_UNLOCK();	errno = EDOOFUS;	return (NULL);    }     malloc_active = 1;    if (!malloc_started) {        if (ptr != NULL) {	    wrtwarning("malloc() has never been called\n");	    malloc_active = 0;            _MALLOC_UNLOCK();	    errno = EDOOFUS;	    return (NULL);	}	malloc_init();	malloc_started = 1;    }       if (ptr == ZEROSIZEPTR)	ptr = NULL;    if (malloc_sysv && !size) {	if (ptr != NULL)	    ifree(ptr);	r = NULL;    } else if (!size) {	if (ptr != NULL)	    ifree(ptr);	r = ZEROSIZEPTR;    } else if (ptr == NULL) {	r = imalloc(size);	err = (r == NULL);    } else {        r = irealloc(ptr, size);	err = (r == NULL);    }    UTRACE(ptr, size, r);    malloc_active = 0;    _MALLOC_UNLOCK();    if (malloc_xmalloc && err)	wrterror("out of memory\n");    if (err)	errno = ENOMEM;    return (r);}/* * These are the public exported interface routines. */void *malloc(size_t size){    return (pubrealloc(NULL, size, " in malloc():"));}voidfree(void *ptr){    pubrealloc(ptr, 0, " in free():");}void *realloc(void *ptr, size_t size){    return (pubrealloc(ptr, size, " in realloc():"));}

⌨️ 快捷键说明

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