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

📄 prmalloc.c

📁 Netscape NSPR库源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//*  * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ *  * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. *  * The Original Code is the Netscape Portable Runtime (NSPR). *  * The Initial Developer of the Original Code is Netscape * Communications Corporation.  Portions created by Netscape are  * Copyright (C) 1998-2000 Netscape Communications Corporation.  All * Rights Reserved. *  * Contributor(s): *  * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable  * instead of those above.  If you wish to allow use of your  * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL.  If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. */#include "primpl.h"/*** We override malloc etc. on any platform which has preemption +** nspr20 user level threads.  When we're debugging, we can make our** version of malloc fail occasionally.*/#ifdef _PR_OVERRIDE_MALLOC/*** Thread safe version of malloc, calloc, realloc, free*/#include <stdarg.h>#ifdef DEBUG#define SANITY#define EXTRA_SANITY#else#undef SANITY#undef EXTRA_SANITY#endif/* Forward decls */void *_PR_UnlockedMalloc(size_t size);void _PR_UnlockedFree(void *ptr);void *_PR_UnlockedRealloc(void *ptr, size_t size);void *_PR_UnlockedCalloc(size_t n, size_t elsize);/************************************************************************//* * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): * <phk@FreeBSD.ORG> wrote this file.  As long as you retain this notice you * can do whatever you want with this stuff. If we meet some day, and you think * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp * ---------------------------------------------------------------------------- * *//* * Defining SANITY will enable some checks which will tell you if the users * program did botch something *//* * Defining EXTRA_SANITY will enable some checks which are mostly related * to internal conditions in malloc.c *//* * Very verbose progress on stdout... */#if 0#  define TRACE(foo)    printf  foostatic int malloc_event;#else#  define TRACE(foo)	#endif/* XXX Pick a number, any number */#   define malloc_pagesize		4096UL#   define malloc_pageshift		12UL#ifdef XP_UNIX#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <errno.h>#include <sys/types.h>#include <sys/mman.h>#endif/* * This structure describes a page's worth of chunks. */struct pginfo {    struct pginfo	*next;	/* next on the free list */    char		*page;	/* Pointer to the page */    u_short		size;	/* size of this page's chunks */    u_short		shift;	/* How far to shift for this size chunks */    u_short		free;	/* How many free chunks */    u_short		total;	/* How many chunk */    u_long		bits[1]; /* Which chunks are free */};struct pgfree {    struct pgfree	*next;	/* next run of free pages */    struct pgfree	*prev;	/* prev run of free pages */    char		*page;	/* pointer to free pages */    char		*end;	/* pointer to end of free pages */    u_long		size;	/* number of bytes free */};/* * How many bits per u_long in the bitmap. * Change only if not 8 bits/byte */#define	MALLOC_BITS	(8*sizeof(u_long))/* * Magic values to put in the page_directory */#define MALLOC_NOT_MINE	((struct pginfo*) 0)#define MALLOC_FREE 	((struct pginfo*) 1)#define MALLOC_FIRST	((struct pginfo*) 2)#define MALLOC_FOLLOW	((struct pginfo*) 3)#define MALLOC_MAGIC	((struct pginfo*) 4)/* * Set to one when malloc_init has been called */static	unsigned	initialized;/* * The size of a page. * Must be a integral multiplum of the granularity of mmap(2). * Your toes will curl if it isn't a power of two */#define malloc_pagemask	((malloc_pagesize)-1)/* * The size of the largest chunk. * Half a page. */#define malloc_maxsize	((malloc_pagesize)>>1)/* * malloc_pagesize == 1 << malloc_pageshift */#ifndef malloc_pageshiftstatic	unsigned	malloc_pageshift;#endif /* malloc_pageshift *//* * The smallest allocation we bother about. * Must be power of two */#ifndef malloc_minsizestatic	unsigned  malloc_minsize;#endif /* malloc_minsize *//* * The largest chunk we care about. * Must be smaller than pagesize * Must be power of two */#ifndef malloc_maxsizestatic	unsigned  malloc_maxsize;#endif /* malloc_maxsize */#ifndef malloc_cachestatic	unsigned  malloc_cache;#endif /* malloc_cache *//* * The offset from pagenumber to index into the page directory */static	u_long  malloc_origo;/* * The last index in the page directory we care about */static	u_long  last_index;/* * Pointer to page directory. * Allocated "as if with" malloc */static	struct	pginfo **page_dir;/* * How many slots in the page directory */static	unsigned	malloc_ninfo;/* * Free pages line up here  */static struct pgfree	free_list;/* * Abort() if we fail to get VM ? */static int malloc_abort;#ifdef SANITY/* * Are we trying to die ? */static int suicide;#endif/* * dump statistics */static int malloc_stats;/* * always realloc ? */static int malloc_realloc;/* * my last break. */static void *malloc_brk;/* * one location cache for free-list holders */static struct pgfree *px;static int set_pgdir(void *ptr, struct  pginfo *info);static int extend_page_directory(u_long index);#ifdef SANITYvoidmalloc_dump(FILE *fd){    struct pginfo **pd;    struct pgfree *pf;    int j;    pd = page_dir;    /* print out all the pages */    for(j=0;j<=last_index;j++) {	fprintf(fd,"%08lx %5d ",(j+malloc_origo) << malloc_pageshift,j);	if (pd[j] == MALLOC_NOT_MINE) {	    for(j++;j<=last_index && pd[j] == MALLOC_NOT_MINE;j++)		;	    j--;	    fprintf(fd,".. %5d not mine\n",	j);	} else if (pd[j] == MALLOC_FREE) {	    for(j++;j<=last_index && pd[j] == MALLOC_FREE;j++)		;	    j--;	    fprintf(fd,".. %5d free\n", j);	} else if (pd[j] == MALLOC_FIRST) {	    for(j++;j<=last_index && pd[j] == MALLOC_FOLLOW;j++)		;	    j--;	    fprintf(fd,".. %5d in use\n", j);	} else if (pd[j] < MALLOC_MAGIC) {	    fprintf(fd,"(%p)\n", pd[j]);	} else {	    fprintf(fd,"%p %d (of %d) x %d @ %p --> %p\n",		pd[j],pd[j]->free, pd[j]->total, 		pd[j]->size, pd[j]->page, pd[j]->next);	}    }    for(pf=free_list.next; pf; pf=pf->next) {	fprintf(fd,"Free: @%p [%p...%p[ %ld ->%p <-%p\n",		pf,pf->page,pf->end,pf->size,pf->prev,pf->next);	if (pf == pf->next) {		fprintf(fd,"Free_list loops.\n");		break;	}    }    /* print out various info */    fprintf(fd,"Minsize\t%d\n",malloc_minsize);    fprintf(fd,"Maxsize\t%ld\n",malloc_maxsize);    fprintf(fd,"Pagesize\t%ld\n",malloc_pagesize);    fprintf(fd,"Pageshift\t%ld\n",malloc_pageshift);    fprintf(fd,"FirstPage\t%ld\n",malloc_origo);    fprintf(fd,"LastPage\t%ld %lx\n",last_index+malloc_pageshift,	(last_index + malloc_pageshift) << malloc_pageshift);    fprintf(fd,"Break\t%ld\n",(u_long)sbrk(0) >> malloc_pageshift);}static void wrterror(char *fmt, ...){    char *q = "malloc() error: ";    char buf[100];    va_list ap;    suicide = 1;    va_start(ap, fmt);    PR_vsnprintf(buf, sizeof(buf), fmt, ap);    va_end(ap);    fputs(q, stderr);    fputs(buf, stderr);    malloc_dump(stderr);    PR_Abort();}static void wrtwarning(char *fmt, ...){    char *q = "malloc() warning: ";    char buf[100];    va_list ap;    va_start(ap, fmt);    PR_vsnprintf(buf, sizeof(buf), fmt, ap);    va_end(ap);    fputs(q, stderr);    fputs(buf, stderr);}#endif /* SANITY *//* * Allocate a number of pages from the OS */static caddr_tmap_pages(int pages, int update){    caddr_t result,tail;    result = ((caddr_t)sbrk(0)) + malloc_pagemask - 1;    result = (caddr_t) ((u_long)result & ~malloc_pagemask);    tail = result + (pages << malloc_pageshift);    if (!brk(tail)) {	last_index = ((u_long)tail >> malloc_pageshift) - malloc_origo -1;	malloc_brk = tail;	TRACE(("%6d S %p .. %p\n",malloc_event++, result, tail));	if (!update || last_index < malloc_ninfo ||	  extend_page_directory(last_index))	    return result;    }    TRACE(("%6d s %d %p %d\n",malloc_event++,pages,sbrk(0),errno));#ifdef EXTRA_SANITY    wrterror("map_pages fails\n");#endif    return 0;}#define set_bit(_pi,_bit) \    (_pi)->bits[(_bit)/MALLOC_BITS] |= 1L<<((_bit)%MALLOC_BITS)#define clr_bit(_pi,_bit) \    (_pi)->bits[(_bit)/MALLOC_BITS] &= ~(1L<<((_bit)%MALLOC_BITS));#define tst_bit(_pi,_bit) \    ((_pi)->bits[(_bit)/MALLOC_BITS] & (1L<<((_bit)%MALLOC_BITS)))/* * Extend page directory */static intextend_page_directory(u_long index){    struct  pginfo **young, **old;    int i;    TRACE(("%6d E %lu\n",malloc_event++,index));        /* Make it this many pages */    i = index * sizeof *page_dir;    i /= malloc_pagesize;    i += 2;    /* Get new pages, if you used this much mem you don't care :-) */    young = (struct pginfo**) map_pages(i,0);    if (!young)	return 0;    /* Copy the old stuff */    memset(young, 0, i * malloc_pagesize);    memcpy(young, page_dir,	    malloc_ninfo * sizeof *page_dir);    /* register the new size */    malloc_ninfo = i * malloc_pagesize / sizeof *page_dir;    /* swap the pointers */    old = page_dir;    page_dir = young;    /* Mark the pages */    index = ((u_long)young >> malloc_pageshift) - malloc_origo;    page_dir[index] = MALLOC_FIRST;    while (--i) {	page_dir[++index] = MALLOC_FOLLOW;    }    /* Now free the old stuff */    _PR_UnlockedFree(old);    return 1;}/* * Set entry in page directory. * Extend page directory if need be. */static intset_pgdir(void *ptr, struct  pginfo *info){    u_long index = ((u_long)ptr >> malloc_pageshift) - malloc_origo;    if (index >= malloc_ninfo && !extend_page_directory(index))	return 0;    page_dir[index] = info;    return 1;}/* * Initialize the world */static voidmalloc_init (void){    int i;    char *p;    TRACE(("%6d I\n",malloc_event++));#ifdef DEBUG    for (p=getenv("MALLOC_OPTIONS"); p && *p; p++) {	switch (*p) {	    case 'a': malloc_abort = 0; break;	    case 'A': malloc_abort = 1; break;	    case 'd': malloc_stats = 0; break;	    case 'D': malloc_stats = 1; break;	    case 'r': malloc_realloc = 0; break;	    case 'R': malloc_realloc = 1; break;	    default:		wrtwarning("Unknown chars in MALLOC_OPTIONS\n");		break;	}    }#endif#ifndef malloc_pagesize    /* determine our pagesize */    malloc_pagesize = getpagesize();#endif /* malloc_pagesize */#ifndef malloc_pageshift    /* determine how much we shift by to get there */    for (i = malloc_pagesize; i > 1; i >>= 1)	malloc_pageshift++;#endif /* malloc_pageshift */#ifndef malloc_cache    malloc_cache = 50 << malloc_pageshift;	#endif /* malloc_cache */#ifndef malloc_minsize    /*     * find the smallest size allocation we will bother about.     * this is determined as the smallest allocation that can hold     * it's own pginfo;     */    i = 2;    for(;;) {	int j;	/* Figure out the size of the bits */	j = malloc_pagesize/i;	j /= 8;	if (j < sizeof(u_long))		j = sizeof (u_long);	if (sizeof(struct pginfo) + j - sizeof (u_long) <= i)		break;	i += i;    }    malloc_minsize = i;#endif /* malloc_minsize */    /* Allocate one page for the page directory */    page_dir = (struct pginfo **) map_pages(1,0);#ifdef SANITY    if (!page_dir)	wrterror("fatal: my first mmap failed.  (check limits ?)\n");#endif    /*     * We need a maximum of malloc_pageshift buckets, steal these from the     * front of the page_directory;     */    malloc_origo = (u_long) page_dir >> malloc_pageshift;    malloc_origo -= malloc_pageshift;    /* Clear it */    memset(page_dir,0,malloc_pagesize);    /* Find out how much it tells us */    malloc_ninfo = malloc_pagesize / sizeof *page_dir;    /* Plug the page directory into itself */    i = set_pgdir(page_dir,MALLOC_FIRST);#ifdef SANITY    if (!i)	wrterror("fatal: couldn't set myself in the page directory\n");#endif    /* Been here, done that */    initialized++;}/* * Allocate a number of complete pages */static void *malloc_pages(size_t size){    void *p,*delay_free = 0;    int i;    struct pgfree *pf;    u_long index;    /* How many pages ? */    size += (malloc_pagesize-1);    size &= ~malloc_pagemask;    p = 0;    /* Look for free pages before asking for more */    for(pf = free_list.next; pf; pf = pf->next) {#ifdef EXTRA_SANITY	if (pf->page == pf->end)	    wrterror("zero entry on free_list\n");	if (pf->page > pf->end) {	    TRACE(("%6d !s %p %p %p <%d>\n",malloc_event++,		pf,pf->page,pf->end,__LINE__));	    wrterror("sick entry on free_list\n");	}	if ((void*)pf->page >= (void*)sbrk(0))	    wrterror("entry on free_list past brk\n");	if (page_dir[((u_long)pf->page >> malloc_pageshift) - malloc_origo] 	  != MALLOC_FREE) {	    TRACE(("%6d !f %p %p %p <%d>\n",malloc_event++,		pf,pf->page,pf->end,__LINE__));	    wrterror("non-free first page on free-list\n");	}	if (page_dir[((u_long)pf->end >> malloc_pageshift) - 1 - malloc_origo] 	  != MALLOC_FREE)	    wrterror("non-free last page on free-list\n");#endif /* EXTRA_SANITY */	if (pf->size < size) 	    continue;	else if (pf->size == size) {	    p = pf->page;	    if (pf->next)		    pf->next->prev = pf->prev;	    pf->prev->next = pf->next;	    delay_free = pf;	    break;	} else {	    p = pf->page;	    pf->page += size;	    pf->size -= size;	    break;        }    }#ifdef EXTRA_SANITY

⌨️ 快捷键说明

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