diff options
Diffstat (limited to 'lib/libc/stdlib/malloc.c')
| -rw-r--r-- | lib/libc/stdlib/malloc.c | 272 |
1 files changed, 120 insertions, 152 deletions
diff --git a/lib/libc/stdlib/malloc.c b/lib/libc/stdlib/malloc.c index 0b06473fed02..dc601ea78e96 100644 --- a/lib/libc/stdlib/malloc.c +++ b/lib/libc/stdlib/malloc.c @@ -6,7 +6,7 @@ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- * - * $Id: malloc.c,v 1.18.2.1 1996/12/30 01:35:15 alex Exp $ + * $Id: malloc.c,v 1.28 1997/07/02 19:33:23 phk Exp $ * */ @@ -22,15 +22,6 @@ #endif /* - * Defining MALLOC_STATS will enable you to call malloc_dump() and set - * the [dD] options in the MALLOC_OPTIONS environment variable. - * It has no run-time performance hit. - */ -#ifndef MALLOC_STATS -#undef MALLOC_STATS -#endif - -/* * What to use for Junk. This is the byte value we use to fill with * when the 'J' option is enabled. */ @@ -41,7 +32,7 @@ * * malloc_pageshift pagesize = 1 << malloc_pageshift * It's probably best if this is the native - * page size, but it shouldn't have to be. + * page size, but it doesn't have to be. * * malloc_minsize minimum size of an allocation in bytes. * If this is too small it's too much work @@ -51,27 +42,52 @@ * */ -#if defined(__i386__) && defined(__FreeBSD__) -# define malloc_pageshift 12U +#if defined(__FreeBSD__) +# if defined(__i386__) +# define malloc_pageshift 12U +# define malloc_minsize 16U +# endif +# define HAS_UTRACE +# if defined(_THREAD_SAFE) +# include <pthread.h> +# include "pthread_private.h" +# define THREAD_LOCK() pthread_mutex_lock(&malloc_lock) +# define THREAD_UNLOCK() pthread_mutex_unlock(&malloc_lock) + static struct pthread_mutex _malloc_lock = PTHREAD_MUTEX_INITIALIZER; + static pthread_mutex_t malloc_lock = &_malloc_lock; +# endif +#endif /* __FreeBSD__ */ + +#if defined(__sparc__) && defined(sun) +# define malloc_pageshirt 12U # define malloc_minsize 16U -#endif /* __i386__ && __FreeBSD__ */ +# define MAP_ANON (0) + static int fdzero; +# define MMAP_FD fdzero +# define INIT_MMAP() \ + { if ((fdzero=open("/dev/zero", O_RDWR, 0000)) == -1) \ + wrterror("open of /dev/zero"); } +# define MADV_FREE MADV_DONTNEED +#endif /* __sparc__ */ /* Insert your combination here... */ #if defined(__FOOCPU__) && defined(__BAROS__) # define malloc_pageshift 12U # define malloc_minsize 16U -#endif /* __i386__ && __FreeBSD__ */ +#endif /* __FOOCPU__ && __BAROS__ */ + /* * No user serviceable parts behind this point. */ +#include <sys/types.h> +#include <sys/mman.h> +#include <errno.h> +#include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/mman.h> /* * This structure describes a page worth of chunks. @@ -96,7 +112,7 @@ struct pgfree { struct pgfree *prev; /* prev run of free pages */ void *page; /* pointer to free pages */ void *end; /* pointer to end of free pages */ - u_long size; /* number of bytes free */ + size_t size; /* number of bytes free */ }; /* @@ -122,10 +138,6 @@ struct pgfree { #define malloc_minsize 16U #endif -#ifndef malloc_pageshift -#error "malloc_pageshift undefined" -#endif - #if !defined(malloc_pagesize) #define malloc_pagesize (1U<<malloc_pageshift) #endif @@ -144,9 +156,28 @@ struct pgfree { #define pageround(foo) (((foo) + (malloc_pagemask))&(~(malloc_pagemask))) #define ptr2index(foo) (((u_long)(foo) >> malloc_pageshift)-malloc_origo) +#ifndef THREAD_LOCK +#define THREAD_LOCK() +#endif + +#ifndef THREAD_UNLOCK +#define THREAD_UNLOCK() +#endif + +#ifndef MMAP_FD +#define MMAP_FD (-1) +#endif + +#ifndef INIT_MMAP +#define INIT_MMAP() +#endif + /* Set when initialization has been done */ static unsigned malloc_started; +/* Recusion flag for public interface. */ +static int malloc_active; + /* Number of free pages we cache */ static unsigned malloc_cache = 16; @@ -171,25 +202,29 @@ static int malloc_abort; /* Are we trying to die ? */ static int suicide; -/* dump statistics */ -static int malloc_stats; - /* always realloc ? */ static int malloc_realloc; /* pass the kernel a hint on free pages ? */ static int malloc_hint; +/* xmalloc behaviour ? */ +static int malloc_xmalloc; + +/* sysv behaviour for malloc(0) ? */ +static int malloc_sysv; + /* zero fill ? */ static int malloc_zero; /* junk fill ? */ static int malloc_junk; +#ifdef HAS_UTRACE + /* utrace ? */ static int malloc_utrace; -#ifdef __FreeBSD__ struct ut { void *p; size_t s; void *r; }; void utrace __P((struct ut *, int)); @@ -197,9 +232,9 @@ void utrace __P((struct ut *, int)); #define UTRACE(a, b, c) \ if (malloc_utrace) \ {struct ut u; u.p=a; u.s = b; u.r=c; utrace(&u, sizeof u);} -#else /* !__FreeBSD__ */ +#else /* !HAS_UTRACE */ #define UTRACE(a,b,c) -#endif +#endif /* HAS_UTRACE */ /* my last break. */ static void *malloc_brk; @@ -213,6 +248,11 @@ char *malloc_options; /* Name of the current public function */ static char *malloc_func; +/* Macro for mmap */ +#define MMAP(size) \ + mmap((caddr_t)0, (size), PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, \ + MMAP_FD, 0); + /* * Necessary function declarations */ @@ -221,79 +261,17 @@ static void *imalloc(size_t size); static void ifree(void *ptr); static void *irealloc(void *ptr, size_t size); -#ifdef MALLOC_STATS -void -malloc_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%d\n", malloc_maxsize); - fprintf(fd, "Pagesize\t%d\n", malloc_pagesize); - fprintf(fd, "Pageshift\t%d\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); -} -#endif /* MALLOC_STATS */ - extern char *__progname; static void wrterror(char *p) { char *q = " error: "; + write(STDERR_FILENO, __progname, strlen(__progname)); + write(STDERR_FILENO, malloc_func, strlen(malloc_func)); + write(STDERR_FILENO, q, strlen(q)); + write(STDERR_FILENO, p, strlen(p)); suicide = 1; - write(2, __progname, strlen(__progname)); - write(2, malloc_func, strlen(malloc_func)); - write(2, q, strlen(q)); - write(2, p, strlen(p)); -#ifdef MALLOC_STATS - if (malloc_stats) - malloc_dump(stderr); -#endif /* MALLOC_STATS */ abort(); } @@ -303,25 +281,11 @@ wrtwarning(char *p) char *q = " warning: "; if (malloc_abort) wrterror(p); - write(2, __progname, strlen(__progname)); - write(2, malloc_func, strlen(malloc_func)); - write(2, q, strlen(q)); - write(2, p, strlen(p)); -} - -#ifdef MALLOC_STATS -static void -malloc_exit() -{ - FILE *fd = fopen("malloc.out", "a"); - char *q = "malloc() warning: Couldn't dump stats.\n"; - if (fd) { - malloc_dump(fd); - fclose(fd); - } else - write(2, q, strlen(q)); + write(STDERR_FILENO, __progname, strlen(__progname)); + write(STDERR_FILENO, malloc_func, strlen(malloc_func)); + write(STDERR_FILENO, q, strlen(q)); + write(STDERR_FILENO, p, strlen(p)); } -#endif /* MALLOC_STATS */ /* @@ -384,8 +348,7 @@ extend_pgdir(u_long index) */ /* Get new pages */ - new = (struct pginfo**) mmap(0, i * malloc_pagesize, PROT_READ|PROT_WRITE, - MAP_ANON|MAP_PRIVATE, -1, 0); + new = (struct pginfo**) MMAP(i * malloc_pagesize); if (new == (struct pginfo **)-1) return 0; @@ -414,6 +377,7 @@ malloc_init () char *p, b[64]; int i, j; + INIT_MMAP(); #ifdef EXTRA_SANITY malloc_junk = 1; @@ -437,16 +401,20 @@ malloc_init () case '<': malloc_cache >>= 1; break; 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 'h': malloc_hint = 0; break; case 'H': malloc_hint = 1; break; case 'r': malloc_realloc = 0; break; case 'R': malloc_realloc = 1; break; case 'j': malloc_junk = 0; break; case 'J': malloc_junk = 1; break; +#ifdef HAS_UTRACE case 'u': malloc_utrace = 0; break; case 'U': malloc_utrace = 1; break; +#endif + case 'v': malloc_sysv = 0; break; + case 'V': malloc_sysv = 1; break; + case 'x': malloc_xmalloc = 0; break; + case 'X': malloc_xmalloc = 1; break; case 'z': malloc_zero = 0; break; case 'Z': malloc_zero = 1; break; default: @@ -468,14 +436,16 @@ malloc_init () if (malloc_zero) malloc_junk=1; -#ifdef MALLOC_STATS - if (malloc_stats) - atexit(malloc_exit); -#endif /* MALLOC_STATS */ + /* + * If we run with junk (or implicitly from above: zero), we want to + * force realloc() to get new storage, so we can DTRT with it. + */ + if (malloc_junk) + malloc_realloc=1; /* Allocate one page for the page directory */ - page_dir = (struct pginfo **) mmap(0, malloc_pagesize, PROT_READ|PROT_WRITE, - MAP_ANON|MAP_PRIVATE, -1, 0); + page_dir = (struct pginfo **) MMAP(malloc_pagesize); + if (page_dir == (struct pginfo **) -1) wrterror("mmap(2) failed, check limits.\n"); @@ -488,9 +458,6 @@ malloc_init () malloc_ninfo = malloc_pagesize / sizeof *page_dir; - /* Been here, done that */ - malloc_started++; - /* Recalculate the cache size in bytes, and make sure it's nonzero */ if (!malloc_cache) @@ -504,6 +471,8 @@ malloc_init () */ px = (struct pgfree *) imalloc (sizeof *px); + /* Been here, done that */ + malloc_started++; } /* @@ -520,6 +489,7 @@ malloc_pages(size_t size) size = pageround(size); p = 0; + /* Look for free pages before asking for more */ for(pf = free_list.next; pf; pf = pf->next) { @@ -725,9 +695,6 @@ imalloc(size_t size) { void *result; - if (!malloc_started) - malloc_init(); - if (suicide) abort(); @@ -759,12 +726,7 @@ irealloc(void *ptr, size_t size) int i; if (suicide) - return 0; - - if (!malloc_started) { - wrtwarning("malloc() has never been called.\n"); - return 0; - } + abort(); index = ptr2index(ptr); @@ -833,7 +795,9 @@ irealloc(void *ptr, size_t size) if (p) { /* copy the lesser of the two sizes, and free the old one */ - if (osize < size) + if (!size || !osize) + ; + else if (osize < size) memcpy(p, ptr, osize); else memcpy(p, ptr, size); @@ -1082,18 +1046,6 @@ ifree(void *ptr) * These are the public exported interface routines. */ -#ifdef _THREAD_SAFE -#include <pthread.h> -#include "pthread_private.h" -static int malloc_lock; -#define THREAD_LOCK() _thread_kern_sig_block(&malloc_lock); -#define THREAD_UNLOCK() _thread_kern_sig_unblock(malloc_lock); -#else -#define THREAD_LOCK() -#define THREAD_UNLOCK() -#endif - -static int malloc_active; void * malloc(size_t size) @@ -1107,10 +1059,17 @@ malloc(size_t size) malloc_active--; return (0); } - r = imalloc(size); + if (!malloc_started) + malloc_init(); + if (malloc_sysv && !size) + r = 0; + else + r = imalloc(size); UTRACE(0, size, r); malloc_active--; THREAD_UNLOCK(); + if (malloc_xmalloc && !r) + wrterror("out of memory.\n"); return (r); } @@ -1143,16 +1102,25 @@ realloc(void *ptr, size_t size) malloc_active--; return (0); } - if (!ptr) { - r = imalloc(size); - } else if (ptr && !size) { + if (ptr && !malloc_started) { + wrtwarning("malloc() has never been called.\n"); + ptr = 0; + } + if (!malloc_started) + malloc_init(); + if (malloc_sysv && !size) { ifree(ptr); r = 0; + } else if (!ptr) { + r = imalloc(size); } else { r = irealloc(ptr, size); } UTRACE(ptr, size, r); malloc_active--; THREAD_UNLOCK(); + if (malloc_xmalloc && !r) + wrterror("out of memory.\n"); return (r); } + |
