📄 dlmalloc.cxx
字号:
//==========================================================================//// dlmalloc.cxx//// Port of Doug Lea's malloc implementation////==========================================================================//####ECOSGPLCOPYRIGHTBEGIN####// -------------------------------------------// This file is part of eCos, the Embedded Configurable Operating System.// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.//// eCos is free software; you can redistribute it and/or modify it under// the terms of the GNU General Public License as published by the Free// Software Foundation; either version 2 or (at your option) any later version.//// eCos is distributed in the hope that it will be useful, but WITHOUT ANY// WARRANTY; without even the implied warranty of MERCHANTABILITY or// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License// for more details.//// You should have received a copy of the GNU General Public License along// with eCos; if not, write to the Free Software Foundation, Inc.,// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.//// As a special exception, if other files instantiate templates or use macros// or inline functions from this file, or you compile this file and link it// with other works to produce a work based on this file, this file does not// by itself cause the resulting work to be covered by the GNU General Public// License. However the source code for this file must still be made available// in accordance with section (3) of the GNU General Public License.//// This exception does not invalidate any other reasons why a work based on// this file might be covered by the GNU General Public License.//// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.// at http://sources.redhat.com/ecos/ecos-license/// -------------------------------------------//####ECOSGPLCOPYRIGHTEND####//==========================================================================//#####DESCRIPTIONBEGIN####//// Author(s): Doug Lea (dl at g.oswego.edu), jlarmour// Contributors: // Date: 2000-06-18// Purpose: Doug Lea's malloc implementation// Description: Doug Lea's malloc has been ported to eCos. This file// provides the implementation in a way acceptable to eCos.// Substantial amounts of unnecessary bits (to eCos) of the// original implementation have been removed to make the// code more tractable. Note this may make a number of the// comments appear to make little sense, or no longer apply!// In particular, mmap support is removed entirely.// Also the memory is "sbrked" all at once at the// beginning, covering the entire memory region given at// construction, and there can be no more afterwards.// Usage: #include <cyg/memalloc/dlmalloc.hxx>// ////####DESCRIPTIONEND####////==========================================================================// DOCUMENTATION FROM ORIGINAL FILE:// (some now irrelevant parts elided)//----------------------------------------------------------------------------/* A version of malloc/free/realloc written by Doug Lea and released to the public domain. Send questions/comments/complaints/performance data to dl at cs.oswego.edu* VERSION 2.6.6 Sun Mar 5 19:10:03 2000 Doug Lea (dl at gee) Note: There may be an updated version of this malloc obtainable at ftp://g.oswego.edu/pub/misc/malloc.c Check before installing!* Why use this malloc? This is not the fastest, most space-conserving, most portable, or most tunable malloc ever written. However it is among the fastest while also being among the most space-conserving, portable and tunable. Consistent balance across these factors results in a good general-purpose allocator. For a high-level description, see http://g.oswego.edu/dl/html/malloc.html* Synopsis of public routines (Much fuller descriptions are contained in the program documentation below.)[ these have of course been renamed in the eCos port ]a malloc(size_t n); Return a pointer to a newly allocated chunk of at least n bytes, or null if no space is available. free(Void_t* p); Release the chunk of memory pointed to by p, or no effect if p is null. realloc(Void_t* p, size_t n); Return a pointer to a chunk of size n that contains the same data as does chunk p up to the minimum of (n, p's size) bytes, or null if no space is available. The returned pointer may or may not be the same as p. If p is null, equivalent to malloc. realloc of zero bytes calls free(p)* Vital statistics: Alignment: 8-byte 8 byte alignment is currently hardwired into the design. This seems to suffice for all current machines and C compilers. Assumed pointer representation: 4 or 8 bytes Code for 8-byte pointers is untested by me but has worked reliably by Wolfram Gloger, who contributed most of the changes supporting this. Assumed size_t representation: 4 or 8 bytes Note that size_t is allowed to be 4 bytes even if pointers are 8. Minimum overhead per allocated chunk: 4 or 8 bytes Each malloced chunk has a hidden overhead of 4 bytes holding size and status information. Minimum allocated size: 4-byte ptrs: 16 bytes (including 4 overhead) 8-byte ptrs: 24/32 bytes (including, 4/8 overhead) When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte ptrs but 4 byte size) or 24 (for 8/8) additional bytes are needed; 4 (8) for a trailing size field and 8 (16) bytes for free list pointers. Thus, the minimum allocatable size is 16/24/32 bytes. Even a request for zero bytes (i.e., malloc(0)) returns a pointer to something of the minimum allocatable size. Maximum allocated size: 4-byte size_t: 2^31 - 8 bytes 8-byte size_t: 2^63 - 16 bytes It is assumed that (possibly signed) size_t bit values suffice to represent chunk sizes. `Possibly signed' is due to the fact that `size_t' may be defined on a system as either a signed or an unsigned type. To be conservative, values that would appear as negative numbers are avoided. Requests for sizes with a negative sign bit when the request size is treaded as a long will return null. Maximum overhead wastage per allocated chunk: normally 15 bytes Alignnment demands, plus the minimum allocatable size restriction make the normal worst-case wastage 15 bytes (i.e., up to 15 more bytes will be allocated than were requested in malloc), with one exception: because requests for zero bytes allocate non-zero space, the worst case wastage for a request of zero bytes is 24 bytes.* Limitations Here are some features that are NOT currently supported * No user-definable hooks for callbacks and the like. * No automated mechanism for fully checking that all accesses to malloced memory stay within their bounds. * No support for compaction.* Synopsis of compile-time options: People have reported using previous versions of this malloc on all versions of Unix, sometimes by tweaking some of the defines below. It has been tested most extensively on Solaris and Linux. It is also reported to work on WIN32 platforms. People have also reported adapting this malloc for use in stand-alone embedded systems. The implementation is in straight, hand-tuned ANSI C. Among other consequences, it uses a lot of macros. Because of this, to be at all usable, this code should be compiled using an optimizing compiler (for example gcc -O2) that can simplify expressions and control paths. CYGDBG_MEMALLOC_ALLOCATOR_DLMALLOC_DEBUG (default: NOT defined) Define to enable debugging. Adds fairly extensive assertion-based checking to help track down memory errors, but noticeably slows down execution. MALLOC_LOCK (default: NOT defined) MALLOC_UNLOCK (default: NOT defined) Define these to C expressions which are run to lock and unlock the malloc data structures. Calls may be nested; that is, MALLOC_LOCK may be called more than once before the corresponding MALLOC_UNLOCK calls. MALLOC_LOCK must avoid waiting for a lock that it already holds. MALLOC_ALIGNMENT (default: NOT defined) Define this to 16 if you need 16 byte alignment instead of 8 byte alignment which is the normal default. SIZE_T_SMALLER_THAN_LONG (default: NOT defined) Define this when the platform you are compiling has sizeof(long) > sizeof(size_t). The option causes some extra code to be generated to handle operations that use size_t operands and have long results. INTERNAL_SIZE_T (default: size_t) Define to a 32-bit type (probably `unsigned int') if you are on a 64-bit machine, yet do not want or need to allow malloc requests of greater than 2^31 to be handled. This saves space, especially for very small chunks.*///----------------------------------------------------------------------------/* Preliminaries */#include <pkgconf/memalloc.h> // configuration header#include <pkgconf/infra.h> // CYGDBG_USE_ASSERTS#include <cyg/infra/cyg_type.h> // types#include <cyg/infra/cyg_ass.h> // assertions#include <stddef.h> // for size_t#include <cyg/memalloc/dlmalloc.hxx>//#include <cyg/infra/diag.h>/* Debugging: Because freed chunks may be overwritten with link fields, this malloc will often die when freed memory is overwritten by user programs. This can be very effective (albeit in an annoying way) in helping track down dangling pointers. If you compile with CYGDBG_MEMALLOC_ALLOCATOR_DLMALLOC_DEBUG enabled, a number of assertion checks are enabled that will catch more memory errors. You probably won't be able to make much sense of the actual assertion errors, but they should help you locate incorrectly overwritten memory. The checking is fairly extensive, and will slow down execution noticeably. Calling get_status() with DEBUG set will attempt to check every allocated and free chunk in the course of computing the summmaries. Setting CYGDBG_MEMALLOC_ALLOCATOR_DLMALLOC_DEBUG may also be helpful if you are trying to modify this code. The assertions in the check routines spell out in more detail the assumptions and invariants underlying the algorithms.*/#ifdef CYGDBG_MEMALLOC_ALLOCATOR_DLMALLOC_DEBUG# define ASSERT(x) CYG_ASSERTC( x )#else# define ASSERT(x) ((void)0)#endif/* Define MALLOC_LOCK and MALLOC_UNLOCK to C expressions to run to lock and unlock the malloc data structures. MALLOC_LOCK may be called recursively. */#ifndef MALLOC_LOCK#define MALLOC_LOCK#endif#ifndef MALLOC_UNLOCK#define MALLOC_UNLOCK#endif/* INTERNAL_SIZE_T is the word-size used for internal bookkeeping of chunk sizes. On a 64-bit machine, you can reduce malloc overhead by defining INTERNAL_SIZE_T to be a 32 bit `unsigned int' at the expense of not being able to handle requests greater than 2^31. This limitation is hardly ever a concern; you are encouraged to set this. However, the default version is the same as size_t.*/ #ifndef INTERNAL_SIZE_T#define INTERNAL_SIZE_T Cyg_Mempool_dlmalloc_Implementation::Cyg_dlmalloc_size_t#endif/* Following is needed on implementations whereby long > size_t. The problem is caused because the code performs subtractions of size_t values and stores the result in long values. In the case where long > size_t and the first value is actually less than the second value, the resultant value is positive. For example, (long)(x - y) where x = 0 and y is 1 ends up being 0x00000000FFFFFFFF which is 2*31 - 1 instead of 0xFFFFFFFFFFFFFFFF. This is due to the fact that assignment from unsigned to signed won't sign extend.*/#ifdef SIZE_T_SMALLER_THAN_LONG#define long_sub_size_t(x, y) ( (x < y) ? -((long)(y - x)) : (x - y) );#else#define long_sub_size_t(x, y) ( (long)(x - y) )#endif#ifdef CYGIMP_MEMALLOC_ALLOCATOR_DLMALLOC_USE_MEMCPY#include <string.h> // memcpy, memset/* The following macros are only invoked with (2n+1)-multiples of INTERNAL_SIZE_T units, with a positive integer n. This is exploited for fast inline execution when n is small. */#define MALLOC_ZERO(charp, nbytes) \do { \ INTERNAL_SIZE_T mzsz = (nbytes); \ if(mzsz <= 9*sizeof(mzsz)) { \ INTERNAL_SIZE_T* mz = (INTERNAL_SIZE_T*) (charp); \ if(mzsz >= 5*sizeof(mzsz)) { *mz++ = 0; \ *mz++ = 0; \ if(mzsz >= 7*sizeof(mzsz)) { *mz++ = 0; \ *mz++ = 0; \ if(mzsz >= 9*sizeof(mzsz)) { *mz++ = 0; \ *mz++ = 0; }}} \ *mz++ = 0; \ *mz++ = 0; \ *mz = 0; \ } else memset((charp), 0, mzsz); \} while(0)#define MALLOC_COPY(dest,src,nbytes) \do { \ INTERNAL_SIZE_T mcsz = (nbytes); \ if(mcsz <= 9*sizeof(mcsz)) { \ INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) (src); \ INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) (dest); \ if(mcsz >= 5*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \ *mcdst++ = *mcsrc++; \ if(mcsz >= 7*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \ *mcdst++ = *mcsrc++; \ if(mcsz >= 9*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \ *mcdst++ = *mcsrc++; }}} \ *mcdst++ = *mcsrc++; \ *mcdst++ = *mcsrc++; \ *mcdst = *mcsrc ; \ } else memcpy(dest, src, mcsz); \} while(0)#else /* !CYGIMP_MEMALLOC_ALLOCATOR_DLMALLOC_USE_MEMCPY *//* Use Duff's device for good zeroing/copying performance. */#define MALLOC_ZERO(charp, nbytes) \do { \ INTERNAL_SIZE_T* mzp = (INTERNAL_SIZE_T*)(charp); \ long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \ if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \ switch (mctmp) { \ case 0: for(;;) { *mzp++ = 0; \ case 7: *mzp++ = 0; \ case 6: *mzp++ = 0; \ case 5: *mzp++ = 0; \ case 4: *mzp++ = 0; \ case 3: *mzp++ = 0; \ case 2: *mzp++ = 0; \ case 1: *mzp++ = 0; if(mcn <= 0) break; mcn--; } \ } \} while(0)#define MALLOC_COPY(dest,src,nbytes) \do { \ INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) src; \ INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) dest; \ long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \ if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \ switch (mctmp) { \ case 0: for(;;) { *mcdst++ = *mcsrc++; \ case 7: *mcdst++ = *mcsrc++; \ case 6: *mcdst++ = *mcsrc++; \ case 5: *mcdst++ = *mcsrc++; \ case 4: *mcdst++ = *mcsrc++; \ case 3: *mcdst++ = *mcsrc++; \ case 2: *mcdst++ = *mcsrc++; \ case 1: *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; } \ } \} while(0)#endif//----------------------------------------------------------------------------/* malloc_chunk details: (The following includes lightly edited explanations by Colin Plumb.) Chunks of memory are maintained using a `boundary tag' method as described in e.g., Knuth or Standish. (See the paper by Paul Wilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a survey of such techniques.) Sizes of free chunks are stored both in the front of each chunk and at the end. This makes consolidating fragmented chunks into bigger chunks very fast. The size fields also hold bits representing whether chunks are free or in use. An allocated chunk looks like this: chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Size of previous chunk, if allocated | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Size of chunk, in bytes |P| mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | User data starts here... . . . . (malloc_usable_space() bytes) . . |nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Size of chunk | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Where "chunk" is the front of the chunk for the purpose of most of the malloc code, but "mem" is the pointer that is returned to the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -