1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "error.h" 7 8 enum 9 { 10 Hdrspc = 64, /* leave room for high-level headers */ 11 Bdead = 0x51494F42, /* "QIOB" */ 12 }; 13 14 struct 15 { 16 Lock; 17 ulong bytes; 18 } ialloc; 19 20 static Block* 21 _allocb(int size) 22 { 23 Block *b; 24 ulong addr; 25 26 if((b = mallocz(sizeof(Block)+size+Hdrspc, 0)) == nil) 27 return nil; 28 29 b->next = nil; 30 b->list = nil; 31 b->free = 0; 32 b->flag = 0; 33 b->ref = 0; 34 _xinc(&b->ref); 35 36 /* align start of data portion by rounding up */ 37 addr = (ulong)b; 38 addr = ROUND(addr + sizeof(Block), BLOCKALIGN); 39 b->base = (uchar*)addr; 40 41 /* align end of data portion by rounding down */ 42 b->lim = ((uchar*)b) + msize(b); 43 addr = (ulong)(b->lim); 44 addr = addr & ~(BLOCKALIGN-1); 45 b->lim = (uchar*)addr; 46 47 /* leave sluff at beginning for added headers */ 48 b->rp = b->lim - ROUND(size, BLOCKALIGN); 49 if(b->rp < b->base) 50 panic("_allocb"); 51 b->wp = b->rp; 52 53 return b; 54 } 55 56 Block* 57 allocb(int size) 58 { 59 Block *b; 60 61 /* 62 * Check in a process and wait until successful. 63 * Can still error out of here, though. 64 */ 65 if(up == nil) 66 panic("allocb without up: %#p", getcallerpc(&size)); 67 if((b = _allocb(size)) == nil){ 68 xsummary(); 69 mallocsummary(); 70 panic("allocb: no memory for %d bytes", size); 71 } 72 setmalloctag(b, getcallerpc(&size)); 73 74 return b; 75 } 76 77 Block* 78 iallocb(int size) 79 { 80 Block *b; 81 static int m1, m2, mp; 82 83 if(ialloc.bytes > conf.ialloc){ 84 if((m1++%10000)==0){ 85 if(mp++ > 1000){ 86 active.exiting = 1; 87 exit(0); 88 } 89 iprint("iallocb: limited %lud/%lud\n", 90 ialloc.bytes, conf.ialloc); 91 } 92 return nil; 93 } 94 95 if((b = _allocb(size)) == nil){ 96 if((m2++%10000)==0){ 97 if(mp++ > 1000){ 98 active.exiting = 1; 99 exit(0); 100 } 101 iprint("iallocb: no memory %lud/%lud\n", 102 ialloc.bytes, conf.ialloc); 103 } 104 return nil; 105 } 106 setmalloctag(b, getcallerpc(&size)); 107 b->flag = BINTR; 108 109 ilock(&ialloc); 110 ialloc.bytes += b->lim - b->base; 111 iunlock(&ialloc); 112 113 return b; 114 } 115 116 void 117 freeb(Block *b) 118 { 119 void *dead = (void*)Bdead; 120 long ref; 121 122 if(b == nil || (ref = _xdec(&b->ref)) > 0) 123 return; 124 125 if(ref < 0){ 126 dumpstack(); 127 panic("ref %ld callerpc %#p", ref, getcallerpc(&b)); 128 } 129 130 /* 131 * drivers which perform non cache coherent DMA manage their own buffer 132 * pool of uncached buffers and provide their own free routine. 133 */ 134 if(b->free) { 135 b->free(b); 136 return; 137 } 138 if(b->flag & BINTR) { 139 ilock(&ialloc); 140 ialloc.bytes -= b->lim - b->base; 141 iunlock(&ialloc); 142 } 143 144 /* poison the block in case someone is still holding onto it */ 145 b->next = dead; 146 b->rp = dead; 147 b->wp = dead; 148 b->lim = dead; 149 b->base = dead; 150 151 free(b); 152 } 153 154 void 155 checkb(Block *b, char *msg) 156 { 157 void *dead = (void*)Bdead; 158 159 if(b == dead) 160 panic("checkb b %s %lux", msg, b); 161 if(b->base == dead || b->lim == dead || b->next == dead 162 || b->rp == dead || b->wp == dead){ 163 print("checkb: base %#p lim %#p next %#p\n", 164 b->base, b->lim, b->next); 165 print("checkb: rp %#p wp %#p\n", b->rp, b->wp); 166 panic("checkb dead: %s", msg); 167 } 168 169 if(b->base > b->lim) 170 panic("checkb 0 %s %#p %#p", msg, b->base, b->lim); 171 if(b->rp < b->base) 172 panic("checkb 1 %s %#p %#p", msg, b->base, b->rp); 173 if(b->wp < b->base) 174 panic("checkb 2 %s %#p %#p", msg, b->base, b->wp); 175 if(b->rp > b->lim) 176 panic("checkb 3 %s %#p %#p", msg, b->rp, b->lim); 177 if(b->wp > b->lim) 178 panic("checkb 4 %s %#p %#p", msg, b->wp, b->lim); 179 } 180 181 void 182 iallocsummary(void) 183 { 184 print("ialloc %lud/%lud\n", ialloc.bytes, conf.ialloc); 185 } 186