Integrate latest malloc(3) from FreeBSD
authortholo <tholo@openbsd.org>
Sun, 5 Jan 1997 22:12:48 +0000 (22:12 +0000)
committertholo <tholo@openbsd.org>
Sun, 5 Jan 1997 22:12:48 +0000 (22:12 +0000)
lib/libc/stdlib/malloc.c

index 1606ea6..94db62c 100644 (file)
@@ -8,7 +8,7 @@
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
-static char rcsid[] = "$OpenBSD: malloc.c,v 1.19 1996/11/24 00:41:30 niklas Exp $";
+static char rcsid[] = "$OpenBSD: malloc.c,v 1.20 1997/01/05 22:12:48 tholo Exp $";
 #endif /* LIBC_SCCS and not lint */
 
 /*
@@ -18,17 +18,17 @@ static char rcsid[] = "$OpenBSD: malloc.c,v 1.19 1996/11/24 00:41:30 niklas Exp
  * any good unless you fiddle with the internals of malloc or want
  * to catch random pointer corruption as early as possible.
  */
-#undef EXTRA_SANITY
+#ifndef MALLOC_EXTRA_SANITY
+#undef MALLOC_EXTRA_SANITY
+#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, but does pull in stdio...
  */
+#ifndef MALLOC_STATS
 #undef MALLOC_STATS
-
-#if defined(EXTRA_SANITY) && !defined(MALLOC_STATS)
-# define MALLOC_STATS  /* required for EXTRA_SANITY */
 #endif
 
 /*
@@ -51,16 +51,24 @@ static char rcsid[] = "$OpenBSD: malloc.c,v 1.19 1996/11/24 00:41:30 niklas Exp
 #include <sys/mman.h>
 
 /*
- * If these weren't defined here, they would be calculated on the fly,
- * at a considerable cost in performance.
+ * The basic parameters you can tweak.
+ *
+ * malloc_pageshift    pagesize = 1 << malloc_pageshift
+ *                     It's probably best if this is the native
+ *                     page size, but it shouldn't have to be.
+ *
+ * malloc_minsize      minimum size of an allocation in bytes.
+ *                     If this is too small it's too much work
+ *                     to manage them.  This is also the smallest
+ *                     unit of alignment used for the storage
+ *                     returned by malloc/realloc.
+ *
  */
 #ifdef __OpenBSD__
 #   if defined(__alpha__) || defined(__m68k__) || defined(__mips__) || \
        defined(__i386__) || defined(__m88k__) || defined(__ns32k__) || \
        defined(__vax__)
-#      define  malloc_pagesize         (NBPG)
 #      define  malloc_pageshift        (PGSHIFT)
-#      define  malloc_maxsize          (malloc_pagesize >> 1)
 #      define  malloc_minsize          16U
 #   endif /* __i386__ */
 #endif /* __OpenBSD__ */
@@ -76,7 +84,7 @@ struct pginfo {
     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 */
+    u_int              bits[1]; /* Which chunks are free */
 };
 
 /*
@@ -92,10 +100,10 @@ struct pgfree {
 };
 
 /*
- * How many bits per u_long in the bitmap.
+ * How many bits per u_int in the bitmap.
  * Change only if not 8 bits/byte
  */
-#define        MALLOC_BITS     (8*sizeof(u_long))
+#define        MALLOC_BITS     (8*sizeof(u_int))
 
 /*
  * Magic values to put in the page_directory
@@ -106,67 +114,29 @@ struct pgfree {
 #define MALLOC_FOLLOW  ((struct pginfo*) 3)
 #define MALLOC_MAGIC   ((struct pginfo*) 4)
 
-/*
- * The i386 architecture has some very convenient instructions.
- * We might as well use them.  There are C-language backups, but
- * they are considerably slower.
- */
-#if defined(__i386__) && defined(__GNUC__)
-#define ffs _ffs
-static __inline int
-_ffs(input)
-       unsigned input;
-{
-       int result;
-       __asm("bsfl %1, %0" : "=r" (result) : "r" (input));
-       return result+1;
-}
-
-#define fls _fls
-static __inline int
-_fls(input)
-       unsigned input;
-{
-       int result;
-       __asm("bsrl %1, %0" : "=r" (result) : "r" (input));
-       return result+1;
-}
+#ifndef malloc_pageshift
+#define malloc_pageshift               12U
+#endif
 
-#define set_bit _set_bit
-static __inline void
-_set_bit(pi, bit)
-       struct pginfo *pi;
-       int bit;
-{
-       __asm("btsl %0, (%1)" :
-       : "r" (bit & (MALLOC_BITS-1)), "r" (pi->bits+(bit/MALLOC_BITS)));
-}
+#ifndef malloc_minsize
+#define malloc_minsize                 16U
+#endif
 
-#define clr_bit _clr_bit
-static __inline void
-_clr_bit(pi, bit)
-       struct pginfo *pi;
-       int bit;
-{
-       __asm("btcl %0, (%1)" :
-       : "r" (bit & (MALLOC_BITS-1)), "r" (pi->bits+(bit/MALLOC_BITS)));
-}
+#ifndef malloc_pageshift
+#error "malloc_pageshift undefined"
+#endif
 
-#endif /* __i386__ && __GNUC__ */
+#if !defined(malloc_pagesize)
+#define malloc_pagesize                        (1U<<malloc_pageshift)
+#endif
 
-/*
- * Set to one when malloc_init has been called
- */
-static unsigned        initialized;
+#if ((1<<malloc_pageshift) != malloc_pagesize)
+#error "(1<<malloc_pageshift) != malloc_pagesize"
+#endif
 
-/*
- * 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
- */
-#ifndef malloc_pagesize
-static unsigned        malloc_pagesize;
-#endif /* malloc_pagesize */
+#ifndef malloc_maxsize
+#define malloc_maxsize                 ((malloc_pagesize)>>1)
+#endif
 
 /* A mask for the offset inside a page.  */
 #define malloc_pagemask        ((malloc_pagesize)-1)
@@ -174,45 +144,26 @@ static    unsigned        malloc_pagesize;
 #define pageround(foo) (((foo) + (malloc_pagemask))&(~(malloc_pagemask)))
 #define ptr2index(foo) (((u_long)(foo) >> malloc_pageshift)-malloc_origo)
 
-/* malloc_pagesize == 1 << malloc_pageshift */
-#ifndef malloc_pageshift
-static unsigned        malloc_pageshift;
-#endif /* malloc_pageshift */
+/* Set when initialization has been done */
+static unsigned malloc_started;        
 
-/*
- * The smallest allocation we bother about.
- * Must be power of two
- */
-#ifndef malloc_minsize
-static unsigned  malloc_minsize;
-#endif /* malloc_minsize */
-
-/*
- * The largest chunk we care about.
- * Must be smaller than pagesize
- * Must be power of two
- */
-#ifndef malloc_maxsize
-static unsigned  malloc_maxsize;
-#endif /* malloc_maxsize */
-
-/* The minimum size (in pages) of the free page cache.  */
-static unsigned  malloc_cache = 16;
+/* Number of free pages we cache */
+static unsigned malloc_cache = 16;
 
 /* The offset from pagenumber to index into the page directory */
-static u_long  malloc_origo;
+static u_long malloc_origo;
 
 /* The last index in the page directory we care about */
-static u_long  last_index;
+static u_long last_index;
 
 /* Pointer to page directory. Allocated "as if with" malloc */
-static struct  pginfo **page_dir;
+static struct  pginfo **page_dir;
 
 /* How many slots in the page directory */
-static unsigned        malloc_ninfo;
+static unsigned        malloc_ninfo;
 
 /* Free pages line up here */
-static struct pgfree   free_list;
+static struct pgfree free_list;
 
 /* Abort(), user doesn't handle problems.  */
 static int malloc_abort;
@@ -223,7 +174,7 @@ static int suicide;
 #ifdef MALLOC_STATS
 /* dump statistics */
 static int malloc_stats;
-#endif /* MALLOC_STATS */
+#endif
 
 /* always realloc ?  */
 static int malloc_realloc;
@@ -245,6 +196,8 @@ static int malloc_utrace;
 
 struct ut { void *p; size_t s; void *r; };
 
+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);}
@@ -261,6 +214,9 @@ static struct pgfree *px;
 /* compile-time options */
 char *malloc_options;
 
+/* Name of the current public function */
+static char *malloc_func;
+
 /*
  * Necessary function declarations
  */
@@ -328,16 +284,17 @@ malloc_dump(fd)
 }
 #endif /* MALLOC_STATS */
 
-static char *malloc_func;
+extern char *__progname;
 
 static void
 wrterror(p)
     char *p;
 {
-    char *q = "Malloc error: ";
+    char *q = " error: ";
     suicide = 1;
-    write(2, q, strlen(q));
+    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)
@@ -350,15 +307,16 @@ static void
 wrtwarning(p)
     char *p;
 {
-    char *q = "Malloc warning: ";
+    char *q = " warning: ";
     if (malloc_abort)
        wrterror(p);
-    write(2, q, strlen(q));
+    write(2, __progname, strlen(__progname));
     write(2, malloc_func, strlen(malloc_func));
+    write(2, q, strlen(q));
     write(2, p, strlen(p));
 }
 
-#ifdef EXTRA_SANITY
+#ifdef MALLOC_STATS
 static void
 malloc_exit()
 {
@@ -370,7 +328,7 @@ malloc_exit()
     } else
        write(2, q, strlen(q));
 }
-#endif /* EXTRA_SANITY */
+#endif /* MALLOC_STATS */
 
 
 /*
@@ -401,83 +359,6 @@ map_pages(pages)
     return result;
 }
 
-/*
- * Set a bit in the bitmap
- */
-#ifndef set_bit
-static __inline void
-set_bit(pi, bit)
-    struct pginfo *pi;
-    int bit;
-{
-    pi->bits[bit/MALLOC_BITS] |= 1UL<<(bit%MALLOC_BITS);
-}
-#endif /* set_bit */
-
-/*
- * Clear a bit in the bitmap
- */
-#ifndef clr_bit
-static __inline void
-clr_bit(pi, bit)
-    struct pginfo *pi;
-    int bit;
-{
-    pi->bits[bit/MALLOC_BITS] &= ~(1UL<<(bit%MALLOC_BITS));
-}
-#endif /* clr_bit */
-
-#ifndef tst_bit
-/*
- * Test a bit in the bitmap
- */
-static __inline int
-tst_bit(pi, bit)
-    struct pginfo *pi;
-    int bit;
-{
-    return pi->bits[bit/MALLOC_BITS] & (1UL<<(bit%MALLOC_BITS));
-}
-#endif /* tst_bit */
-
-/*
- * Find last bit
- */
-#ifndef fls
-static __inline int
-fls(size)
-    size_t size;
-{
-    int i = 1;
-    while (size >>= 1)
-       i++;
-    return i;
-}
-#endif /* fls */
-
-#if LONG_BIT == WORD_BIT
-#define ffs_ul ffs
-#else
-static __inline int
-ffs_ul(u_long ul)
-{
-    u_int n;
-    int i;
-    int k;
-
-    for (i = 0; i < sizeof (u_long) / sizeof (u_int); i++) {
-       n = ul & UINT_MAX;
-       k = ffs (n);
-       if (k)
-           break;
-       ul >>= (sizeof (u_int) * 8);
-    }
-    if (k)
-       k += i * sizeof (u_int) * 8;
-    return k;
-}
-#endif
-
 /*
  * Extend page directory
  */
@@ -556,11 +437,9 @@ malloc_init ()
            p = b;
        } else if (i == 1 && issetugid() == 0) {
            p = getenv("MALLOC_OPTIONS");
-       } else if (i == 2) {
+       } else {
            p = malloc_options;
        }
-       else
-           p = NULL;
        for (; p && *p; p++) {
            switch (*p) {
                case '>': malloc_cache   <<= 1; break;
@@ -604,53 +483,10 @@ malloc_init ()
     if (malloc_zero)
        malloc_junk=1;
 
-#ifdef EXTRA_SANITY
+#ifdef MALLOC_STATS
     if (malloc_stats)
        atexit(malloc_exit);
-#endif /* EXTRA_SANITY */
-
-#ifndef malloc_pagesize
-    /* determine our pagesize */
-    malloc_pagesize = getpagesize();
-#endif /* malloc_pagesize */
-
-#ifndef malloc_maxsize
-    malloc_maxsize = malloc_pagesize >> 1;
-#endif /* malloc_maxsize */
-
-#ifndef malloc_pageshift
-    {
-    int i;
-    /* determine how much we shift by to get there */
-    for (i = malloc_pagesize; i > 1; i >>= 1)
-       malloc_pageshift++;
-    }
-#endif /* malloc_pageshift */
-
-#ifndef malloc_minsize
-    {
-    int i;
-    /*
-     * 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 */
+#endif /* MALLOC_STATS */
 
     /* Allocate one page for the page directory */
     page_dir = (struct pginfo **) mmap(0, malloc_pagesize, PROT_READ|PROT_WRITE,
@@ -668,7 +504,14 @@ malloc_init ()
     malloc_ninfo = malloc_pagesize / sizeof *page_dir;
 
     /* Been here, done that */
-    initialized++;
+    malloc_started++;
+
+    /* Recalculate the cache size in bytes, and make sure it's nonzero */
+
+    if (!malloc_cache)
+       malloc_cache++;
+
+    malloc_cache <<= malloc_pageshift;
 
     /*
      * This is a nice hack from Kaleb Keithly (kaleb@x.org).
@@ -676,16 +519,12 @@ malloc_init ()
      */
     px = (struct pgfree *) imalloc (sizeof *px);
 
-    if (!malloc_cache)
-       malloc_cache++;
-
-    malloc_cache <<= malloc_pageshift;
 }
 
 /*
  * Allocate a number of complete pages
  */
-void *
+static void *
 malloc_pages(size)
     size_t size;
 {
@@ -771,7 +610,7 @@ malloc_pages(size)
  * Allocate a page of fragments
  */
 
-static __inline int
+static __inline__ int
 malloc_make_chunks(bits)
     int bits;
 {
@@ -794,8 +633,10 @@ malloc_make_chunks(bits)
        bp = (struct  pginfo *)pp;
     } else {
        bp = (struct  pginfo *)imalloc(l);
-       if (!bp)
+       if (!bp) {
+           ifree(pp);
            return 0;
+       }
     }
 
     bp->size = (1UL<<bits);
@@ -803,12 +644,7 @@ malloc_make_chunks(bits)
     bp->total = bp->free = malloc_pagesize >> bits;
     bp->page = pp;
 
-    page_dir[ptr2index(pp)] = bp;
-
-    bp->next = page_dir[bits];
-    page_dir[bits] = bp;
-
-    /* set all valid bits in the bits */
+    /* set all valid bits in the bitmap */
     k = bp->total;
     i = 0;
 
@@ -817,18 +653,27 @@ malloc_make_chunks(bits)
        bp->bits[i / MALLOC_BITS] = (u_long)~0;
 
     for(; i < k; i++)
-       set_bit(bp, i);
+        bp->bits[i/MALLOC_BITS] |= 1<<(i%MALLOC_BITS);
 
     if (bp == bp->page) {
        /* Mark the ones we stole for ourselves */
        for(i=0;l > 0;i++) {
-           clr_bit(bp, i);
+           bp->bits[i/MALLOC_BITS] &= ~(1<<(i%MALLOC_BITS));
            bp->free--;
            bp->total--;
            l -= (1 << bits);
        }
     }
 
+    /* MALLOC_LOCK */
+
+    page_dir[ptr2index(pp)] = bp;
+
+    bp->next = page_dir[bits];
+    page_dir[bits] = bp;
+
+    /* MALLOC_UNLOCK */
+
     return 1;
 }
 
@@ -839,17 +684,21 @@ static void *
 malloc_bytes(size)
     size_t size;
 {
-    int j;
+    int i,j;
+    u_int u;
     struct  pginfo *bp;
     int k;
-    u_long *lp;
+    u_int *lp;
 
     /* Don't bother with anything less than this */
     if (size < malloc_minsize)
        size = malloc_minsize;
 
     /* Find the right bucket */
-    j = fls((size)-1);
+    j = 1;
+    i = size-1;
+    while (i >>= 1)
+       j++;
 
     /* If it's empty, make a page more of that size chunks */
     if (!page_dir[j] && !malloc_make_chunks(j))
@@ -862,8 +711,13 @@ malloc_bytes(size)
        ;
 
     /* Find that bit, and tweak it */
-    k = ffs_ul(*lp) - 1;
-    *lp ^= 1UL<<k;
+    u = 1;
+    k = 0;
+    while (!(*lp & u)) {
+       u += u;
+       k++;
+    }
+    *lp ^= u;
 
     /* If there are no more free, remove from free-list */
     if (!--bp->free) {
@@ -878,7 +732,7 @@ malloc_bytes(size)
     if (malloc_junk)
        memset((char *)bp->page + k, SOME_JUNK, bp->size);
 
-    return (void *)((char *)bp->page + k);
+    return (u_char *)bp->page + k;
 }
 
 /*
@@ -893,7 +747,7 @@ imalloc(size)
     int     status;
 #endif
 
-    if (!initialized)
+    if (!malloc_started)
        malloc_init();
 
     if (suicide)
@@ -907,7 +761,7 @@ imalloc(size)
     if (malloc_abort && !result)
        wrterror("allocation failed.\n");
 
-    if (malloc_zero)
+    if (malloc_zero && result)
        memset(result, 0, size);
 
     return result;
@@ -932,7 +786,7 @@ irealloc(ptr, size)
     if (suicide)
        return 0;
 
-    if (!initialized) {
+    if (!malloc_started) {
        wrtwarning("malloc() has never been called.\n");
        return 0;
     }
@@ -981,7 +835,7 @@ irealloc(ptr, size)
        i = ((u_long)ptr & malloc_pagemask) >> (*mp)->shift;
 
        /* Verify that it isn't a free chunk already */
-       if (tst_bit(*mp, i)) {
+        if ((*mp)->bits[i/MALLOC_BITS] & (1<<(i%MALLOC_BITS))) {
            wrtwarning("chunk is already free.\n");
            return 0;
        }
@@ -1017,7 +871,7 @@ irealloc(ptr, size)
  * Free a sequence of pages
  */
 
-static __inline void
+static __inline__ void
 free_pages(ptr, index, info)
     void *ptr;
     int index;
@@ -1050,6 +904,9 @@ free_pages(ptr, index, info)
 
     l = i << malloc_pageshift;
 
+    if (malloc_junk)
+       memset(ptr, SOME_JUNK, l);
+
 #ifdef __FreeBSD__
     if (malloc_hint)
        madvise(ptr, l, MADV_FREE);
@@ -1150,7 +1007,7 @@ free_pages(ptr, index, info)
  */
 
 /* ARGSUSED */
-static __inline void
+static __inline__ void
 free_bytes(ptr, index, info)
     void *ptr;
     int index;
@@ -1168,12 +1025,15 @@ free_bytes(ptr, index, info)
        return;
     }
 
-    if (tst_bit(info, i)) {
+    if (info->bits[i/MALLOC_BITS] & (1<<(i%MALLOC_BITS))) {
        wrtwarning("chunk is already free.\n");
        return;
     }
 
-    set_bit(info, i);
+    if (malloc_junk)
+       memset(ptr, SOME_JUNK, info->size);
+
+    info->bits[i/MALLOC_BITS] |= 1<<(i%MALLOC_BITS);
     info->free++;
 
     mp = page_dir + info->shift;
@@ -1226,7 +1086,7 @@ ifree(ptr)
     if (!ptr)
        return;
 
-    if (!initialized) {
+    if (!malloc_started) {
        wrtwarning("malloc() has never been called.\n");
        return;
     }
@@ -1265,7 +1125,7 @@ ifree(ptr)
 #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);
+#define THREAD_UNLOCK() _thread_kern_sig_unblock(malloc_lock);
 #else
 #define THREAD_LOCK() 
 #define THREAD_UNLOCK()
@@ -1278,7 +1138,7 @@ malloc(size_t size)
 {
     register void *r;
 
-    malloc_func = "malloc():";
+    malloc_func = " in malloc():";
     THREAD_LOCK();
     if (malloc_active++) {
        wrtwarning("recursive call.\n");
@@ -1295,7 +1155,7 @@ malloc(size_t size)
 void
 free(void *ptr)
 {
-    malloc_func = "free():";
+    malloc_func = " in free():";
     THREAD_LOCK();
     if (malloc_active++) {
        wrtwarning("recursive call.\n");
@@ -1314,7 +1174,7 @@ realloc(void *ptr, size_t size)
 {
     register void *r;
 
-    malloc_func = "realloc():";
+    malloc_func = " in realloc():";
     THREAD_LOCK();
     if (malloc_active++) {
        wrtwarning("recursive call.\n");