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