19ef1f84bSDavid du Colombier /*
29ef1f84bSDavid du Colombier * malloc
39ef1f84bSDavid du Colombier *
49ef1f84bSDavid du Colombier * Uses Quickfit (see SIGPLAN Notices October 1988)
59ef1f84bSDavid du Colombier * with allocator from Kernighan & Ritchie
69ef1f84bSDavid du Colombier *
79ef1f84bSDavid du Colombier * This is a placeholder.
89ef1f84bSDavid du Colombier */
99ef1f84bSDavid du Colombier #include "u.h"
109ef1f84bSDavid du Colombier #include "../port/lib.h"
119ef1f84bSDavid du Colombier #include "mem.h"
129ef1f84bSDavid du Colombier #include "dat.h"
139ef1f84bSDavid du Colombier #include "fns.h"
149ef1f84bSDavid du Colombier
159ef1f84bSDavid du Colombier typedef double Align;
169ef1f84bSDavid du Colombier typedef union Header Header;
179ef1f84bSDavid du Colombier typedef struct Qlist Qlist;
189ef1f84bSDavid du Colombier
199ef1f84bSDavid du Colombier union Header {
209ef1f84bSDavid du Colombier struct {
219ef1f84bSDavid du Colombier Header* next;
229ef1f84bSDavid du Colombier uint size;
239ef1f84bSDavid du Colombier } s;
249ef1f84bSDavid du Colombier Align al;
259ef1f84bSDavid du Colombier };
269ef1f84bSDavid du Colombier
279ef1f84bSDavid du Colombier struct Qlist {
289ef1f84bSDavid du Colombier Lock lk;
299ef1f84bSDavid du Colombier Header* first;
309ef1f84bSDavid du Colombier
319ef1f84bSDavid du Colombier uint nalloc;
329ef1f84bSDavid du Colombier };
339ef1f84bSDavid du Colombier
349ef1f84bSDavid du Colombier enum {
359ef1f84bSDavid du Colombier Unitsz = sizeof(Header),
369ef1f84bSDavid du Colombier };
379ef1f84bSDavid du Colombier
389ef1f84bSDavid du Colombier #define NUNITS(n) (HOWMANY(n, Unitsz) + 1)
399ef1f84bSDavid du Colombier #define NQUICK ((4096/Unitsz)+1)
409ef1f84bSDavid du Colombier
419ef1f84bSDavid du Colombier static Qlist quicklist[NQUICK+1];
429ef1f84bSDavid du Colombier static Header misclist;
439ef1f84bSDavid du Colombier static Header *rover;
449ef1f84bSDavid du Colombier static unsigned tailsize;
459ef1f84bSDavid du Colombier static unsigned availnunits;
469ef1f84bSDavid du Colombier static Header *tailbase;
479ef1f84bSDavid du Colombier static Header *tailptr;
489ef1f84bSDavid du Colombier static Header checkval;
499ef1f84bSDavid du Colombier static int morecore(unsigned);
509ef1f84bSDavid du Colombier
519277c452SDavid du Colombier enum
529277c452SDavid du Colombier {
539277c452SDavid du Colombier QSmalign = 0,
549277c452SDavid du Colombier QSmalignquick,
559277c452SDavid du Colombier QSmalignrover,
569277c452SDavid du Colombier QSmalignfront,
579277c452SDavid du Colombier QSmalignback,
589277c452SDavid du Colombier QSmaligntail,
599277c452SDavid du Colombier QSmalignnottail,
609277c452SDavid du Colombier QSmalloc,
619277c452SDavid du Colombier QSmallocrover,
629277c452SDavid du Colombier QSmalloctail,
639277c452SDavid du Colombier QSfree,
649277c452SDavid du Colombier QSfreetail,
659277c452SDavid du Colombier QSfreequick,
669277c452SDavid du Colombier QSfreenext,
679277c452SDavid du Colombier QSfreeprev,
689277c452SDavid du Colombier QSmax
699277c452SDavid du Colombier };
709277c452SDavid du Colombier
719277c452SDavid du Colombier static char* qstatstr[QSmax] = {
729277c452SDavid du Colombier [QSmalign] "malign",
739277c452SDavid du Colombier [QSmalignquick] "malignquick",
749277c452SDavid du Colombier [QSmalignrover] "malignrover",
759277c452SDavid du Colombier [QSmalignfront] "malignfront",
769277c452SDavid du Colombier [QSmalignback] "malignback",
779277c452SDavid du Colombier [QSmaligntail] "maligntail",
789277c452SDavid du Colombier [QSmalignnottail] "malignnottail",
799277c452SDavid du Colombier [QSmalloc] "malloc",
809277c452SDavid du Colombier [QSmallocrover] "mallocrover",
819277c452SDavid du Colombier [QSmalloctail] "malloctail",
829277c452SDavid du Colombier [QSfree] "free",
839277c452SDavid du Colombier [QSfreetail] "freetail",
849277c452SDavid du Colombier [QSfreequick] "freequick",
859277c452SDavid du Colombier [QSfreenext] "freenext",
869277c452SDavid du Colombier [QSfreeprev] "freeprev",
879277c452SDavid du Colombier };
889277c452SDavid du Colombier
899ef1f84bSDavid du Colombier static void* qmalloc(usize);
909ef1f84bSDavid du Colombier static void qfreeinternal(void*);
919277c452SDavid du Colombier static int qstats[QSmax];
929ef1f84bSDavid du Colombier
939ef1f84bSDavid du Colombier static Lock mainlock;
949ef1f84bSDavid du Colombier
959ef1f84bSDavid du Colombier #define MLOCK ilock(&mainlock)
969ef1f84bSDavid du Colombier #define MUNLOCK iunlock(&mainlock)
979ef1f84bSDavid du Colombier #define QLOCK(l) ilock(l)
989ef1f84bSDavid du Colombier #define QUNLOCK(l) iunlock(l)
999ef1f84bSDavid du Colombier
1009ef1f84bSDavid du Colombier #define tailalloc(p, n) ((p)=tailptr, tailsize -= (n), tailptr+=(n),\
1019ef1f84bSDavid du Colombier (p)->s.size=(n), (p)->s.next = &checkval)
1029ef1f84bSDavid du Colombier
1039ef1f84bSDavid du Colombier #define ISPOWEROF2(x) (/*((x) != 0) && */!((x) & ((x)-1)))
1049ef1f84bSDavid du Colombier #define ALIGNHDR(h, a) (Header*)((((uintptr)(h))+((a)-1)) & ~((a)-1))
1059ef1f84bSDavid du Colombier #define ALIGNED(h, a) ((((uintptr)(h)) & (a-1)) == 0)
1069ef1f84bSDavid du Colombier
1079ef1f84bSDavid du Colombier static void*
qmallocalign(usize nbytes,uintptr align,long offset,usize span)1089ef1f84bSDavid du Colombier qmallocalign(usize nbytes, uintptr align, long offset, usize span)
1099ef1f84bSDavid du Colombier {
1109ef1f84bSDavid du Colombier Qlist *qlist;
1119ef1f84bSDavid du Colombier uintptr aligned;
1129ef1f84bSDavid du Colombier Header **pp, *p, *q, *r;
1139ef1f84bSDavid du Colombier uint naligned, nunits, n;
1149ef1f84bSDavid du Colombier
1159ef1f84bSDavid du Colombier if(nbytes == 0 || offset != 0 || span != 0)
1169ef1f84bSDavid du Colombier return nil;
1179ef1f84bSDavid du Colombier
1189ef1f84bSDavid du Colombier if(!ISPOWEROF2(align))
1199ef1f84bSDavid du Colombier panic("qmallocalign");
1209ef1f84bSDavid du Colombier
1219ef1f84bSDavid du Colombier if(align <= sizeof(Align))
1229ef1f84bSDavid du Colombier return qmalloc(nbytes);
1239ef1f84bSDavid du Colombier
1249277c452SDavid du Colombier qstats[QSmalign]++;
1259ef1f84bSDavid du Colombier nunits = NUNITS(nbytes);
1269ef1f84bSDavid du Colombier if(nunits <= NQUICK){
1279ef1f84bSDavid du Colombier /*
1289ef1f84bSDavid du Colombier * Look for a conveniently aligned block
1299ef1f84bSDavid du Colombier * on one of the quicklists.
1309ef1f84bSDavid du Colombier */
1319ef1f84bSDavid du Colombier qlist = &quicklist[nunits];
1329ef1f84bSDavid du Colombier QLOCK(&qlist->lk);
1339ef1f84bSDavid du Colombier pp = &qlist->first;
1349ef1f84bSDavid du Colombier for(p = *pp; p != nil; p = p->s.next){
1359ef1f84bSDavid du Colombier if(ALIGNED(p+1, align)){
1369ef1f84bSDavid du Colombier *pp = p->s.next;
1379ef1f84bSDavid du Colombier p->s.next = &checkval;
1389ef1f84bSDavid du Colombier QUNLOCK(&qlist->lk);
1399277c452SDavid du Colombier qstats[QSmalignquick]++;
1409ef1f84bSDavid du Colombier return p+1;
1419ef1f84bSDavid du Colombier }
1429ef1f84bSDavid du Colombier pp = &p->s.next;
1439ef1f84bSDavid du Colombier }
1449ef1f84bSDavid du Colombier QUNLOCK(&qlist->lk);
1459ef1f84bSDavid du Colombier }
1469ef1f84bSDavid du Colombier
1479ef1f84bSDavid du Colombier MLOCK;
1489ef1f84bSDavid du Colombier if(nunits > tailsize) {
1499ef1f84bSDavid du Colombier /* hard way */
1509ef1f84bSDavid du Colombier if((q = rover) != nil){
1519ef1f84bSDavid du Colombier do {
1529ef1f84bSDavid du Colombier p = q->s.next;
1539ef1f84bSDavid du Colombier if(p->s.size < nunits)
1549ef1f84bSDavid du Colombier continue;
1559ef1f84bSDavid du Colombier aligned = ALIGNED(p+1, align);
1569ef1f84bSDavid du Colombier naligned = NUNITS(align)-1;
1579ef1f84bSDavid du Colombier if(!aligned && p->s.size < nunits+naligned)
1589ef1f84bSDavid du Colombier continue;
1599ef1f84bSDavid du Colombier
1609ef1f84bSDavid du Colombier /*
1619ef1f84bSDavid du Colombier * This block is big enough, remove it
1629ef1f84bSDavid du Colombier * from the list.
1639ef1f84bSDavid du Colombier */
1649ef1f84bSDavid du Colombier q->s.next = p->s.next;
1659ef1f84bSDavid du Colombier rover = q;
1669277c452SDavid du Colombier qstats[QSmalignrover]++;
1679ef1f84bSDavid du Colombier
1689ef1f84bSDavid du Colombier /*
1699ef1f84bSDavid du Colombier * Free any runt in front of the alignment.
1709ef1f84bSDavid du Colombier */
1719ef1f84bSDavid du Colombier if(!aligned){
1729ef1f84bSDavid du Colombier r = p;
1739ef1f84bSDavid du Colombier p = ALIGNHDR(p+1, align) - 1;
1749ef1f84bSDavid du Colombier n = p - r;
1759ef1f84bSDavid du Colombier p->s.size = r->s.size - n;
1769ef1f84bSDavid du Colombier
1779ef1f84bSDavid du Colombier r->s.size = n;
1789ef1f84bSDavid du Colombier r->s.next = &checkval;
1799ef1f84bSDavid du Colombier qfreeinternal(r+1);
1809277c452SDavid du Colombier qstats[QSmalignfront]++;
1819ef1f84bSDavid du Colombier }
1829ef1f84bSDavid du Colombier
1839ef1f84bSDavid du Colombier /*
1849ef1f84bSDavid du Colombier * Free any residue after the aligned block.
1859ef1f84bSDavid du Colombier */
1869ef1f84bSDavid du Colombier if(p->s.size > nunits){
1879ef1f84bSDavid du Colombier r = p+nunits;
1889ef1f84bSDavid du Colombier r->s.size = p->s.size - nunits;
1899ef1f84bSDavid du Colombier r->s.next = &checkval;
1909277c452SDavid du Colombier qstats[QSmalignback]++;
1919ef1f84bSDavid du Colombier qfreeinternal(r+1);
1929ef1f84bSDavid du Colombier
1939ef1f84bSDavid du Colombier p->s.size = nunits;
1949ef1f84bSDavid du Colombier }
1959ef1f84bSDavid du Colombier
1969ef1f84bSDavid du Colombier p->s.next = &checkval;
1979ef1f84bSDavid du Colombier MUNLOCK;
1989ef1f84bSDavid du Colombier return p+1;
1999ef1f84bSDavid du Colombier } while((q = p) != rover);
2009ef1f84bSDavid du Colombier }
2019ef1f84bSDavid du Colombier if((n = morecore(nunits)) == 0){
2029ef1f84bSDavid du Colombier MUNLOCK;
2039ef1f84bSDavid du Colombier return nil;
2049ef1f84bSDavid du Colombier }
2059ef1f84bSDavid du Colombier tailsize += n;
2069ef1f84bSDavid du Colombier }
2079ef1f84bSDavid du Colombier
2089ef1f84bSDavid du Colombier q = ALIGNHDR(tailptr+1, align);
2099ef1f84bSDavid du Colombier if(q == tailptr+1){
2109ef1f84bSDavid du Colombier tailalloc(p, nunits);
2119277c452SDavid du Colombier qstats[QSmaligntail]++;
2129ef1f84bSDavid du Colombier }
2139ef1f84bSDavid du Colombier else{
2149ef1f84bSDavid du Colombier naligned = NUNITS(align)-1;
2159ef1f84bSDavid du Colombier if(tailsize < nunits+naligned){
2169ef1f84bSDavid du Colombier /*
2179ef1f84bSDavid du Colombier * There are at least nunits,
2189ef1f84bSDavid du Colombier * get enough for alignment.
2199ef1f84bSDavid du Colombier */
2209ef1f84bSDavid du Colombier if((n = morecore(naligned)) == 0){
2219ef1f84bSDavid du Colombier MUNLOCK;
2229ef1f84bSDavid du Colombier return nil;
2239ef1f84bSDavid du Colombier }
2249ef1f84bSDavid du Colombier tailsize += n;
2259ef1f84bSDavid du Colombier }
2269ef1f84bSDavid du Colombier /*
2279ef1f84bSDavid du Colombier * Save the residue before the aligned allocation
2289ef1f84bSDavid du Colombier * and free it after the tail pointer has been bumped
2299ef1f84bSDavid du Colombier * for the main allocation.
2309ef1f84bSDavid du Colombier */
2319ef1f84bSDavid du Colombier n = q-tailptr - 1;
2329ef1f84bSDavid du Colombier tailalloc(r, n);
2339ef1f84bSDavid du Colombier tailalloc(p, nunits);
2349277c452SDavid du Colombier qstats[QSmalignnottail]++;
2359ef1f84bSDavid du Colombier qfreeinternal(r+1);
2369ef1f84bSDavid du Colombier }
2379ef1f84bSDavid du Colombier MUNLOCK;
2389ef1f84bSDavid du Colombier
2399ef1f84bSDavid du Colombier return p+1;
2409ef1f84bSDavid du Colombier }
2419ef1f84bSDavid du Colombier
2429ef1f84bSDavid du Colombier static void*
qmalloc(usize nbytes)2439ef1f84bSDavid du Colombier qmalloc(usize nbytes)
2449ef1f84bSDavid du Colombier {
2459ef1f84bSDavid du Colombier Qlist *qlist;
2469ef1f84bSDavid du Colombier Header *p, *q;
2479ef1f84bSDavid du Colombier uint nunits, n;
2489ef1f84bSDavid du Colombier
2499ef1f84bSDavid du Colombier ///* FIXME: (ignore for now)
2509ef1f84bSDavid du Colombier if(nbytes == 0)
2519ef1f84bSDavid du Colombier return nil;
2529ef1f84bSDavid du Colombier //*/
2539ef1f84bSDavid du Colombier
2549277c452SDavid du Colombier qstats[QSmalloc]++;
2559ef1f84bSDavid du Colombier nunits = NUNITS(nbytes);
2569ef1f84bSDavid du Colombier if(nunits <= NQUICK){
2579ef1f84bSDavid du Colombier qlist = &quicklist[nunits];
2589ef1f84bSDavid du Colombier QLOCK(&qlist->lk);
2599ef1f84bSDavid du Colombier if((p = qlist->first) != nil){
2609ef1f84bSDavid du Colombier qlist->first = p->s.next;
2619ef1f84bSDavid du Colombier qlist->nalloc++;
2629ef1f84bSDavid du Colombier QUNLOCK(&qlist->lk);
2639ef1f84bSDavid du Colombier p->s.next = &checkval;
2649ef1f84bSDavid du Colombier return p+1;
2659ef1f84bSDavid du Colombier }
2669ef1f84bSDavid du Colombier QUNLOCK(&qlist->lk);
2679ef1f84bSDavid du Colombier }
2689ef1f84bSDavid du Colombier
2699ef1f84bSDavid du Colombier MLOCK;
2709ef1f84bSDavid du Colombier if(nunits > tailsize) {
2719ef1f84bSDavid du Colombier /* hard way */
2729ef1f84bSDavid du Colombier if((q = rover) != nil){
2739ef1f84bSDavid du Colombier do {
2749ef1f84bSDavid du Colombier p = q->s.next;
2759ef1f84bSDavid du Colombier if(p->s.size >= nunits) {
2769ef1f84bSDavid du Colombier if(p->s.size > nunits) {
2779ef1f84bSDavid du Colombier p->s.size -= nunits;
2789ef1f84bSDavid du Colombier p += p->s.size;
2799ef1f84bSDavid du Colombier p->s.size = nunits;
2809ef1f84bSDavid du Colombier } else
2819ef1f84bSDavid du Colombier q->s.next = p->s.next;
2829ef1f84bSDavid du Colombier p->s.next = &checkval;
2839ef1f84bSDavid du Colombier rover = q;
2849277c452SDavid du Colombier qstats[QSmallocrover]++;
2859ef1f84bSDavid du Colombier MUNLOCK;
2869ef1f84bSDavid du Colombier return p+1;
2879ef1f84bSDavid du Colombier }
2889ef1f84bSDavid du Colombier } while((q = p) != rover);
2899ef1f84bSDavid du Colombier }
2909ef1f84bSDavid du Colombier if((n = morecore(nunits)) == 0){
2919ef1f84bSDavid du Colombier MUNLOCK;
2929ef1f84bSDavid du Colombier return nil;
2939ef1f84bSDavid du Colombier }
2949ef1f84bSDavid du Colombier tailsize += n;
2959ef1f84bSDavid du Colombier }
2969277c452SDavid du Colombier qstats[QSmalloctail]++;
2979ef1f84bSDavid du Colombier tailalloc(p, nunits);
2989ef1f84bSDavid du Colombier MUNLOCK;
2999ef1f84bSDavid du Colombier
3009ef1f84bSDavid du Colombier return p+1;
3019ef1f84bSDavid du Colombier }
3029ef1f84bSDavid du Colombier
3039ef1f84bSDavid du Colombier static void
qfreeinternal(void * ap)3049ef1f84bSDavid du Colombier qfreeinternal(void* ap)
3059ef1f84bSDavid du Colombier {
3069ef1f84bSDavid du Colombier Qlist *qlist;
3079ef1f84bSDavid du Colombier Header *p, *q;
3089ef1f84bSDavid du Colombier uint nunits;
3099ef1f84bSDavid du Colombier
3109ef1f84bSDavid du Colombier if(ap == nil)
3119ef1f84bSDavid du Colombier return;
3129277c452SDavid du Colombier qstats[QSfree]++;
3139ef1f84bSDavid du Colombier
3149ef1f84bSDavid du Colombier p = (Header*)ap - 1;
3159ef1f84bSDavid du Colombier if((nunits = p->s.size) == 0 || p->s.next != &checkval)
3169ef1f84bSDavid du Colombier panic("malloc: corrupt allocation arena");
3179ef1f84bSDavid du Colombier if(tailptr != nil && p+nunits == tailptr) {
3189ef1f84bSDavid du Colombier /* block before tail */
3199ef1f84bSDavid du Colombier tailptr = p;
3209ef1f84bSDavid du Colombier tailsize += nunits;
3219277c452SDavid du Colombier qstats[QSfreetail]++;
3229ef1f84bSDavid du Colombier return;
3239ef1f84bSDavid du Colombier }
3249ef1f84bSDavid du Colombier if(nunits <= NQUICK) {
3259ef1f84bSDavid du Colombier qlist = &quicklist[nunits];
3269ef1f84bSDavid du Colombier QLOCK(&qlist->lk);
3279ef1f84bSDavid du Colombier p->s.next = qlist->first;
3289ef1f84bSDavid du Colombier qlist->first = p;
3299ef1f84bSDavid du Colombier QUNLOCK(&qlist->lk);
3309277c452SDavid du Colombier qstats[QSfreequick]++;
3319ef1f84bSDavid du Colombier return;
3329ef1f84bSDavid du Colombier }
3339ef1f84bSDavid du Colombier if((q = rover) == nil) {
3349ef1f84bSDavid du Colombier q = &misclist;
3359ef1f84bSDavid du Colombier q->s.size = 0;
3369ef1f84bSDavid du Colombier q->s.next = q;
3379ef1f84bSDavid du Colombier }
3389ef1f84bSDavid du Colombier for(; !(p > q && p < q->s.next); q = q->s.next)
3399ef1f84bSDavid du Colombier if(q >= q->s.next && (p > q || p < q->s.next))
3409ef1f84bSDavid du Colombier break;
3419ef1f84bSDavid du Colombier if(p+p->s.size == q->s.next) {
3429ef1f84bSDavid du Colombier p->s.size += q->s.next->s.size;
3439ef1f84bSDavid du Colombier p->s.next = q->s.next->s.next;
3449277c452SDavid du Colombier qstats[QSfreenext]++;
3459ef1f84bSDavid du Colombier } else
3469ef1f84bSDavid du Colombier p->s.next = q->s.next;
3479ef1f84bSDavid du Colombier if(q+q->s.size == p) {
3489ef1f84bSDavid du Colombier q->s.size += p->s.size;
3499ef1f84bSDavid du Colombier q->s.next = p->s.next;
3509277c452SDavid du Colombier qstats[QSfreeprev]++;
3519ef1f84bSDavid du Colombier } else
3529ef1f84bSDavid du Colombier q->s.next = p;
3539ef1f84bSDavid du Colombier rover = q;
3549ef1f84bSDavid du Colombier }
3559ef1f84bSDavid du Colombier
3569ef1f84bSDavid du Colombier static void
mallocreadfmt(char * s,char * e)3579ef1f84bSDavid du Colombier mallocreadfmt(char* s, char* e)
3589ef1f84bSDavid du Colombier {
3599ef1f84bSDavid du Colombier char *p;
3609ef1f84bSDavid du Colombier Header *q;
3619ef1f84bSDavid du Colombier int i, n, t;
3629ef1f84bSDavid du Colombier Qlist *qlist;
3639ef1f84bSDavid du Colombier
3649ef1f84bSDavid du Colombier p = s;
3659ef1f84bSDavid du Colombier p = seprint(p, e, "%lud/%lud kernel malloc\n",
3669ef1f84bSDavid du Colombier (tailptr-tailbase)*sizeof(Header),
3679ef1f84bSDavid du Colombier (tailsize+availnunits + tailptr-tailbase)*sizeof(Header));
3689ef1f84bSDavid du Colombier p = seprint(p, e, "0/0 kernel draw\n"); // keep scripts happy
3699ef1f84bSDavid du Colombier
3709ef1f84bSDavid du Colombier t = 0;
3719ef1f84bSDavid du Colombier for(i = 0; i <= NQUICK; i++) {
3729ef1f84bSDavid du Colombier n = 0;
3739ef1f84bSDavid du Colombier qlist = &quicklist[i];
3749ef1f84bSDavid du Colombier QLOCK(&qlist->lk);
3759ef1f84bSDavid du Colombier for(q = qlist->first; q != nil; q = q->s.next){
3769ef1f84bSDavid du Colombier // if(q->s.size != i)
3779ef1f84bSDavid du Colombier // p = seprint(p, e, "q%d\t%#p\t%ud\n",
3789ef1f84bSDavid du Colombier // i, q, q->s.size);
3799ef1f84bSDavid du Colombier n++;
3809ef1f84bSDavid du Colombier }
3819ef1f84bSDavid du Colombier QUNLOCK(&qlist->lk);
3829ef1f84bSDavid du Colombier
3839ef1f84bSDavid du Colombier // if(n != 0)
3849ef1f84bSDavid du Colombier // p = seprint(p, e, "q%d %d\n", i, n);
3859ef1f84bSDavid du Colombier t += n * i*sizeof(Header);
3869ef1f84bSDavid du Colombier }
3879ef1f84bSDavid du Colombier p = seprint(p, e, "quick: %ud bytes total\n", t);
3889ef1f84bSDavid du Colombier
3899ef1f84bSDavid du Colombier MLOCK;
3909ef1f84bSDavid du Colombier if((q = rover) != nil){
3919ef1f84bSDavid du Colombier i = t = 0;
3929ef1f84bSDavid du Colombier do {
3939ef1f84bSDavid du Colombier t += q->s.size;
3949ef1f84bSDavid du Colombier i++;
3959ef1f84bSDavid du Colombier // p = seprint(p, e, "m%d\t%#p\n", q->s.size, q);
3969ef1f84bSDavid du Colombier } while((q = q->s.next) != rover);
3979ef1f84bSDavid du Colombier
3989ef1f84bSDavid du Colombier p = seprint(p, e, "rover: %d blocks %ud bytes total\n",
3999ef1f84bSDavid du Colombier i, t*sizeof(Header));
4009ef1f84bSDavid du Colombier }
4019ef1f84bSDavid du Colombier
4029ef1f84bSDavid du Colombier for(i = 0; i < nelem(qstats); i++){
4039ef1f84bSDavid du Colombier if(qstats[i] == 0)
4049ef1f84bSDavid du Colombier continue;
4059277c452SDavid du Colombier // p = seprint(p, e, "%s %ud\n", qstatstr[i], qstats[i]);
4069ef1f84bSDavid du Colombier }
4079ef1f84bSDavid du Colombier USED(p);
4089ef1f84bSDavid du Colombier MUNLOCK;
4099ef1f84bSDavid du Colombier }
4109ef1f84bSDavid du Colombier
4119ef1f84bSDavid du Colombier long
mallocreadsummary(Chan *,void * a,long n,long offset)4129ef1f84bSDavid du Colombier mallocreadsummary(Chan*, void *a, long n, long offset)
4139ef1f84bSDavid du Colombier {
4149ef1f84bSDavid du Colombier char *alloc;
4159ef1f84bSDavid du Colombier
4169ef1f84bSDavid du Colombier alloc = malloc(16*READSTR);
4179ef1f84bSDavid du Colombier if(waserror()){
4189ef1f84bSDavid du Colombier free(alloc);
4199ef1f84bSDavid du Colombier nexterror();
4209ef1f84bSDavid du Colombier }
4219ef1f84bSDavid du Colombier mallocreadfmt(alloc, alloc+16*READSTR);
4229ef1f84bSDavid du Colombier n = readstr(offset, a, n, alloc);
4239ef1f84bSDavid du Colombier poperror();
4249ef1f84bSDavid du Colombier free(alloc);
4259ef1f84bSDavid du Colombier
4269ef1f84bSDavid du Colombier return n;
4279ef1f84bSDavid du Colombier }
4289ef1f84bSDavid du Colombier
4299ef1f84bSDavid du Colombier void
mallocsummary(void)4309ef1f84bSDavid du Colombier mallocsummary(void)
4319ef1f84bSDavid du Colombier {
4329ef1f84bSDavid du Colombier Header *q;
4339ef1f84bSDavid du Colombier int i, n, t;
4349ef1f84bSDavid du Colombier Qlist *qlist;
4359ef1f84bSDavid du Colombier
4369ef1f84bSDavid du Colombier t = 0;
4379ef1f84bSDavid du Colombier for(i = 0; i <= NQUICK; i++) {
4389ef1f84bSDavid du Colombier n = 0;
4399ef1f84bSDavid du Colombier qlist = &quicklist[i];
4409ef1f84bSDavid du Colombier QLOCK(&qlist->lk);
4419ef1f84bSDavid du Colombier for(q = qlist->first; q != nil; q = q->s.next){
4429ef1f84bSDavid du Colombier if(q->s.size != i)
4439ef1f84bSDavid du Colombier DBG("q%d\t%#p\t%ud\n", i, q, q->s.size);
4449ef1f84bSDavid du Colombier n++;
4459ef1f84bSDavid du Colombier }
4469ef1f84bSDavid du Colombier QUNLOCK(&qlist->lk);
4479ef1f84bSDavid du Colombier
4489ef1f84bSDavid du Colombier t += n * i*sizeof(Header);
4499ef1f84bSDavid du Colombier }
4509ef1f84bSDavid du Colombier print("quick: %ud bytes total\n", t);
4519ef1f84bSDavid du Colombier
4529ef1f84bSDavid du Colombier MLOCK;
4539ef1f84bSDavid du Colombier if((q = rover) != nil){
4549ef1f84bSDavid du Colombier i = t = 0;
4559ef1f84bSDavid du Colombier do {
4569ef1f84bSDavid du Colombier t += q->s.size;
4579ef1f84bSDavid du Colombier i++;
4589ef1f84bSDavid du Colombier } while((q = q->s.next) != rover);
4599ef1f84bSDavid du Colombier }
4609ef1f84bSDavid du Colombier MUNLOCK;
4619ef1f84bSDavid du Colombier
4629ef1f84bSDavid du Colombier if(i != 0){
4639ef1f84bSDavid du Colombier print("rover: %d blocks %ud bytes total\n",
4649ef1f84bSDavid du Colombier i, t*sizeof(Header));
4659ef1f84bSDavid du Colombier }
4669ef1f84bSDavid du Colombier print("total allocated %lud, %ud remaining\n",
4679ef1f84bSDavid du Colombier (tailptr-tailbase)*sizeof(Header),
4689ef1f84bSDavid du Colombier (tailsize+availnunits)*sizeof(Header));
4699ef1f84bSDavid du Colombier
4709ef1f84bSDavid du Colombier for(i = 0; i < nelem(qstats); i++){
4719ef1f84bSDavid du Colombier if(qstats[i] == 0)
4729ef1f84bSDavid du Colombier continue;
4739277c452SDavid du Colombier print("%s %ud\n", qstatstr[i], qstats[i]);
4749ef1f84bSDavid du Colombier }
4759ef1f84bSDavid du Colombier }
4769ef1f84bSDavid du Colombier
4779ef1f84bSDavid du Colombier void
free(void * ap)4789ef1f84bSDavid du Colombier free(void* ap)
4799ef1f84bSDavid du Colombier {
4809ef1f84bSDavid du Colombier MLOCK;
4819ef1f84bSDavid du Colombier qfreeinternal(ap);
4829ef1f84bSDavid du Colombier MUNLOCK;
4839ef1f84bSDavid du Colombier }
4849ef1f84bSDavid du Colombier
4859ef1f84bSDavid du Colombier void*
malloc(ulong size)4869ef1f84bSDavid du Colombier malloc(ulong size)
4879ef1f84bSDavid du Colombier {
4889ef1f84bSDavid du Colombier void* v;
4899ef1f84bSDavid du Colombier
4909ef1f84bSDavid du Colombier if((v = qmalloc(size)) != nil)
4919ef1f84bSDavid du Colombier memset(v, 0, size);
4929ef1f84bSDavid du Colombier
4939ef1f84bSDavid du Colombier return v;
4949ef1f84bSDavid du Colombier }
4959ef1f84bSDavid du Colombier
4969ef1f84bSDavid du Colombier void*
mallocz(ulong size,int clr)4979ef1f84bSDavid du Colombier mallocz(ulong size, int clr)
4989ef1f84bSDavid du Colombier {
4999ef1f84bSDavid du Colombier void *v;
5009ef1f84bSDavid du Colombier
5019ef1f84bSDavid du Colombier if((v = qmalloc(size)) != nil && clr)
5029ef1f84bSDavid du Colombier memset(v, 0, size);
5039ef1f84bSDavid du Colombier
5049ef1f84bSDavid du Colombier return v;
5059ef1f84bSDavid du Colombier }
5069ef1f84bSDavid du Colombier
5079ef1f84bSDavid du Colombier void*
mallocalign(ulong nbytes,ulong align,long offset,ulong span)5089ef1f84bSDavid du Colombier mallocalign(ulong nbytes, ulong align, long offset, ulong span)
5099ef1f84bSDavid du Colombier {
5109ef1f84bSDavid du Colombier void *v;
5119ef1f84bSDavid du Colombier
5129ef1f84bSDavid du Colombier if(span != 0 && align <= span){
5139ef1f84bSDavid du Colombier if(nbytes > span)
5149ef1f84bSDavid du Colombier return nil;
5159ef1f84bSDavid du Colombier align = span;
5169ef1f84bSDavid du Colombier span = 0;
5179ef1f84bSDavid du Colombier }
5189ef1f84bSDavid du Colombier
5199ef1f84bSDavid du Colombier /*
5209ef1f84bSDavid du Colombier * Should this memset or should it be left to the caller?
5219ef1f84bSDavid du Colombier */
5229ef1f84bSDavid du Colombier if((v = qmallocalign(nbytes, align, offset, span)) != nil)
5239ef1f84bSDavid du Colombier memset(v, 0, nbytes);
5249ef1f84bSDavid du Colombier
5259ef1f84bSDavid du Colombier return v;
5269ef1f84bSDavid du Colombier }
5279ef1f84bSDavid du Colombier
5289ef1f84bSDavid du Colombier void*
smalloc(ulong size)5299ef1f84bSDavid du Colombier smalloc(ulong size)
5309ef1f84bSDavid du Colombier {
5319ef1f84bSDavid du Colombier void *v;
5329ef1f84bSDavid du Colombier
5339ef1f84bSDavid du Colombier while((v = malloc(size)) == nil)
5349ef1f84bSDavid du Colombier tsleep(&up->sleep, return0, 0, 100);
5359ef1f84bSDavid du Colombier memset(v, 0, size);
5369ef1f84bSDavid du Colombier
5379ef1f84bSDavid du Colombier return v;
5389ef1f84bSDavid du Colombier }
5399ef1f84bSDavid du Colombier
5409ef1f84bSDavid du Colombier void*
realloc(void * ap,ulong size)5419ef1f84bSDavid du Colombier realloc(void* ap, ulong size)
5429ef1f84bSDavid du Colombier {
5439ef1f84bSDavid du Colombier void *v;
5449ef1f84bSDavid du Colombier Header *p;
5459ef1f84bSDavid du Colombier ulong osize;
5469ef1f84bSDavid du Colombier uint nunits, ounits;
5479ef1f84bSDavid du Colombier int delta;
5489ef1f84bSDavid du Colombier
5499ef1f84bSDavid du Colombier /*
5509ef1f84bSDavid du Colombier * Easy stuff:
5519ef1f84bSDavid du Colombier * free and return nil if size is 0
5529ef1f84bSDavid du Colombier * (implementation-defined behaviour);
5539ef1f84bSDavid du Colombier * behave like malloc if ap is nil;
5549ef1f84bSDavid du Colombier * check for arena corruption;
5559ef1f84bSDavid du Colombier * do nothing if units are the same.
5569ef1f84bSDavid du Colombier */
5579ef1f84bSDavid du Colombier if(size == 0){
5589ef1f84bSDavid du Colombier MLOCK;
5599ef1f84bSDavid du Colombier qfreeinternal(ap);
5609ef1f84bSDavid du Colombier MUNLOCK;
5619ef1f84bSDavid du Colombier
5629ef1f84bSDavid du Colombier return nil;
5639ef1f84bSDavid du Colombier }
5649ef1f84bSDavid du Colombier if(ap == nil)
5659ef1f84bSDavid du Colombier return qmalloc(size);
5669ef1f84bSDavid du Colombier
5679ef1f84bSDavid du Colombier p = (Header*)ap - 1;
5689ef1f84bSDavid du Colombier if((ounits = p->s.size) == 0 || p->s.next != &checkval)
5699ef1f84bSDavid du Colombier panic("realloc: corrupt allocation arena");
5709ef1f84bSDavid du Colombier
5719ef1f84bSDavid du Colombier if((nunits = NUNITS(size)) == ounits)
5729ef1f84bSDavid du Colombier return ap;
5739ef1f84bSDavid du Colombier
5749ef1f84bSDavid du Colombier /*
5759ef1f84bSDavid du Colombier * Slightly harder:
5769ef1f84bSDavid du Colombier * if this allocation abuts the tail, try to just
5779ef1f84bSDavid du Colombier * adjust the tailptr.
5789ef1f84bSDavid du Colombier */
5799ef1f84bSDavid du Colombier MLOCK;
5809ef1f84bSDavid du Colombier if(tailptr != nil && p+ounits == tailptr){
5819ef1f84bSDavid du Colombier delta = nunits-ounits;
5829ef1f84bSDavid du Colombier if(delta < 0 || tailsize >= delta){
5839ef1f84bSDavid du Colombier p->s.size = nunits;
5849ef1f84bSDavid du Colombier tailsize -= delta;
5859ef1f84bSDavid du Colombier tailptr += delta;
5869ef1f84bSDavid du Colombier MUNLOCK;
5879ef1f84bSDavid du Colombier return ap;
5889ef1f84bSDavid du Colombier }
5899ef1f84bSDavid du Colombier }
5909ef1f84bSDavid du Colombier MUNLOCK;
5919ef1f84bSDavid du Colombier
5929ef1f84bSDavid du Colombier /*
5939ef1f84bSDavid du Colombier * Worth doing if it's a small reduction?
5949ef1f84bSDavid du Colombier * Do it anyway if <= NQUICK?
5959ef1f84bSDavid du Colombier if((ounits-nunits) < 2)
5969ef1f84bSDavid du Colombier return ap;
5979ef1f84bSDavid du Colombier */
5989ef1f84bSDavid du Colombier
5999ef1f84bSDavid du Colombier /*
6009ef1f84bSDavid du Colombier * Too hard (or can't be bothered):
6019ef1f84bSDavid du Colombier * allocate, copy and free.
6029ef1f84bSDavid du Colombier * What does the standard say for failure here?
6039ef1f84bSDavid du Colombier */
6049ef1f84bSDavid du Colombier if((v = qmalloc(size)) != nil){
6059ef1f84bSDavid du Colombier osize = (ounits-1)*sizeof(Header);
6069ef1f84bSDavid du Colombier if(size < osize)
6079ef1f84bSDavid du Colombier osize = size;
6089ef1f84bSDavid du Colombier memmove(v, ap, osize);
6099ef1f84bSDavid du Colombier MLOCK;
6109ef1f84bSDavid du Colombier qfreeinternal(ap);
6119ef1f84bSDavid du Colombier MUNLOCK;
6129ef1f84bSDavid du Colombier }
6139ef1f84bSDavid du Colombier
6149ef1f84bSDavid du Colombier return v;
6159ef1f84bSDavid du Colombier }
6169ef1f84bSDavid du Colombier
6179ef1f84bSDavid du Colombier void
setmalloctag(void *,ulong)6189ef1f84bSDavid du Colombier setmalloctag(void*, ulong)
6199ef1f84bSDavid du Colombier {
6209ef1f84bSDavid du Colombier }
6219ef1f84bSDavid du Colombier
6229ef1f84bSDavid du Colombier void
mallocinit(void)6239ef1f84bSDavid du Colombier mallocinit(void)
6249ef1f84bSDavid du Colombier {
6259ef1f84bSDavid du Colombier if(tailptr != nil)
6269ef1f84bSDavid du Colombier return;
6279ef1f84bSDavid du Colombier
6289ef1f84bSDavid du Colombier tailbase = UINT2PTR(sys->vmunused);
6299ef1f84bSDavid du Colombier tailptr = tailbase;
6309ef1f84bSDavid du Colombier availnunits = HOWMANY(sys->vmend - sys->vmunused, Unitsz);
6319ef1f84bSDavid du Colombier print("base %#p ptr %#p nunits %ud\n", tailbase, tailptr, availnunits);
6329ef1f84bSDavid du Colombier }
6339ef1f84bSDavid du Colombier
6349ef1f84bSDavid du Colombier static int
morecore(uint nunits)6359ef1f84bSDavid du Colombier morecore(uint nunits)
6369ef1f84bSDavid du Colombier {
6379ef1f84bSDavid du Colombier /*
6389ef1f84bSDavid du Colombier * First (simple) cut.
6399ef1f84bSDavid du Colombier * Pump it up when you don't really need it.
6409ef1f84bSDavid du Colombier * Pump it up until you can feel it.
6419ef1f84bSDavid du Colombier */
642*f4d540d3SDavid du Colombier if(nunits < NUNITS(128*KiB))
6439ef1f84bSDavid du Colombier nunits = NUNITS(128*KiB);
644*f4d540d3SDavid du Colombier if(nunits > availnunits)
645*f4d540d3SDavid du Colombier nunits = availnunits;
6469ef1f84bSDavid du Colombier availnunits -= nunits;
6479ef1f84bSDavid du Colombier
6489ef1f84bSDavid du Colombier return nunits;
6499ef1f84bSDavid du Colombier }
650