malloc.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,140 行 · 第 1/2 页

C
1,140
字号
    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)	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) {	    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] && !malloc_make_chunks(j))	return 0;    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 = 0;    }    /* 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 = 0;    else if (size <= malloc_maxsize)	result =  malloc_bytes(size);    else	result =  malloc_pages(size);    if (malloc_abort && !result)	wrterror("allocation failed.\n");    if (malloc_zero && result)	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 0;    }    if (index > last_index) {	wrtwarning("junk pointer, too high to make sense.\n");	return 0;    }    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 0;	}	/* 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, */	    return ptr;				/* don't do anything. */	}    } 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 0;	}	/* 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 0;	}	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) */	    return ptr;			/* ..Don't do anything */	}    } else {	wrtwarning("pointer to wrong page.\n");	return 0;    }    p = imalloc(size);    if (p) {	/* 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, int index, struct pginfo *info){    int i;    struct pgfree *pf, *pt=0;    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 (malloc_hint)	madvise(ptr, l, MADV_FREE);    tail = (char *)ptr+l;    /* add to free-list */    if (!px)	px = imalloc(sizeof *pt);	/* This cannot fail... */    px->page = ptr;    px->end =  tail;    px->size = l;    if (!free_list.next) {	/* Nothing on free list, put this at head */	px->next = free_list.next;	px->prev = &free_list;	free_list.next = px;	pf = px;	px = 0;    } 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; 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 = 0;	} else if (pf->end == ptr ) {	    /* Append to the previous entry */	    pf->end = (char *)pf->end + l;	    pf->size += l;	    if (pf->next && 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)		    pf->next->prev = pf;	    }	} else if (pf->page == tail) {	    /* Prepend to entry */	    pf->size += l;	    pf->page = ptr;	} else if (!pf->next) {	    /* Append at tail of chain */	    px->next = 0;	    px->prev = pf;	    pf->next = px;	    pf = px;	    px = 0;	} else {	    wrterror("freelist is destroyed.\n");	}    }        /* Return something to OS ? */    if (!pf->next &&				/* 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);	last_index = index - 1;	for(i=index;i <= last_index;)	    page_dir[i++] = MALLOC_NOT_MINE;	/* XXX: We could realloc/shrink the pagedir here I guess. */    }    if (pt)	ifree(pt);}/* * Free a chunk, and possibly the page it's on, if the page becomes empty. */static __inline__ voidfree_bytes(void *ptr, int 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 EXTRA_SANITY	if (!*mp)		wrterror("(ES): Not on queue\n");#endif /* 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;    int index;    /* This is legal */    if (!ptr)	return;    if (!malloc_started) {	wrtwarning("malloc() has never been called.\n");	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;}/* * These are the public exported interface routines. */void *malloc(size_t size){    register void *r;    THREAD_LOCK();    malloc_func = " in malloc():";    if (malloc_active++) {	wrtwarning("recursive call.\n");        malloc_active--;	return (0);    }    if (!malloc_started)	malloc_init();    if (malloc_sysv && !size)	r = 0;    else	r = imalloc(size);    UTRACE(0, size, r);    malloc_active--;    THREAD_UNLOCK();    if (malloc_xmalloc && !r)	wrterror("out of memory.\n");    return (r);}voidfree(void *ptr){    THREAD_LOCK();    malloc_func = " in free():";    if (malloc_active++) {	wrtwarning("recursive call.\n");	malloc_active--;	return;    } else {	ifree(ptr);	UTRACE(ptr, 0, 0);    }    malloc_active--;    THREAD_UNLOCK();    return;}void *realloc(void *ptr, size_t size){    register void *r;    THREAD_LOCK();    malloc_func = " in realloc():";    if (malloc_active++) {	wrtwarning("recursive call.\n");        malloc_active--;	return (0);    }    if (ptr && !malloc_started) {	wrtwarning("malloc() has never been called.\n");	ptr = 0;    }		    if (!malloc_started)	malloc_init();    if (malloc_sysv && !size) {	ifree(ptr);	r = 0;    } else if (!ptr) {	r = imalloc(size);    } else {        r = irealloc(ptr, size);    }    UTRACE(ptr, size, r);    malloc_active--;    THREAD_UNLOCK();    if (malloc_xmalloc && !r)	wrterror("out of memory.\n");    return (r);}#endif /* !OSKIT */

⌨️ 快捷键说明

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