📄 prmalloc.c
字号:
if (p && page_dir[((u_long)p >> malloc_pageshift) - malloc_origo] != MALLOC_FREE) { wrterror("allocated non-free page on free-list\n"); }#endif /* EXTRA_SANITY */ size >>= malloc_pageshift; /* Map new pages */ if (!p) p = map_pages(size,1); if (p) { /* Mark the pages in the directory */ index = ((u_long)p >> malloc_pageshift) - malloc_origo; page_dir[index] = MALLOC_FIRST; for (i=1;i<size;i++) page_dir[index+i] = MALLOC_FOLLOW; } if (delay_free) { if (!px) px = (struct pgfree*)delay_free; else _PR_UnlockedFree(delay_free); } return p;}/* * Allocate a page of fragments */static 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; l = sizeof *bp - sizeof(u_long); l += sizeof(u_long) * (((malloc_pagesize >> bits)+MALLOC_BITS-1) / MALLOC_BITS); if ((1<<(bits)) <= l+l) { bp = (struct pginfo *)pp; } else { bp = (struct pginfo *)_PR_UnlockedMalloc(l); } if (!bp) return 0; bp->size = (1<<bits); bp->shift = bits; bp->total = bp->free = malloc_pagesize >> bits; bp->next = page_dir[bits]; bp->page = (char*)pp; i = set_pgdir(pp,bp); if (!i) return 0; /* We can safely assume that there is nobody in this chain */ page_dir[bits] = bp; /* set all valid bits in the bits */ k = bp->total; i = 0;/* for(;k-i >= MALLOC_BITS; i += MALLOC_BITS) bp->bits[i / MALLOC_BITS] = ~0;*/ for(; i < k; i++) set_bit(bp,i); if (bp != pp) return 1; /* We may have used the first ones already */ for(i=0;l > 0;i++) { clr_bit(bp,i); bp->free--; bp->total--; l -= (1 << bits); } return 1;}/* * Allocate a fragment */static void *malloc_bytes(size_t size){ size_t s; int j; struct pginfo *bp; int k; u_long *lp, bf; /* Don't bother with anything less than this */ if (size < malloc_minsize) { size = malloc_minsize; } /* Find the right bucket */ j = 1; s = size - 1; while (s >>= 1) { j++; } /* If it's empty, make a page more of that size chunks */ if (!page_dir[j] && !malloc_make_chunks(j)) return 0; /* Find first word of bitmap which isn't empty */ bp = page_dir[j]; for (lp = bp->bits; !*lp; lp++) ; /* Find that bit */ bf = *lp; k = 0; while ((bf & 1) == 0) { bf >>= 1; k++; } *lp ^= 1L<<k; /* clear it */ bp->free--; if (!bp->free) { page_dir[j] = bp->next; bp->next = 0; } k += (lp - bp->bits)*MALLOC_BITS; return bp->page + (k << bp->shift);}void *_PR_UnlockedMalloc(size_t size){ void *result; /* Round up to a multiple of 8 bytes */ if (size & 7) { size = size + 8 - (size & 7); } if (!initialized) malloc_init();#ifdef SANITY if (suicide) PR_Abort();#endif if (size <= malloc_maxsize) result = malloc_bytes(size); else result = malloc_pages(size);#ifdef SANITY if (malloc_abort && !result) wrterror("malloc() returns NULL\n");#endif TRACE(("%6d M %p %d\n",malloc_event++,result,size)); return result;}void *_PR_UnlockedMemalign(size_t alignment, size_t size){ void *result; /* * alignment has to be a power of 2 */ if ((size <= alignment) && (alignment <= malloc_maxsize)) size = alignment; else size += alignment - 1; /* Round up to a multiple of 8 bytes */ if (size & 7) { size = size + 8 - (size & 7); } if (!initialized) malloc_init();#ifdef SANITY if (suicide) abort();#endif if (size <= malloc_maxsize) result = malloc_bytes(size); else result = malloc_pages(size);#ifdef SANITY if (malloc_abort && !result) wrterror("malloc() returns NULL\n");#endif TRACE(("%6d A %p %d\n",malloc_event++,result,size)); if ((u_long)result & (alignment - 1)) return ((void *)(((u_long)result + alignment) & ~(alignment - 1))); else return result;}void *_PR_UnlockedCalloc(size_t n, size_t nelem){ void *p; /* Compute total size and then round up to a double word amount */ n *= nelem; if (n & 7) { n = n + 8 - (n & 7); } /* Get the memory */ p = _PR_UnlockedMalloc(n); if (p) { /* Zero it */ memset(p, 0, n); } return p;}/* * Change an allocation's size */void *_PR_UnlockedRealloc(void *ptr, size_t size){ void *p; u_long osize,page,index,tmp_index; struct pginfo **mp; if (!initialized) malloc_init();#ifdef SANITY if (suicide) PR_Abort();#endif /* used as free() */ TRACE(("%6d R %p %d\n",malloc_event++, ptr, size)); if (ptr && !size) { _PR_UnlockedFree(ptr); return _PR_UnlockedMalloc (1); } /* used as malloc() */ if (!ptr) { p = _PR_UnlockedMalloc(size); return p; } /* Find the page directory entry for the page in question */ page = (u_long)ptr >> malloc_pageshift; index = page - malloc_origo; /* * check if memory was allocated by memalign */ tmp_index = index; while (page_dir[tmp_index] == MALLOC_FOLLOW) tmp_index--; if (tmp_index != index) { /* * memalign-allocated memory */ index = tmp_index; page = index + malloc_origo; ptr = (void *) (page << malloc_pageshift); } TRACE(("%6d R2 %p %d\n",malloc_event++, ptr, size)); /* make sure it makes sense in some fashion */ if (index < malloc_pageshift || index > last_index) {#ifdef SANITY wrtwarning("junk pointer passed to realloc()\n");#endif return 0; } /* find the size of that allocation, and see if we need to relocate */ mp = &page_dir[index]; if (*mp == MALLOC_FIRST) { osize = malloc_pagesize; while (mp[1] == MALLOC_FOLLOW) { osize += malloc_pagesize; mp++; } if (!malloc_realloc && size < osize && size > malloc_maxsize && size > (osize - malloc_pagesize)) { return ptr; } } else if (*mp >= MALLOC_MAGIC) { osize = (*mp)->size; if (!malloc_realloc && size < osize && (size > (*mp)->size/2 || (*mp)->size == malloc_minsize)) { return ptr; } } else {#ifdef SANITY wrterror("realloc() of wrong page.\n");#endif } /* try to reallocate */ p = _PR_UnlockedMalloc(size); if (p) { /* copy the lesser of the two sizes */ if (osize < size) memcpy(p,ptr,osize); else memcpy(p,ptr,size); _PR_UnlockedFree(ptr); }#ifdef DEBUG else if (malloc_abort) wrterror("realloc() returns NULL\n");#endif return p;}/* * Free a sequence of pages */static voidfree_pages(char *ptr, u_long page, int index, struct pginfo *info){ int i; struct pgfree *pf,*pt; u_long l; char *tail; TRACE(("%6d FP %p %d\n",malloc_event++, ptr, page)); /* Is it free already ? */ if (info == MALLOC_FREE) {#ifdef SANITY wrtwarning("freeing free page at %p.\n", ptr);#endif return; }#ifdef SANITY /* Is it not the right place to begin ? */ if (info != MALLOC_FIRST) wrterror("freeing wrong page.\n"); /* Is this really a pointer to a page ? */ if ((u_long)ptr & malloc_pagemask) wrterror("freeing messed up page pointer.\n");#endif /* Count how many pages it is anyway */ 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; tail = ptr+l; /* add to free-list */ if (!px) px = (struct pgfree*)_PR_UnlockedMalloc(sizeof *pt); /* XXX check success */ px->page = ptr; px->end = tail; px->size = l; if (!free_list.next) { px->next = free_list.next; px->prev = &free_list; free_list.next = px; pf = px; px = 0; } else { tail = ptr+l; for(pf = free_list.next; pf->next && pf->end < ptr; pf = pf->next) ; for(; pf; pf = pf->next) { if (pf->end == ptr ) { /* append to entry */ pf->end += l; pf->size += l; if (pf->next && pf->end == pf->next->page ) { pt = pf->next; pf->end = pt->end; pf->size += pt->size; pf->next = pt->next; if (pf->next) pf->next->prev = pf; _PR_UnlockedFree(pt); } } else if (pf->page == tail) { /* prepend to entry */ pf->size += l; pf->page = ptr; } else if (pf->page > ptr) { px->next = pf; px->prev = pf->prev; pf->prev = px; px->prev->next = px; pf = px; px = 0; } else if (!pf->next) { px->next = 0; px->prev = pf; pf->next = px; pf = px; px = 0; } else { continue; } break; } } if (!pf->next && pf->size > malloc_cache && pf->end == malloc_brk && malloc_brk == (void*)sbrk(0)) { pf->end = pf->page + malloc_cache; pf->size = malloc_cache; TRACE(("%6d U %p %d\n",malloc_event++,pf->end,pf->end - pf->page)); brk(pf->end); malloc_brk = pf->end; /* Find the page directory entry for the page in question */ page = (u_long)pf->end >> malloc_pageshift; index = page - malloc_origo; /* Now update the directory */ for(i=index;i <= last_index;) page_dir[i++] = MALLOC_NOT_MINE; last_index = index - 1; }}/* * Free a chunk, and possibly the page it's on, if the page becomes empty. */static voidfree_bytes(void *ptr, u_long page, int index, struct pginfo *info){ int i; struct pginfo **mp; void *vp; /* Make sure that pointer is multiplum of chunk-size */#ifdef SANITY if ((u_long)ptr & (info->size - 1)) wrterror("freeing messed up chunk pointer\n");#endif /* Find the chunk number on the page */ i = ((u_long)ptr & malloc_pagemask) >> info->shift; /* See if it's free already */ if (tst_bit(info,i)) {#ifdef SANITY wrtwarning("freeing free chunk at %p\n", ptr);#endif return; } /* Mark it free */ set_bit(info,i); info->free++; /* If the page was full before, we need to put it on the queue now */ if (info->free == 1) { mp = page_dir + info->shift; while (*mp && (*mp)->next && (*mp)->next->page < info->page) mp = &(*mp)->next; info->next = *mp; *mp = info; return; } /* If this page isn't empty, don't do anything. */ if (info->free != info->total) return; /* We may want to keep at least one page of each size chunks around. */ mp = page_dir + info->shift; if (0 && (*mp == info) && !info->next) return; /* Find & remove this page in the queue */ while (*mp != info) { mp = &((*mp)->next);#ifdef EXTRA_SANITY if (!*mp) { TRACE(("%6d !q %p\n",malloc_event++,info)); wrterror("Not on queue\n"); }#endif } *mp = info->next; /* Free the page & the info structure if need be */ set_pgdir(info->page,MALLOC_FIRST); if((void*)info->page == (void*)info) { _PR_UnlockedFree(info->page); } else { vp = info->page; _PR_UnlockedFree(info); _PR_UnlockedFree(vp); }}void _PR_UnlockedFree(void *ptr){ u_long page; struct pginfo *info; int index, tmp_index; TRACE(("%6d F %p\n",malloc_event++,ptr)); /* This is legal */ if (!ptr) return;#ifdef SANITY /* There wouldn't be anything to free */ if (!initialized) { wrtwarning("free() called before malloc() ever got called\n"); return; }#endif#ifdef SANITY if (suicide) PR_Abort();#endif /* Find the page directory entry for the page in question */ page = (u_long)ptr >> malloc_pageshift; index = page - malloc_origo; /* * check if memory was allocated by memalign */ tmp_index = index; while (page_dir[tmp_index] == MALLOC_FOLLOW) tmp_index--; if (tmp_index != index) { /* * memalign-allocated memory */ index = tmp_index; page = index + malloc_origo; ptr = (void *) (page << malloc_pageshift); } /* make sure it makes sense in some fashion */ if (index < malloc_pageshift) {#ifdef SANITY wrtwarning("junk pointer %p (low) passed to free()\n", ptr);#endif return; } if (index > last_index) {#ifdef SANITY wrtwarning("junk pointer %p (high) passed to free()\n", ptr);#endif return; } /* handle as page-allocation or chunk allocation */ info = page_dir[index]; if (info < MALLOC_MAGIC) free_pages((char*)ptr, page, index, info); else free_bytes(ptr,page,index,info); return;}#endif /* _PR_OVERRIDE_MALLOC */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -