The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_malloc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 1987, 1991, 1993
    3  *      The Regents of the University of California.  All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. All advertising materials mentioning features or use of this software
   14  *    must display the following acknowledgement:
   15  *      This product includes software developed by the University of
   16  *      California, Berkeley and its contributors.
   17  * 4. Neither the name of the University nor the names of its contributors
   18  *    may be used to endorse or promote products derived from this software
   19  *    without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31  * SUCH DAMAGE.
   32  *
   33  *      @(#)kern_malloc.c       8.3 (Berkeley) 1/4/94
   34  * $FreeBSD: src/sys/kern/kern_malloc.c,v 1.24.2.2 1999/09/05 08:14:57 peter Exp $
   35  */
   36 
   37 #include <sys/param.h>
   38 #include <sys/systm.h>
   39 #include <sys/proc.h>
   40 #include <sys/kernel.h>
   41 #include <sys/malloc.h>
   42 #include <sys/mbuf.h>
   43 #include <sys/vmmeter.h>
   44 
   45 #include <vm/vm.h>
   46 #include <vm/vm_param.h>
   47 #include <vm/vm_kern.h>
   48 #include <vm/vm_extern.h>
   49 
   50 static void kmeminit __P((void *));
   51 SYSINIT(kmem, SI_SUB_KMEM, SI_ORDER_FIRST, kmeminit, NULL)
   52 
   53 static struct kmembuckets bucket[MINBUCKET + 16];
   54 struct kmemstats kmemstats[M_LAST];
   55 struct kmemusage *kmemusage;
   56 char *kmembase, *kmemlimit;
   57 char *memname[] = INITKMEMNAMES;
   58 
   59 #ifdef DIAGNOSTIC
   60 /*
   61  * This structure provides a set of masks to catch unaligned frees.
   62  */
   63 static long addrmask[] = { 0,
   64         0x00000001, 0x00000003, 0x00000007, 0x0000000f,
   65         0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
   66         0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
   67         0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
   68 };
   69 
   70 /*
   71  * The WEIRD_ADDR is used as known text to copy into free objects so
   72  * that modifications after frees can be detected.
   73  */
   74 #define WEIRD_ADDR      0xdeadc0de
   75 #define MAX_COPY        64
   76 
   77 /*
   78  * Normally the first word of the structure is used to hold the list
   79  * pointer for free objects. However, when running with diagnostics,
   80  * we use the third and fourth fields, so as to catch modifications
   81  * in the most commonly trashed first two words.
   82  */
   83 struct freelist {
   84         long    spare0;
   85         short   type;
   86         long    spare1;
   87         caddr_t next;
   88 };
   89 #else /* !DIAGNOSTIC */
   90 struct freelist {
   91         caddr_t next;
   92 };
   93 #endif /* DIAGNOSTIC */
   94 
   95 /*
   96  * Allocate a block of memory
   97  */
   98 void *
   99 malloc(size, type, flags)
  100         unsigned long size;
  101         int type, flags;
  102 {
  103         register struct kmembuckets *kbp;
  104         register struct kmemusage *kup;
  105         register struct freelist *freep;
  106         long indx, npg, allocsize;
  107         int s;
  108         caddr_t va, cp, savedlist;
  109 #ifdef DIAGNOSTIC
  110         long *end, *lp;
  111         int copysize;
  112         char *savedtype;
  113 #endif
  114 #ifdef KMEMSTATS
  115         register struct kmemstats *ksp = &kmemstats[type];
  116 
  117         if (((unsigned long)type) > M_LAST)
  118                 panic("malloc - bogus type");
  119 #endif
  120         indx = BUCKETINDX(size);
  121         kbp = &bucket[indx];
  122         s = splhigh();
  123 #ifdef KMEMSTATS
  124         while (ksp->ks_memuse >= ksp->ks_limit) {
  125                 if (flags & M_NOWAIT) {
  126                         splx(s);
  127                         return ((void *) NULL);
  128                 }
  129                 if (ksp->ks_limblocks < 65535)
  130                         ksp->ks_limblocks++;
  131                 tsleep((caddr_t)ksp, PSWP+2, memname[type], 0);
  132         }
  133         ksp->ks_size |= 1 << indx;
  134 #endif
  135 #ifdef DIAGNOSTIC
  136         copysize = 1 << indx < MAX_COPY ? 1 << indx : MAX_COPY;
  137 #endif
  138         if (kbp->kb_next == NULL) {
  139                 kbp->kb_last = NULL;
  140                 if (size > MAXALLOCSAVE)
  141                         allocsize = roundup(size, PAGE_SIZE);
  142                 else
  143                         allocsize = 1 << indx;
  144                 npg = btoc(allocsize);
  145                 va = (caddr_t) kmem_malloc(kmem_map, (vm_size_t)ctob(npg), flags);
  146                 if (va == NULL) {
  147                         splx(s);
  148                         return ((void *) NULL);
  149                 }
  150 #ifdef KMEMSTATS
  151                 kbp->kb_total += kbp->kb_elmpercl;
  152 #endif
  153                 kup = btokup(va);
  154                 kup->ku_indx = indx;
  155                 if (allocsize > MAXALLOCSAVE) {
  156                         if (npg > 65535)
  157                                 panic("malloc: allocation too large");
  158                         kup->ku_pagecnt = npg;
  159 #ifdef KMEMSTATS
  160                         ksp->ks_memuse += allocsize;
  161 #endif
  162                         goto out;
  163                 }
  164 #ifdef KMEMSTATS
  165                 kup->ku_freecnt = kbp->kb_elmpercl;
  166                 kbp->kb_totalfree += kbp->kb_elmpercl;
  167 #endif
  168                 /*
  169                  * Just in case we blocked while allocating memory,
  170                  * and someone else also allocated memory for this
  171                  * bucket, don't assume the list is still empty.
  172                  */
  173                 savedlist = kbp->kb_next;
  174                 kbp->kb_next = cp = va + (npg * PAGE_SIZE) - allocsize;
  175                 for (;;) {
  176                         freep = (struct freelist *)cp;
  177 #ifdef DIAGNOSTIC
  178                         /*
  179                          * Copy in known text to detect modification
  180                          * after freeing.
  181                          */
  182                         end = (long *)&cp[copysize];
  183                         for (lp = (long *)cp; lp < end; lp++)
  184                                 *lp = WEIRD_ADDR;
  185                         freep->type = M_FREE;
  186 #endif /* DIAGNOSTIC */
  187                         if (cp <= va)
  188                                 break;
  189                         cp -= allocsize;
  190                         freep->next = cp;
  191                 }
  192                 freep->next = savedlist;
  193                 if (kbp->kb_last == NULL)
  194                         kbp->kb_last = (caddr_t)freep;
  195         }
  196         va = kbp->kb_next;
  197         kbp->kb_next = ((struct freelist *)va)->next;
  198 #ifdef DIAGNOSTIC
  199         freep = (struct freelist *)va;
  200         savedtype = (unsigned)freep->type < M_LAST ?
  201                 memname[freep->type] : "???";
  202 #if BYTE_ORDER == BIG_ENDIAN
  203         freep->type = WEIRD_ADDR >> 16;
  204 #endif
  205 #if BYTE_ORDER == LITTLE_ENDIAN
  206         freep->type = (short)WEIRD_ADDR;
  207 #endif
  208         if (((long)(&freep->next)) & 0x2)
  209                 freep->next = (caddr_t)((WEIRD_ADDR >> 16)|(WEIRD_ADDR << 16));
  210         else
  211                 freep->next = (caddr_t)WEIRD_ADDR;
  212         end = (long *)&va[copysize];
  213         for (lp = (long *)va; lp < end; lp++) {
  214                 if (*lp == WEIRD_ADDR)
  215                         continue;
  216                 printf("%s %d of object %p size %ld %s %s (0x%lx != 0x%x)\n",
  217                         "Data modified on freelist: word", lp - (long *)va,
  218                         va, size, "previous type", savedtype, *lp, WEIRD_ADDR);
  219                 break;
  220         }
  221         freep->spare0 = 0;
  222 #endif /* DIAGNOSTIC */
  223 #ifdef KMEMSTATS
  224         kup = btokup(va);
  225         if (kup->ku_indx != indx)
  226                 panic("malloc: wrong bucket");
  227         if (kup->ku_freecnt == 0)
  228                 panic("malloc: lost data");
  229         kup->ku_freecnt--;
  230         kbp->kb_totalfree--;
  231         ksp->ks_memuse += 1 << indx;
  232 out:
  233         kbp->kb_calls++;
  234         ksp->ks_inuse++;
  235         ksp->ks_calls++;
  236         if (ksp->ks_memuse > ksp->ks_maxused)
  237                 ksp->ks_maxused = ksp->ks_memuse;
  238 #else
  239 out:
  240 #endif
  241         splx(s);
  242         return ((void *) va);
  243 }
  244 
  245 /*
  246  * Free a block of memory allocated by malloc.
  247  */
  248 void
  249 free(addr, type)
  250         void *addr;
  251         int type;
  252 {
  253         register struct kmembuckets *kbp;
  254         register struct kmemusage *kup;
  255         register struct freelist *freep;
  256         long size;
  257         int s;
  258 #ifdef DIAGNOSTIC
  259         struct freelist *fp;
  260         long *end, *lp, alloc, copysize;
  261 #endif
  262 #ifdef KMEMSTATS
  263         register struct kmemstats *ksp = &kmemstats[type];
  264 #endif
  265 
  266 #ifdef DIAGNOSTIC
  267         if ((char *)addr < kmembase || (char *)addr >= kmemlimit) {
  268                 panic("free: address 0x%x out of range", addr);
  269         }
  270         if ((u_long)type > M_LAST) {
  271                 panic("free: type %d out of range", type);
  272         }
  273 #endif
  274         kup = btokup(addr);
  275         size = 1 << kup->ku_indx;
  276         kbp = &bucket[kup->ku_indx];
  277         s = splhigh();
  278 #ifdef DIAGNOSTIC
  279         /*
  280          * Check for returns of data that do not point to the
  281          * beginning of the allocation.
  282          */
  283         if (size > PAGE_SIZE)
  284                 alloc = addrmask[BUCKETINDX(PAGE_SIZE)];
  285         else
  286                 alloc = addrmask[kup->ku_indx];
  287         if (((u_long)addr & alloc) != 0)
  288                 panic("free: unaligned addr 0x%x, size %d, type %s, mask %d",
  289                         addr, size, memname[type], alloc);
  290 #endif /* DIAGNOSTIC */
  291         if (size > MAXALLOCSAVE) {
  292                 kmem_free(kmem_map, (vm_offset_t)addr, ctob(kup->ku_pagecnt));
  293 #ifdef KMEMSTATS
  294                 size = kup->ku_pagecnt << PAGE_SHIFT;
  295                 ksp->ks_memuse -= size;
  296                 kup->ku_indx = 0;
  297                 kup->ku_pagecnt = 0;
  298                 if (ksp->ks_memuse + size >= ksp->ks_limit &&
  299                     ksp->ks_memuse < ksp->ks_limit)
  300                         wakeup((caddr_t)ksp);
  301                 ksp->ks_inuse--;
  302                 kbp->kb_total -= 1;
  303 #endif
  304                 splx(s);
  305                 return;
  306         }
  307         freep = (struct freelist *)addr;
  308 #ifdef DIAGNOSTIC
  309         /*
  310          * Check for multiple frees. Use a quick check to see if
  311          * it looks free before laboriously searching the freelist.
  312          */
  313         if (freep->spare0 == WEIRD_ADDR) {
  314                 fp = (struct freelist *)kbp->kb_next;
  315                 while (fp) {
  316                         if (fp->spare0 != WEIRD_ADDR) {
  317                                 printf("trashed free item %p\n", fp);
  318                                 panic("free: free item modified");
  319                         } else if (addr == (caddr_t)fp) {
  320                                 printf("multiple freed item %p\n", addr);
  321                                 panic("free: multiple free");
  322                         }
  323                         fp = (struct freelist *)fp->next;
  324                 }
  325         }
  326         /*
  327          * Copy in known text to detect modification after freeing
  328          * and to make it look free. Also, save the type being freed
  329          * so we can list likely culprit if modification is detected
  330          * when the object is reallocated.
  331          */
  332         copysize = size < MAX_COPY ? size : MAX_COPY;
  333         end = (long *)&((caddr_t)addr)[copysize];
  334         for (lp = (long *)addr; lp < end; lp++)
  335                 *lp = WEIRD_ADDR;
  336         freep->type = type;
  337 #endif /* DIAGNOSTIC */
  338 #ifdef KMEMSTATS
  339         kup->ku_freecnt++;
  340         if (kup->ku_freecnt >= kbp->kb_elmpercl)
  341                 if (kup->ku_freecnt > kbp->kb_elmpercl)
  342                         panic("free: multiple frees");
  343                 else if (kbp->kb_totalfree > kbp->kb_highwat)
  344                         kbp->kb_couldfree++;
  345         kbp->kb_totalfree++;
  346         ksp->ks_memuse -= size;
  347         if (ksp->ks_memuse + size >= ksp->ks_limit &&
  348             ksp->ks_memuse < ksp->ks_limit)
  349                 wakeup((caddr_t)ksp);
  350         ksp->ks_inuse--;
  351 #endif
  352 #ifdef OLD_MALLOC_MEMORY_POLICY
  353         if (kbp->kb_next == NULL)
  354                 kbp->kb_next = addr;
  355         else
  356                 ((struct freelist *)kbp->kb_last)->next = addr;
  357         freep->next = NULL;
  358         kbp->kb_last = addr;
  359 #else
  360         /*
  361          * Return memory to the head of the queue for quick reuse.  This
  362          * can improve performance by improving the probability of the
  363          * item being in the cache when it is reused.
  364          */
  365         if (kbp->kb_next == NULL) {
  366                 kbp->kb_next = addr;
  367                 kbp->kb_last = addr;
  368                 freep->next = NULL;
  369         } else {
  370                 freep->next = kbp->kb_next;
  371                 kbp->kb_next = addr;
  372         }
  373 #endif
  374         splx(s);
  375 }
  376 
  377 /*
  378  * Initialize the kernel memory allocator
  379  */
  380 /* ARGSUSED*/
  381 static void
  382 kmeminit(dummy)
  383         void *dummy;
  384 {
  385         register long indx;
  386         int npg;
  387 
  388 #if     ((MAXALLOCSAVE & (MAXALLOCSAVE - 1)) != 0)
  389 #error "kmeminit: MAXALLOCSAVE not power of 2"
  390 #endif
  391 #if     (MAXALLOCSAVE > MINALLOCSIZE * 32768)
  392 #error "kmeminit: MAXALLOCSAVE too big"
  393 #endif
  394 #if     (MAXALLOCSAVE < PAGE_SIZE)
  395 #error "kmeminit: MAXALLOCSAVE too small"
  396 #endif
  397         npg = (nmbufs * MSIZE + nmbclusters * MCLBYTES + VM_KMEM_SIZE)
  398                 / PAGE_SIZE;
  399 
  400         kmemusage = (struct kmemusage *) kmem_alloc(kernel_map,
  401                 (vm_size_t)(npg * sizeof(struct kmemusage)));
  402         kmem_map = kmem_suballoc(kernel_map, (vm_offset_t *)&kmembase,
  403                 (vm_offset_t *)&kmemlimit, (vm_size_t)(npg * PAGE_SIZE),
  404                 FALSE);
  405 #ifdef KMEMSTATS
  406         for (indx = 0; indx < MINBUCKET + 16; indx++) {
  407                 if (1 << indx >= PAGE_SIZE)
  408                         bucket[indx].kb_elmpercl = 1;
  409                 else
  410                         bucket[indx].kb_elmpercl = PAGE_SIZE / (1 << indx);
  411                 bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl;
  412         }
  413         /*
  414          * Limit maximum memory for each type to 60% of malloc area size or
  415          * 60% of physical memory, whichever is smaller.
  416          */
  417         for (indx = 0; indx < M_LAST; indx++) {
  418                 kmemstats[indx].ks_limit = min(cnt.v_page_count * PAGE_SIZE,
  419                         (npg * PAGE_SIZE - nmbclusters * MCLBYTES
  420                          - nmbufs * MSIZE)) * 6 / 10;
  421         }
  422 #endif
  423 }

Cache object: 72afaeb35446289ef195d01b55e96b0f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.