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

📄 elib_malloc.c

📁 OTP是开放电信平台的简称
💻 C
📖 第 1 页 / 共 4 页
字号:
/* ``The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved via the world wide web at http://www.erlang.org/. *  * 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 Initial Developer of the Original Code is Ericsson Utvecklings AB. * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings * AB. All Rights Reserved.'' *  *     $Id$ *//*** Description: Faster malloc().*/#ifdef HAVE_CONFIG_H#  include "config.h"#endif#include "sys.h"#ifdef ENABLE_ELIB_MALLOC#undef THREAD_SAFE_ELIB_MALLOC#ifdef USE_THREADS#define THREAD_SAFE_ELIB_MALLOC 1#else#define THREAD_SAFE_ELIB_MALLOC 0#endif#include "erl_driver.h"#include "erl_threads.h"#include "elib_stat.h"#include <stdio.h>#include <stdlib.h>/* To avoid clobbering of names becaure of reclaim on VxWorks,   we undefine all possible malloc, calloc etc. */#undef malloc#undef calloc#undef free#undef realloc#define ELIB_INLINE         /* inline all possible functions */#ifndef ELIB_ALIGN#define ELIB_ALIGN             sizeof(double)#endif#ifndef ELIB_HEAP_SIZE#define ELIB_HEAP_SIZE         (64*1024)  /* Default 64K */#endif#ifndef ELIB_HEAP_INCREAMENT#define ELIB_HEAP_INCREAMENT   (32*1024)  /* Default 32K */#endif#ifndef ELIB_FAILURE#define ELIB_FAILURE    abort()#endif#undef ASSERT#ifdef DEBUG#define ASSERT(B) \ ((void) ((B) ? 1 : (fprintf(stderr, "%s:%d: Assertion failed: %s\n", \			     __FILE__, __LINE__, #B), abort(), 0)))#else#define ASSERT(B) ((void) 1)#endif#ifndef USE_RECURSIVE_MALLOC_MUTEX#define USE_RECURSIVE_MALLOC_MUTEX 0#endif#if USE_RECURSIVE_MALLOC_MUTEXstatic erts_mtx_t malloc_mutex = ERTS_REC_MTX_INITER;#else /* #if USE_RECURSIVE_MALLOC_MUTEX */static erts_mtx_t malloc_mutex = ERTS_MTX_INITER;#if THREAD_SAFE_ELIB_MALLOCstatic erts_cnd_t  malloc_cond  = ERTS_CND_INITER;#endif#endif  /* #if USE_RECURSIVE_MALLOC_MUTEX */typedef unsigned long EWord;       /* Assume 32-bit in this implementation */typedef unsigned short EHalfWord;  /* Assume 16-bit in this implementation */typedef unsigned char EByte;       /* Assume 8-bit byte */#define elib_printf fprintf#define elib_putc   fputc#if defined(__STDC__) || defined(__WIN32__)#define CONCAT(x,y) x##y#else#define CONCAT(x,y) x/**/y#endif#ifdef ELIB_DEBUG#define ELIB_PREFIX(fun, args) CONCAT(elib__,fun) args#else#define ELIB_PREFIX(fun, args) CONCAT(elib_,fun) args#endif#if defined(__STDC__)void *ELIB_PREFIX(malloc, (size_t));void *ELIB_PREFIX(calloc, (size_t, size_t));void ELIB_PREFIX(cfree, (EWord *));void ELIB_PREFIX(free, (EWord *));void *ELIB_PREFIX(realloc, (EWord *, size_t));void* ELIB_PREFIX(memresize, (EWord *, int));void* ELIB_PREFIX(memalign, (int, int));void* ELIB_PREFIX(valloc, (int));void* ELIB_PREFIX(pvalloc, (int));int ELIB_PREFIX(memsize, (EWord *));/* Extern interfaces used by VxWorks */size_t elib_sizeof(void *);void elib_init(EWord *, EWord);void elib_force_init(EWord *, EWord);#endif#if defined(__STDC__)/* define prototypes for missing */void* memalign(size_t a, size_t s);void* pvalloc(size_t nb);void* memresize(void *p, int nb);int memsize(void *p);#endif/* bytes to pages */#define PAGES(x)      (((x)+page_size-1) / page_size)#define PAGE_ALIGN(p) ((char*)((((EWord)(p))+page_size-1)&~(page_size-1)))/* bytes to words */#define WORDS(x)      (((x)+sizeof(EWord)-1) / sizeof(EWord))/* Align an address */#define ALIGN(p)     ((EWord*)((((EWord)(p)+ELIB_ALIGN-1)&~(ELIB_ALIGN-1))))/* Calculate the size needed to keep alignment */#define ALIGN_BSZ(nb)  ((nb+sizeof(EWord)+ELIB_ALIGN-1) & ~(ELIB_ALIGN-1))#define ALIGN_WSZ(nb)  WORDS(ALIGN_BSZ(nb))#define ALIGN_SIZE(nb) (ALIGN_WSZ(nb) - 1)/* PARAMETERS */#if defined(ELIB_HEAP_SBRK)#undef PAGE_SIZE/* Get the system page size (NEED MORE DEFINES HERE) */#ifdef _SC_PAGESIZE#define PAGE_SIZE   sysconf(_SC_PAGESIZE)#elif defined(_MSC_VER)#  ifdef _M_ALPHA#    define PAGE_SIZE      0x2000#  else#    define PAGE_SIZE      0x1000#  endif#else#define PAGE_SIZE   getpagesize()#endif#define ELIB_EXPAND(need)  expand_sbrk(need)static FUNCTION(int, expand_sbrk, (EWord));#elif defined(ELIB_HEAP_FIXED)#define PAGE_SIZE 1024#define ELIB_EXPAND(need) -1static EWord fix_heap[WORDS(ELIB_HEAP_SIZE)];#elif defined(ELIB_HEAP_USER)#define PAGE_SIZE 1024#define ELIB_EXPAND(need) -1#else#error "ELIB HEAP TYPE NOT SET"#endif#define STAT_ALLOCED_BLOCK(SZ)		\do {					\    tot_allocated += (SZ);		\    if (max_allocated < tot_allocated)	\	max_allocated = tot_allocated;	\} while (0)#define STAT_FREED_BLOCK(SZ)		\do {					\    tot_allocated -= (SZ);		\} while (0)static int max_allocated = 0;static int tot_allocated = 0;static EWord* eheap;        /* Align heap start */static EWord* eheap_top;    /* Point to end of heap */EWord page_size = 0;        /* Set by elib_init */#if defined(ELIB_DEBUG) || defined(DEBUG)#define ALIGN_CHECK(a, p)						\ do {									\    if ((EWord)(p) & (a-1)) {						\	elib_printf(stderr,						\		    "RUNTIME ERROR: bad alignment (0x%lx:%d:%d)\n",	\		    (unsigned long) (p), (int) a, __LINE__);			\	ELIB_FAILURE;							\    }									\  } while(0)#define ELIB_ALIGN_CHECK(p) ALIGN_CHECK(ELIB_ALIGN, p)#else#define ALIGN_CHECK(a, p)#define ELIB_ALIGN_CHECK(p)#endif#define DYNAMIC 32/*** Free block layout**   1 1          30**  +--------------------------+**  |F|P|        Size          |**  +--------------------------+**** Where F is the free bit**       P is the free above bit**       Size is messured in words and does not include the hdr word**** If block is on the free list the size is also stored last in the block.** */typedef struct _free_block FreeBlock;struct _free_block {    EWord hdr;    Uint flags;    FreeBlock* parent;    FreeBlock* left;    FreeBlock* right;    EWord v[1];};typedef struct _allocated_block {    EWord hdr;    EWord v[5];} AllocatedBlock;/* * Interface to tree routines. */typedef Uint Block_t;static Block_t*	get_free_block(Uint);static void link_free_block(Block_t *);static void unlink_free_block(Block_t *del);#define FREE_BIT       0x80000000#define FREE_ABOVE_BIT 0x40000000#define SIZE_MASK      0x3fffffff     /* 2^30 words = 2^32 bytes *//* Work on both FreeBlock and AllocatedBlock */#define SIZEOF(p)         ((p)->hdr & SIZE_MASK)#define IS_FREE(p)        (((p)->hdr & FREE_BIT) != 0)#define IS_FREE_ABOVE(p)  (((p)->hdr & FREE_ABOVE_BIT) != 0)/* Given that we have a free block above find its size */#define SIZEOF_ABOVE(p)    *(((EWord*) (p)) - 1)#define MIN_BLOCK_SIZE      (sizeof(FreeBlock)/sizeof(EWord))#define MIN_WORD_SIZE       (MIN_BLOCK_SIZE-1)#define MIN_BYTE_SIZE       (sizeof(FreeBlock)-sizeof(EWord))#define MIN_ALIGN_SIZE      ALIGN_SIZE(MIN_BYTE_SIZE)static AllocatedBlock* heap_head = 0;static AllocatedBlock* heap_tail = 0;static EWord eheap_size = 0;static int heap_locked;static int elib_need_init = 1;#if THREAD_SAFE_ELIB_MALLOCstatic int elib_is_initing = 0;#endiftypedef FreeBlock RBTree_t;static RBTree_t* root = NULL;static FUNCTION(void, deallocate, (AllocatedBlock*, int));/* * Unlink a free block */#define mark_allocated(p, szp) do { \      (p)->hdr = ((p)->hdr & FREE_ABOVE_BIT) | (szp); \      (p)->v[szp] &= ~FREE_ABOVE_BIT; \   } while(0)#define mark_free(p, szp) do { \      (p)->hdr = FREE_BIT | (szp); \      ((FreeBlock *)p)->v[szp-sizeof(FreeBlock)/sizeof(EWord)+1] = (szp); \   } while(0)#if 0/* Help macros to log2 */#define LOG_1(x)  (((x) > 1) ? 1 : 0)#define LOG_2(x)  (((x) > 3) ? 2+LOG_1((x) >> 2) : LOG_1(x))#define LOG_4(x)  (((x) > 15) ? 4+LOG_2((x) >> 4) : LOG_2(x))#define LOG_8(x)  (((x) > 255) ? 8+LOG_4((x)>>8) : LOG_4(x))#define LOG_16(x) (((x) > 65535) ? 16+LOG_8((x)>>16) : LOG_8(x))#define log2(x)   LOG_16(x)#endif/* * Split a block to be allocated. * Mark block as ALLOCATED and clear * FREE_ABOVE_BIT on next block * * nw is SIZE aligned and szp is SIZE aligned + 1 */static voidsplit_block(FreeBlock* p, EWord nw, EWord szp){    EWord szq;    FreeBlock* q;    szq = szp - nw;    /* Preserve FREE_ABOVE bit in p->hdr !!! */    if (szq >= MIN_ALIGN_SIZE+1) {	szq--;	p->hdr = (p->hdr & FREE_ABOVE_BIT) | nw;	q = (FreeBlock*) (((EWord*) p) + nw + 1);	mark_free(q, szq);	link_free_block((Block_t *) q);	q = (FreeBlock*) (((EWord*) q) + szq + 1);	q->hdr |= FREE_ABOVE_BIT;    }    else {	mark_allocated((AllocatedBlock*)p, szp);    }}/* * Find a free block */static FreeBlock*alloc_block(EWord nw){    for (;;) {	FreeBlock* p = (FreeBlock *) get_free_block(nw);	if (p != NULL) {	    return p;	} else if (ELIB_EXPAND(nw+MIN_WORD_SIZE)) {	    return 0;	}    }}size_t elib_sizeof(void *p){    AllocatedBlock* pp;    if (p != 0) {	pp = (AllocatedBlock*) (((char *)p)-1);	return SIZEOF(pp);    }    return 0;}static void locked_elib_init(EWord*, EWord);static void init_elib_malloc(EWord*, EWord);/*** Initialize the elib** The addr and sz is only used when compiled with EXPAND_ADDR *//* Not static, this is used by VxWorks */void elib_init(EWord* addr, EWord sz){    if (!elib_need_init)	return;    erts_mtx_lock(&malloc_mutex);    locked_elib_init(addr, sz);    erts_mtx_unlock(&malloc_mutex);}static void locked_elib_init(EWord* addr, EWord sz){    if (!elib_need_init)	return;#if THREAD_SAFE_ELIB_MALLOC#if !USE_RECURSIVE_MALLOC_MUTEX    {	static erts_tid_t initer_tid;	if(elib_is_initing) {	    if(erts_equal_tids(initer_tid, erts_thr_self()))		return;	    /* Wait until initializing thread is done with initialization */	    while(elib_need_init)		erts_cnd_wait(&malloc_cond, &malloc_mutex);	    return;	}	else {	    initer_tid = erts_thr_self();	    elib_is_initing = 1;	}    }#else    if(elib_is_initing)	return;    elib_is_initing = 1;#endif#endif /* #if THREAD_SAFE_ELIB_MALLOC */    /* Do the actual initialization of the malloc implementation */    init_elib_malloc(addr, sz);#if THREAD_SAFE_ELIB_MALLOC#if !USE_RECURSIVE_MALLOC_MUTEX    erts_mtx_unlock(&malloc_mutex);#endif    /* Recursive calls to malloc are allowed here... */    erts_mtx_set_forksafe(&malloc_mutex);#if !USE_RECURSIVE_MALLOC_MUTEX    erts_mtx_lock(&malloc_mutex);    elib_is_initing = 0;#endif#endif /* #if THREAD_SAFE_ELIB_MALLOC */    elib_need_init = 0;#if THREAD_SAFE_ELIB_MALLOC && !USE_RECURSIVE_MALLOC_MUTEX    erts_cnd_broadcast(&malloc_cond);#endif}static void init_elib_malloc(EWord* addr, EWord sz){    int i;    FreeBlock* freep;    EWord tmp_sz;#ifdef ELIB_HEAP_SBRK    char* top;    EWord n;#endif    max_allocated = 0;    tot_allocated = 0;    root = NULL;    /* Get the page size (may involve system call!!!) */    page_size = PAGE_SIZE;#if defined(ELIB_HEAP_SBRK)    sz = PAGES(ELIB_HEAP_SIZE)*page_size;    if ((top = (char*) sbrk(0)) == (char*)-1) {	elib_printf(stderr, "could not initialize elib, sbrk(0)");	ELIB_FAILURE;    }    n = PAGE_ALIGN(top) - top;    if ((top = (char*) sbrk(n)) == (char*)-1) {	elib_printf(stderr, "could not initialize elib, sbrk(n)");	ELIB_FAILURE;    }    if ((eheap = (EWord*) sbrk(sz)) == (EWord*)-1) {	elib_printf(stderr, "could not initialize elib, sbrk(SIZE)");	ELIB_FAILURE;    }    sz = WORDS(ELIB_HEAP_SIZE);#elif defined(ELIB_HEAP_FIXED)    eheap = fix_heap;    sz = WORDS(ELIB_HEAP_SIZE);#elif defined(ELIB_HEAP_USER)    eheap = addr;    sz = WORDS(sz);#else    return -1;#endif    eheap_size = 0;    /* Make sure that the first word of the heap_head is aligned */    addr = ALIGN(eheap+1);    sz -= ((addr - 1) - eheap);      /* Subtract unusable size */    eheap_top = eheap = addr - 1;    /* Set new aligned heap start */    eheap_top[sz-1] = 0;	     /* Heap stop mark */    addr = eheap;    heap_head = (AllocatedBlock*) addr;    heap_head->hdr = MIN_ALIGN_SIZE;    for (i = 0; i < MIN_ALIGN_SIZE; i++)	heap_head->v[i] = 0;    addr += (MIN_ALIGN_SIZE+1);    freep = (FreeBlock*) addr;    tmp_sz = sz - (((MIN_ALIGN_SIZE+1) + MIN_BLOCK_SIZE) + 1 + 1);    mark_free(freep, tmp_sz);    link_free_block((Block_t *) freep);    /* No need to align heap tail */    heap_tail = (AllocatedBlock*) &eheap_top[sz-MIN_BLOCK_SIZE-1];    heap_tail->hdr = FREE_ABOVE_BIT | MIN_WORD_SIZE;    heap_tail->v[0] = 0;    heap_tail->v[1] = 0;    heap_tail->v[2] = 0;    eheap_top += sz;    eheap_size += sz;    heap_locked = 0;}#ifdef ELIB_HEAP_USERvoid elib_force_init(EWord* addr, EWord sz){    elib_need_init = 1;    elib_init(addr,sz);}#endif#ifdef ELIB_HEAP_SBRK/*** need in number of words (should include head and tail words)*/static int expand_sbrk(EWord sz){    EWord* p;    EWord  bytes = sz * sizeof(EWord);    EWord  size;    AllocatedBlock* tail;    if (bytes < ELIB_HEAP_SIZE)	size = PAGES(ELIB_HEAP_INCREAMENT)*page_size;    else	size = PAGES(bytes)*page_size;    if ((p = (EWord*) sbrk(size)) == ((EWord*) -1))	return -1;    if (p != eheap_top) {	elib_printf(stderr, "panic: sbrk moved\n");	ELIB_FAILURE;    }    sz = WORDS(size);

⌨️ 快捷键说明

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