/* * malloc/free by O.Dreesen * * first TRY: * lists w/magics * and now the second TRY * let the kernel map all the stuff (if there is something to do) */ #define _GNU_SOURCE 1 #include #include #include #include #include #include #include #include //#include /* for PAGE_SIZE */ #ifndef PAGE_SIZE #define PAGE_SIZE sysconf (_SC_PAGESIZE) #endif #ifndef MREMAP_MAYMOVE #define MREMAP_MAYMOVE 1 #endif /* -- HELPER CODE --------------------------------------------------------- */ #ifndef MAP_FAILED #define MAP_FAILED ((void*)-1) #endif #ifndef NULL #define NULL ((void*)0) #endif typedef struct { void* next; size_t size; } __alloc_t; #define BLOCK_START(b) (((void*)(b))-sizeof(__alloc_t)) #define BLOCK_RET(b) (((void*)(b))+sizeof(__alloc_t)) #define MEM_BLOCK_SIZE PAGE_SIZE #define PAGE_ALIGN(s) (((s)+MEM_BLOCK_SIZE-1)&(unsigned long)(~(MEM_BLOCK_SIZE-1))) /* a simple mmap :) */ #if defined(__i386__) #define REGPARM(x) __attribute__((regparm(x))) #else #define REGPARM(x) #endif static void REGPARM(1) *do_mmap(size_t size) { return mmap(0, size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, (size_t)0); } /* -- SMALL MEM ----------------------------------------------------------- */ static __alloc_t* __small_mem[8]; #define __SMALL_NR(i) (MEM_BLOCK_SIZE/(i)) #define __MIN_SMALL_SIZE __SMALL_NR(256) /* 16 / 32 */ #define __MAX_SMALL_SIZE __SMALL_NR(2) /* 2048 / 4096 */ #define GET_SIZE(s) (__MIN_SMALL_SIZE<>__ind_shift(); while(size) { size>>=1; ++idx; } // } return idx; } /* small mem */ static void __small_free(void*_ptr,size_t _size) REGPARM(2); static void REGPARM(2) __small_free(void*_ptr,size_t _size) { __alloc_t* ptr=BLOCK_START(_ptr); size_t size=_size; size_t idx=get_index(size); #ifdef WANT_FREE_OVERWRITE memset(ptr,0x55,size); /* allways zero out small mem */ #else #if 0 memset(ptr,0,size); /* allways zero out small mem */ #endif #endif ptr->next=__small_mem[idx]; __small_mem[idx]=ptr; } static void* REGPARM(1) __small_malloc(size_t _size) { __alloc_t *ptr; size_t size=_size; size_t idx; idx=get_index(size); ptr=__small_mem[idx]; if (ptr==0) { /* no free blocks ? */ register int i,nr; ptr=do_mmap(MEM_BLOCK_SIZE); if (ptr==MAP_FAILED) return MAP_FAILED; __small_mem[idx]=ptr; nr=__SMALL_NR(size)-1; for (i=0;inext=(((void*)ptr)+size); ptr=ptr->next; } ptr->next=0; ptr=__small_mem[idx]; } /* get a free block */ __small_mem[idx]=ptr->next; ptr->next=0; return ptr; } /* -- PUBLIC FUNCTIONS ---------------------------------------------------- */ void free(void *ptr) { register size_t size; if (ptr) { size=((__alloc_t*)BLOCK_START(ptr))->size; if (size) { if (size<=__MAX_SMALL_SIZE) __small_free(ptr,size); else munmap(BLOCK_START(ptr),size); } } } void* malloc(size_t size) { __alloc_t* ptr; size_t need; if (!size) goto err_out; size+=sizeof(__alloc_t); if (sizesize=need; return BLOCK_RET(ptr); err_out: //(*__errno_location())=ENOMEM; return 0; } void* calloc(size_t nmemb, size_t _size) { register size_t size=_size*nmemb; if (nmemb && size/nmemb!=_size) { //(*__errno_location())=ENOMEM; return 0; } #ifdef WANT_FREE_OVERWRITE if (size<__MAX_SMALL_SIZE) { void* x=malloc(size); memset(x,0,size); return x; } else #endif return malloc(size); } void* realloc(void* ptr, size_t _size) { register size_t size=_size; if (ptr) { if (size) { __alloc_t* tmp=BLOCK_START(ptr); size+=sizeof(__alloc_t); if (sizesize!=size) { if ((tmp->size<=__MAX_SMALL_SIZE)) { void *new=malloc(_size); if (new) { register __alloc_t* foo=BLOCK_START(new); size=foo->size; if (size>tmp->size) size=tmp->size; if (size) memcpy(new,ptr,size-sizeof(__alloc_t)); free(ptr); } ptr=new; } else { register __alloc_t* foo; size=PAGE_ALIGN(size); foo=mremap(tmp,tmp->size,size,MREMAP_MAYMOVE); if (foo==MAP_FAILED) { retzero: //(*__errno_location())=ENOMEM; ptr=0; } else { foo->size=size; ptr=BLOCK_RET(foo); } } } } else { /* size==0 */ free(ptr); ptr = NULL; } } else { /* ptr==0 */ if (size) { ptr=malloc(size); } } return ptr; }