📄 malloc.c
字号:
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 + -