131422Smckusick /* 231422Smckusick * Copyright (c) 1987 Regents of the University of California. 333439Smckusick * All rights reserved. 431422Smckusick * 533439Smckusick * Redistribution and use in source and binary forms are permitted 633439Smckusick * provided that this notice is preserved and that due credit is given 733439Smckusick * to the University of California at Berkeley. The name of the University 833439Smckusick * may not be used to endorse or promote products derived from this 933439Smckusick * software without specific prior written permission. This software 1033439Smckusick * is provided ``as is'' without express or implied warranty. 1133439Smckusick * 12*34534Skarels * @(#)kern_malloc.c 7.9 (Berkeley) 05/27/88 1331422Smckusick */ 1431422Smckusick 1531422Smckusick #include "param.h" 1631422Smckusick #include "vm.h" 1731422Smckusick #include "cmap.h" 1831422Smckusick #include "time.h" 1931422Smckusick #include "proc.h" 2031422Smckusick #include "map.h" 2131422Smckusick #include "kernel.h" 2231422Smckusick #include "malloc.h" 2331422Smckusick 2431422Smckusick #include "../machine/pte.h" 2531422Smckusick 2631422Smckusick struct kmembuckets bucket[MINBUCKET + 16]; 2731422Smckusick struct kmemstats kmemstats[M_LAST]; 2831422Smckusick struct kmemusage *kmemusage; 2933438Smckusick long wantkmemmap; 3031422Smckusick 3131422Smckusick /* 3231422Smckusick * Allocate a block of memory 3331422Smckusick */ 3433497Smckusick qaddr_t 3533497Smckusick malloc(size, type, flags) 3631422Smckusick unsigned long size; 37*34534Skarels int type, flags; 3831422Smckusick { 3931422Smckusick register struct kmembuckets *kbp; 4031422Smckusick register struct kmemusage *kup; 41*34534Skarels long indx, npg, alloc, allocsize; 42*34534Skarels int s; 4331422Smckusick caddr_t va, cp; 4431422Smckusick #ifdef KMEMSTATS 4533438Smckusick register struct kmemstats *ksp = &kmemstats[type]; 4633438Smckusick #endif 4731422Smckusick 4831422Smckusick indx = BUCKETINDX(size); 4931422Smckusick kbp = &bucket[indx]; 5031422Smckusick s = splimp(); 5133438Smckusick again: 5233438Smckusick #ifdef KMEMSTATS 5333613Smckusick while (ksp->ks_memuse >= ksp->ks_limit) { 5433438Smckusick if (flags & M_NOWAIT) { 5533438Smckusick splx(s); 5633438Smckusick return (0); 5733438Smckusick } 5833438Smckusick if (ksp->ks_limblocks < 65535) 5933438Smckusick ksp->ks_limblocks++; 6033438Smckusick sleep((caddr_t)ksp, PSWP+2); 6133438Smckusick } 6233438Smckusick #endif 6331422Smckusick if (kbp->kb_next == NULL) { 6431422Smckusick if (size > MAXALLOCSAVE) 6531422Smckusick allocsize = roundup(size, CLBYTES); 6631422Smckusick else 6731422Smckusick allocsize = 1 << indx; 6831422Smckusick npg = clrnd(btoc(allocsize)); 6931422Smckusick if ((flags & M_NOWAIT) && freemem < npg) { 7031422Smckusick splx(s); 7131422Smckusick return (0); 7231422Smckusick } 7331422Smckusick alloc = rmalloc(kmemmap, npg); 7431422Smckusick if (alloc == 0) { 7533438Smckusick if (flags & M_NOWAIT) { 7633438Smckusick splx(s); 7733438Smckusick return (0); 7833438Smckusick } 7933438Smckusick #ifdef KMEMSTATS 8033438Smckusick if (ksp->ks_mapblocks < 65535) 8133438Smckusick ksp->ks_mapblocks++; 8233438Smckusick #endif 8333438Smckusick wantkmemmap++; 8433438Smckusick sleep((caddr_t)&wantkmemmap, PSWP+2); 8533438Smckusick goto again; 8631422Smckusick } 8732530Skre alloc -= CLSIZE; /* convert to base 0 */ 88*34534Skarels (void) vmemall(&kmempt[alloc], (int)npg, &proc[0], CSYS); 8931422Smckusick va = (caddr_t) kmemxtob(alloc); 90*34534Skarels vmaccess(&kmempt[alloc], va, (int)npg); 9131422Smckusick #ifdef KMEMSTATS 9231422Smckusick kbp->kb_total += kbp->kb_elmpercl; 9331422Smckusick #endif 9431422Smckusick kup = btokup(va); 9531422Smckusick kup->ku_indx = indx; 9631422Smckusick if (allocsize > MAXALLOCSAVE) { 9731422Smckusick if (npg > 65535) 9831422Smckusick panic("malloc: allocation too large"); 9931422Smckusick kup->ku_pagecnt = npg; 10033438Smckusick #ifdef KMEMSTATS 10133438Smckusick ksp->ks_memuse += allocsize; 10233438Smckusick #endif 10331422Smckusick goto out; 10431422Smckusick } 10531422Smckusick #ifdef KMEMSTATS 10631422Smckusick kup->ku_freecnt = kbp->kb_elmpercl; 10731422Smckusick kbp->kb_totalfree += kbp->kb_elmpercl; 10831422Smckusick #endif 10931422Smckusick kbp->kb_next = va + (npg * NBPG) - allocsize; 11033438Smckusick for (cp = kbp->kb_next; cp > va; cp -= allocsize) 11131422Smckusick *(caddr_t *)cp = cp - allocsize; 11231422Smckusick *(caddr_t *)cp = NULL; 11331422Smckusick } 11431422Smckusick va = kbp->kb_next; 11531422Smckusick kbp->kb_next = *(caddr_t *)va; 11631422Smckusick #ifdef KMEMSTATS 11731422Smckusick kup = btokup(va); 11831422Smckusick if (kup->ku_indx != indx) 11931422Smckusick panic("malloc: wrong bucket"); 12031422Smckusick if (kup->ku_freecnt == 0) 12131422Smckusick panic("malloc: lost data"); 12231422Smckusick kup->ku_freecnt--; 12331422Smckusick kbp->kb_totalfree--; 12433438Smckusick ksp->ks_memuse += 1 << indx; 12531422Smckusick out: 12631422Smckusick kbp->kb_calls++; 12731422Smckusick ksp->ks_inuse++; 12831422Smckusick ksp->ks_calls++; 12933613Smckusick if (ksp->ks_memuse > ksp->ks_maxused) 13033613Smckusick ksp->ks_maxused = ksp->ks_memuse; 13131422Smckusick #else 13231422Smckusick out: 13331422Smckusick #endif 13431422Smckusick splx(s); 13531422Smckusick return ((qaddr_t)va); 13631422Smckusick } 13731422Smckusick 13831422Smckusick /* 13931422Smckusick * Free a block of memory allocated by malloc. 14031422Smckusick */ 14133497Smckusick void 14233497Smckusick free(addr, type) 14331422Smckusick caddr_t addr; 144*34534Skarels int type; 14531422Smckusick { 14631422Smckusick register struct kmembuckets *kbp; 14731422Smckusick register struct kmemusage *kup; 148*34534Skarels long alloc, size; 149*34534Skarels int s; 15033438Smckusick #ifdef KMEMSTATS 15133438Smckusick register struct kmemstats *ksp = &kmemstats[type]; 15233438Smckusick #endif 15331422Smckusick 15431422Smckusick kup = btokup(addr); 15533497Smckusick kbp = &bucket[kup->ku_indx]; 15631422Smckusick s = splimp(); 15733613Smckusick size = 1 << kup->ku_indx; 15833613Smckusick if (size > MAXALLOCSAVE) { 15931422Smckusick alloc = btokmemx(addr); 160*34534Skarels (void) memfree(&kmempt[alloc], (int)kup->ku_pagecnt, 0); 16133438Smckusick rmfree(kmemmap, (long)kup->ku_pagecnt, alloc + CLSIZE); 16233438Smckusick if (wantkmemmap) { 16333438Smckusick wakeup((caddr_t)&wantkmemmap); 16433438Smckusick wantkmemmap = 0; 16533438Smckusick } 16631422Smckusick #ifdef KMEMSTATS 16733613Smckusick size = kup->ku_pagecnt << PGSHIFT; 16833613Smckusick ksp->ks_memuse -= size; 16931422Smckusick kup->ku_indx = 0; 17031422Smckusick kup->ku_pagecnt = 0; 17133613Smckusick if (ksp->ks_memuse + size >= ksp->ks_limit && 17233613Smckusick ksp->ks_memuse < ksp->ks_limit) 17333438Smckusick wakeup((caddr_t)ksp); 17433438Smckusick ksp->ks_inuse--; 17533497Smckusick kbp->kb_total -= 1; 17631422Smckusick #endif 17731422Smckusick splx(s); 17831422Smckusick return; 17931422Smckusick } 18031422Smckusick #ifdef KMEMSTATS 18131422Smckusick kup->ku_freecnt++; 18231422Smckusick if (kup->ku_freecnt >= kbp->kb_elmpercl) 18331422Smckusick if (kup->ku_freecnt > kbp->kb_elmpercl) 18431422Smckusick panic("free: multiple frees"); 18531422Smckusick else if (kbp->kb_totalfree > kbp->kb_highwat) 18631422Smckusick kbp->kb_couldfree++; 18731422Smckusick kbp->kb_totalfree++; 18833613Smckusick ksp->ks_memuse -= size; 18933613Smckusick if (ksp->ks_memuse + size >= ksp->ks_limit && 19033613Smckusick ksp->ks_memuse < ksp->ks_limit) 19133438Smckusick wakeup((caddr_t)ksp); 19233438Smckusick ksp->ks_inuse--; 19331422Smckusick #endif 19431422Smckusick *(caddr_t *)addr = kbp->kb_next; 19531422Smckusick kbp->kb_next = addr; 19631422Smckusick splx(s); 19731422Smckusick } 19831422Smckusick 19931422Smckusick /* 20031422Smckusick * Initialize the kernel memory allocator 20131422Smckusick */ 20231422Smckusick kmeminit() 20331422Smckusick { 20431422Smckusick register long indx; 20533497Smckusick int npg; 20631422Smckusick 207*34534Skarels #if ((MAXALLOCSAVE & (MAXALLOCSAVE - 1)) != 0) 208*34534Skarels ERROR!_kmeminit:_MAXALLOCSAVE_not_power_of_2 209*34534Skarels #endif 210*34534Skarels #if (MAXALLOCSAVE > MINALLOCSIZE * 32768) 211*34534Skarels ERROR!_kmeminit:_MAXALLOCSAVE_too_big 212*34534Skarels #endif 213*34534Skarels #if (MAXALLOCSAVE < CLBYTES) 214*34534Skarels ERROR!_kmeminit:_MAXALLOCSAVE_too_small 215*34534Skarels #endif 21633497Smckusick npg = ekmempt - kmempt; 217*34534Skarels rminit(kmemmap, (long)npg, (long)CLSIZE, "malloc map", npg); 21831422Smckusick #ifdef KMEMSTATS 21931422Smckusick for (indx = 0; indx < MINBUCKET + 16; indx++) { 22031422Smckusick if (1 << indx >= CLBYTES) 22131422Smckusick bucket[indx].kb_elmpercl = 1; 22231422Smckusick else 22331422Smckusick bucket[indx].kb_elmpercl = CLBYTES / (1 << indx); 22431422Smckusick bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl; 22531422Smckusick } 22631422Smckusick for (indx = 0; indx < M_LAST; indx++) 22733497Smckusick kmemstats[indx].ks_limit = npg * CLBYTES * 8 / 10; 22831422Smckusick #endif 22931422Smckusick } 230