1 /* 2 * Copyright (c) 1987 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 * 6 * @(#)kern_malloc.c 7.4 (Berkeley) 10/23/87 7 */ 8 9 #include "param.h" 10 #include "vm.h" 11 #include "cmap.h" 12 #include "time.h" 13 #include "proc.h" 14 #include "map.h" 15 #include "kernel.h" 16 #include "malloc.h" 17 18 #include "../machine/pte.h" 19 20 struct kmembuckets bucket[MINBUCKET + 16]; 21 struct kmemstats kmemstats[M_LAST]; 22 struct kmemusage *kmemusage; 23 24 /* 25 * Allocate a block of memory 26 */ 27 qaddr_t malloc(size, type, flags) 28 unsigned long size; 29 long type, flags; 30 { 31 register struct kmembuckets *kbp; 32 register struct kmemusage *kup; 33 long indx, npg, alloc, allocsize, s; 34 caddr_t va, cp; 35 #ifdef KMEMSTATS 36 register struct kmemstats *ksp; 37 38 ksp = &kmemstats[type]; 39 if (ksp->ks_inuse >= ksp->ks_limit) 40 return (0); 41 #endif 42 indx = BUCKETINDX(size); 43 kbp = &bucket[indx]; 44 s = splimp(); 45 if (kbp->kb_next == NULL) { 46 if (size > MAXALLOCSAVE) 47 allocsize = roundup(size, CLBYTES); 48 else 49 allocsize = 1 << indx; 50 npg = clrnd(btoc(allocsize)); 51 if ((flags & M_NOWAIT) && freemem < npg) { 52 splx(s); 53 return (0); 54 } 55 alloc = rmalloc(kmemmap, npg); 56 if (alloc == 0) { 57 splx(s); 58 return (0); 59 } 60 alloc -= CLSIZE; /* convert to base 0 */ 61 if (vmemall(&kmempt[alloc], npg, &proc[0], CSYS) == 0) { 62 rmfree(kmemmap, npg, alloc+CLSIZE); 63 splx(s); 64 return (0); 65 } 66 va = (caddr_t) kmemxtob(alloc); 67 vmaccess(&kmempt[alloc], va, npg); 68 #ifdef KMEMSTATS 69 kbp->kb_total += kbp->kb_elmpercl; 70 #endif 71 kup = btokup(va); 72 kup->ku_indx = indx; 73 if (allocsize > MAXALLOCSAVE) { 74 if (npg > 65535) 75 panic("malloc: allocation too large"); 76 kup->ku_pagecnt = npg; 77 goto out; 78 } 79 #ifdef KMEMSTATS 80 kup->ku_freecnt = kbp->kb_elmpercl; 81 kbp->kb_totalfree += kbp->kb_elmpercl; 82 #endif 83 kbp->kb_next = va + (npg * NBPG) - allocsize; 84 for(cp = kbp->kb_next; cp > va; cp -= allocsize) 85 *(caddr_t *)cp = cp - allocsize; 86 *(caddr_t *)cp = NULL; 87 } 88 va = kbp->kb_next; 89 kbp->kb_next = *(caddr_t *)va; 90 #ifdef KMEMSTATS 91 kup = btokup(va); 92 if (kup->ku_indx != indx) 93 panic("malloc: wrong bucket"); 94 if (kup->ku_freecnt == 0) 95 panic("malloc: lost data"); 96 kup->ku_freecnt--; 97 kbp->kb_totalfree--; 98 out: 99 kbp->kb_calls++; 100 ksp->ks_inuse++; 101 ksp->ks_calls++; 102 if (ksp->ks_inuse > ksp->ks_maxused) 103 ksp->ks_maxused = ksp->ks_inuse; 104 #else 105 out: 106 #endif 107 splx(s); 108 return ((qaddr_t)va); 109 } 110 111 /* 112 * Free a block of memory allocated by malloc. 113 */ 114 void free(addr, type) 115 caddr_t addr; 116 long type; 117 { 118 register struct kmembuckets *kbp; 119 register struct kmemusage *kup; 120 long alloc, s; 121 122 kup = btokup(addr); 123 s = splimp(); 124 if (1 << kup->ku_indx > MAXALLOCSAVE) { 125 alloc = btokmemx(addr); 126 (void) memfree(&kmempt[alloc], kup->ku_pagecnt, 0); 127 rmfree(kmemmap, (long)kup->ku_pagecnt, alloc+CLSIZE); 128 #ifdef KMEMSTATS 129 kup->ku_indx = 0; 130 kup->ku_pagecnt = 0; 131 kmemstats[type].ks_inuse--; 132 #endif 133 splx(s); 134 return; 135 } 136 kbp = &bucket[kup->ku_indx]; 137 #ifdef KMEMSTATS 138 kup->ku_freecnt++; 139 if (kup->ku_freecnt >= kbp->kb_elmpercl) 140 if (kup->ku_freecnt > kbp->kb_elmpercl) 141 panic("free: multiple frees"); 142 else if (kbp->kb_totalfree > kbp->kb_highwat) 143 kbp->kb_couldfree++; 144 kbp->kb_totalfree++; 145 kmemstats[type].ks_inuse--; 146 #endif 147 *(caddr_t *)addr = kbp->kb_next; 148 kbp->kb_next = addr; 149 splx(s); 150 } 151 152 /* 153 * Initialize the kernel memory allocator 154 */ 155 kmeminit() 156 { 157 register long indx; 158 159 if (!powerof2(MAXALLOCSAVE)) 160 panic("kmeminit: MAXALLOCSAVE not power of 2"); 161 if (MAXALLOCSAVE > MINALLOCSIZE * 32768) 162 panic("kmeminit: MAXALLOCSAVE too big"); 163 if (MAXALLOCSAVE < CLBYTES) 164 panic("kmeminit: MAXALLOCSAVE too small"); 165 rminit(kmemmap, ekmempt - kmempt, (long)CLSIZE, 166 "malloc map", ekmempt - kmempt); 167 #ifdef KMEMSTATS 168 for (indx = 0; indx < MINBUCKET + 16; indx++) { 169 if (1 << indx >= CLBYTES) 170 bucket[indx].kb_elmpercl = 1; 171 else 172 bucket[indx].kb_elmpercl = CLBYTES / (1 << indx); 173 bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl; 174 } 175 for (indx = 0; indx < M_LAST; indx++) 176 kmemstats[indx].ks_limit = 0x7fffffff; 177 #endif 178 } 179