xref: /plan9/sys/src/9/port/allocb.c (revision 6083aa4307383671473908ab2d661f80fbf6814b)
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