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