VFLUSHO -> VDISCARD
[unix-history] / usr / src / sys / kern / kern_malloc.c
index 4463ddc..91d6b6e 100644 (file)
@@ -1,9 +1,20 @@
 /*
  * Copyright (c) 1987 Regents of the University of California.
 /*
  * Copyright (c) 1987 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * All rights reserved.
  *
  *
- *     @(#)kern_malloc.c       7.1 (Berkeley) %G%
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     @(#)kern_malloc.c       7.17 (Berkeley) %G%
  */
 
 #include "param.h"
  */
 
 #include "param.h"
 #include "kernel.h"
 #include "malloc.h"
 
 #include "kernel.h"
 #include "malloc.h"
 
-#include "../machine/pte.h"
+#include "machine/pte.h"
 
 struct kmembuckets bucket[MINBUCKET + 16];
 struct kmemstats kmemstats[M_LAST];
 struct kmemusage *kmemusage;
 
 struct kmembuckets bucket[MINBUCKET + 16];
 struct kmemstats kmemstats[M_LAST];
 struct kmemusage *kmemusage;
+long wantkmemmap;
+long malloc_reentered;
+#define IN { if (malloc_reentered) panic("malloc reentered");\
+                       else malloc_reentered = 1;}
+#define OUT (malloc_reentered = 0)
 
 /*
  * Allocate a block of memory
  */
 
 /*
  * Allocate a block of memory
  */
-qaddr_t malloc(size, type, flags)
+qaddr_t
+malloc(size, type, flags)
        unsigned long size;
        unsigned long size;
-       long type, flags;
+       int type, flags;
 {
        register struct kmembuckets *kbp;
        register struct kmemusage *kup;
 {
        register struct kmembuckets *kbp;
        register struct kmemusage *kup;
-       long indx, npg, alloc, allocsize, s;
+       long indx, npg, alloc, allocsize;
+       int s;
        caddr_t va, cp;
 #ifdef KMEMSTATS
        caddr_t va, cp;
 #ifdef KMEMSTATS
-       register struct kmemstats *ksp;
+       register struct kmemstats *ksp = &kmemstats[type];
 
 
-       ksp = &kmemstats[type];
-       if (ksp->ks_inuse >= ksp->ks_limit)
-               return (0);
+       if (((unsigned long)type) > M_LAST)
+               panic("malloc - bogus type");
 #endif
 #endif
+
        indx = BUCKETINDX(size);
        kbp = &bucket[indx];
        s = splimp();
        indx = BUCKETINDX(size);
        kbp = &bucket[indx];
        s = splimp();
+       IN;
+again:
+#ifdef KMEMSTATS
+       while (ksp->ks_memuse >= ksp->ks_limit) {
+               if (flags & M_NOWAIT) {
+                       OUT;
+                       splx(s);
+                       return (0);
+               }
+               if (ksp->ks_limblocks < 65535)
+                       ksp->ks_limblocks++;
+               OUT;
+               sleep((caddr_t)ksp, PSWP+2);
+               IN;
+       }
+#endif
        if (kbp->kb_next == NULL) {
                if (size > MAXALLOCSAVE)
                        allocsize = roundup(size, CLBYTES);
        if (kbp->kb_next == NULL) {
                if (size > MAXALLOCSAVE)
                        allocsize = roundup(size, CLBYTES);
@@ -49,21 +83,31 @@ qaddr_t malloc(size, type, flags)
                        allocsize = 1 << indx;
                npg = clrnd(btoc(allocsize));
                if ((flags & M_NOWAIT) && freemem < npg) {
                        allocsize = 1 << indx;
                npg = clrnd(btoc(allocsize));
                if ((flags & M_NOWAIT) && freemem < npg) {
+                       OUT;
                        splx(s);
                        return (0);
                }
                alloc = rmalloc(kmemmap, npg);
                if (alloc == 0) {
                        splx(s);
                        return (0);
                }
                alloc = rmalloc(kmemmap, npg);
                if (alloc == 0) {
-                       splx(s);
-                       return (0);
-               }
-               if (vmemall(&kmempt[alloc], npg, &proc[0], CSYS) == 0) {
-                       rmfree(kmemmap, npg, alloc);
-                       splx(s);
-                       return (0);
+                       if (flags & M_NOWAIT) {
+                               OUT;
+                               splx(s);
+                               return (0);
+                       }
+#ifdef KMEMSTATS
+                       if (ksp->ks_mapblocks < 65535)
+                               ksp->ks_mapblocks++;
+#endif
+                       wantkmemmap++;
+                       OUT;
+                       sleep((caddr_t)&wantkmemmap, PSWP+2);
+                       IN;
+                       goto again;
                }
                }
+               alloc -= CLSIZE;                /* convert to base 0 */
+               (void) vmemall(&kmempt[alloc], (int)npg, &proc[0], CSYS);
                va = (caddr_t) kmemxtob(alloc);
                va = (caddr_t) kmemxtob(alloc);
-               vmaccess(&kmempt[alloc], va, npg);
+               vmaccess(&kmempt[alloc], va, (int)npg);
 #ifdef KMEMSTATS
                kbp->kb_total += kbp->kb_elmpercl;
 #endif
 #ifdef KMEMSTATS
                kbp->kb_total += kbp->kb_elmpercl;
 #endif
@@ -73,6 +117,9 @@ qaddr_t malloc(size, type, flags)
                        if (npg > 65535)
                                panic("malloc: allocation too large");
                        kup->ku_pagecnt = npg;
                        if (npg > 65535)
                                panic("malloc: allocation too large");
                        kup->ku_pagecnt = npg;
+#ifdef KMEMSTATS
+                       ksp->ks_memuse += allocsize;
+#endif
                        goto out;
                }
 #ifdef KMEMSTATS
                        goto out;
                }
 #ifdef KMEMSTATS
@@ -80,12 +127,21 @@ qaddr_t malloc(size, type, flags)
                kbp->kb_totalfree += kbp->kb_elmpercl;
 #endif
                kbp->kb_next = va + (npg * NBPG) - allocsize;
                kbp->kb_totalfree += kbp->kb_elmpercl;
 #endif
                kbp->kb_next = va + (npg * NBPG) - allocsize;
-               for(cp = kbp->kb_next; cp > va; cp -= allocsize)
-                       *(caddr_t *)cp = cp - allocsize;
-               *(caddr_t *)cp = NULL;
+               for (cp = kbp->kb_next; cp >= va; cp -= allocsize) {
+                       ((caddr_t *)cp)[2] = (cp > va ? cp - allocsize : NULL);
+                       if (indx == 7) {
+                               long *lp = (long *)cp;
+                               lp[0] = lp[1] = lp[3] = lp[4] = -1;
+                       }
+               }
        }
        va = kbp->kb_next;
        }
        va = kbp->kb_next;
-       kbp->kb_next = *(caddr_t *)va;
+       kbp->kb_next = ((caddr_t *)va)[2];
+       if (indx == 7) {
+               long *lp = (long *)va;
+               if (lp[0] != -1 || lp[1] != -1 || lp[3] != -1 || lp[4] != -1)
+                       panic("malloc meddled");
+       }
 #ifdef KMEMSTATS
        kup = btokup(va);
        if (kup->ku_indx != indx)
 #ifdef KMEMSTATS
        kup = btokup(va);
        if (kup->ku_indx != indx)
@@ -94,15 +150,17 @@ qaddr_t malloc(size, type, flags)
                panic("malloc: lost data");
        kup->ku_freecnt--;
        kbp->kb_totalfree--;
                panic("malloc: lost data");
        kup->ku_freecnt--;
        kbp->kb_totalfree--;
+       ksp->ks_memuse += 1 << indx;
 out:
        kbp->kb_calls++;
        ksp->ks_inuse++;
        ksp->ks_calls++;
 out:
        kbp->kb_calls++;
        ksp->ks_inuse++;
        ksp->ks_calls++;
-       if (ksp->ks_inuse > ksp->ks_maxused)
-               ksp->ks_maxused = ksp->ks_inuse;
+       if (ksp->ks_memuse > ksp->ks_maxused)
+               ksp->ks_maxused = ksp->ks_memuse;
 #else
 out:
 #endif
 #else
 out:
 #endif
+       OUT;
        splx(s);
        return ((qaddr_t)va);
 }
        splx(s);
        return ((qaddr_t)va);
 }
@@ -110,30 +168,51 @@ out:
 /*
  * Free a block of memory allocated by malloc.
  */
 /*
  * Free a block of memory allocated by malloc.
  */
-void free(addr, type)
+void
+free(addr, type)
        caddr_t addr;
        caddr_t addr;
-       long type;
+       int type;
 {
        register struct kmembuckets *kbp;
        register struct kmemusage *kup;
 {
        register struct kmembuckets *kbp;
        register struct kmemusage *kup;
-       long alloc, s;
+       long alloc, size;
+       int s;
+#ifdef KMEMSTATS
+       register struct kmemstats *ksp = &kmemstats[type];
+#endif
 
        kup = btokup(addr);
 
        kup = btokup(addr);
+       kbp = &bucket[kup->ku_indx];
        s = splimp();
        s = splimp();
-       if (1 << kup->ku_indx > MAXALLOCSAVE) {
+       IN;
+       size = 1 << kup->ku_indx;
+       if (size > MAXALLOCSAVE) {
                alloc = btokmemx(addr);
                alloc = btokmemx(addr);
-               (void) memfree(&kmempt[alloc], kup->ku_pagecnt, 0);
-               rmfree(kmemmap, (long)kup->ku_pagecnt, alloc);
+               (void) memfree(&kmempt[alloc], (int)kup->ku_pagecnt, 1);
+               rmfree(kmemmap, (long)kup->ku_pagecnt, alloc + CLSIZE);
+               OUT;
+               if (wantkmemmap) {
+                       wakeup((caddr_t)&wantkmemmap);
+                       wantkmemmap = 0;
+               }
 #ifdef KMEMSTATS
 #ifdef KMEMSTATS
+               size = kup->ku_pagecnt << PGSHIFT;
+               ksp->ks_memuse -= size;
                kup->ku_indx = 0;
                kup->ku_pagecnt = 0;
                kup->ku_indx = 0;
                kup->ku_pagecnt = 0;
-               kbp->kb_total -= kbp->kb_elmpercl;
-               kmemstats[type].ks_inuse--;
+               if (ksp->ks_memuse + size >= ksp->ks_limit &&
+                   ksp->ks_memuse < ksp->ks_limit)
+                       wakeup((caddr_t)ksp);
+               ksp->ks_inuse--;
+               kbp->kb_total -= 1;
 #endif
                splx(s);
                return;
        }
 #endif
                splx(s);
                return;
        }
-       kbp = &bucket[kup->ku_indx];
+       if (size == 128) {
+               long *lp = (long *)addr;
+               lp[0] = lp[1] = lp[3] = lp[4] = -1;
+       }
 #ifdef KMEMSTATS
        kup->ku_freecnt++;
        if (kup->ku_freecnt >= kbp->kb_elmpercl)
 #ifdef KMEMSTATS
        kup->ku_freecnt++;
        if (kup->ku_freecnt >= kbp->kb_elmpercl)
@@ -142,10 +221,15 @@ void free(addr, type)
                else if (kbp->kb_totalfree > kbp->kb_highwat)
                        kbp->kb_couldfree++;
        kbp->kb_totalfree++;
                else if (kbp->kb_totalfree > kbp->kb_highwat)
                        kbp->kb_couldfree++;
        kbp->kb_totalfree++;
-       kmemstats[type].ks_inuse--;
+       ksp->ks_memuse -= size;
+       if (ksp->ks_memuse + size >= ksp->ks_limit &&
+           ksp->ks_memuse < ksp->ks_limit)
+               wakeup((caddr_t)ksp);
+       ksp->ks_inuse--;
 #endif
 #endif
-       *(caddr_t *)addr = kbp->kb_next;
+       ((caddr_t *)addr)[2] = kbp->kb_next;
        kbp->kb_next = addr;
        kbp->kb_next = addr;
+       OUT;
        splx(s);
 }
 
        splx(s);
 }
 
@@ -155,15 +239,19 @@ void free(addr, type)
 kmeminit()
 {
        register long indx;
 kmeminit()
 {
        register long indx;
+       int npg;
 
 
-       if (!powerof2(MAXALLOCSAVE))
-               panic("kmeminit: MAXALLOCSAVE not power of 2");
-       if (MAXALLOCSAVE > MINALLOCSIZE * 32768)
-               panic("kmeminit: MAXALLOCSAVE too big");
-       if (MAXALLOCSAVE < CLBYTES)
-               panic("kmeminit: MAXALLOCSAVE too small");
-       rminit(kmemmap, ekmempt - kmempt, (long)1,
-               "malloc map", ekmempt - kmempt);
+#if    ((MAXALLOCSAVE & (MAXALLOCSAVE - 1)) != 0)
+               ERROR!_kmeminit:_MAXALLOCSAVE_not_power_of_2
+#endif
+#if    (MAXALLOCSAVE > MINALLOCSIZE * 32768)
+               ERROR!_kmeminit:_MAXALLOCSAVE_too_big
+#endif
+#if    (MAXALLOCSAVE < CLBYTES)
+               ERROR!_kmeminit:_MAXALLOCSAVE_too_small
+#endif
+       npg = ekmempt - kmempt;
+       rminit(kmemmap, (long)npg, (long)CLSIZE, "malloc map", npg);
 #ifdef KMEMSTATS
        for (indx = 0; indx < MINBUCKET + 16; indx++) {
                if (1 << indx >= CLBYTES)
 #ifdef KMEMSTATS
        for (indx = 0; indx < MINBUCKET + 16; indx++) {
                if (1 << indx >= CLBYTES)
@@ -173,6 +261,6 @@ kmeminit()
                bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl;
        }
        for (indx = 0; indx < M_LAST; indx++)
                bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl;
        }
        for (indx = 0; indx < M_LAST; indx++)
-               kmemstats[indx].ks_limit = 0x7fffffff;
+               kmemstats[indx].ks_limit = npg * NBPG * 6 / 10;
 #endif
 }
 #endif
 }