xref: /plan9/sys/src/9/port/allocb.c (revision ec59a3ddbfceee0efe34584c2c9981a5e5ff1ec4)
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 
34 	/* align start of data portion by rounding up */
35 	addr = (ulong)b;
36 	addr = ROUND(addr + sizeof(Block), BLOCKALIGN);
37 	b->base = (uchar*)addr;
38 
39 	/* align end of data portion by rounding down */
40 	b->lim = ((uchar*)b) + msize(b);
41 	addr = (ulong)(b->lim);
42 	addr = addr & ~(BLOCKALIGN-1);
43 	b->lim = (uchar*)addr;
44 
45 	/* leave sluff at beginning for added headers */
46 	b->rp = b->lim - ROUND(size, BLOCKALIGN);
47 	if(b->rp < b->base)
48 		panic("_allocb");
49 	b->wp = b->rp;
50 
51 	return b;
52 }
53 
54 Block*
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: %luX\n", getcallerpc(&size));
65 	if((b = _allocb(size)) == nil){
66 		xsummary();
67 		mallocsummary();
68 		panic("allocb: no memory for %d bytes\n", size);
69 	}
70 	setmalloctag(b, getcallerpc(&size));
71 
72 	return b;
73 }
74 
75 Block*
76 iallocb(int size)
77 {
78 	Block *b;
79 	static int m1, m2, mp;
80 
81 	if(ialloc.bytes > conf.ialloc){
82 		if((m1++%10000)==0){
83 			if(mp++ > 1000){
84 				active.exiting = 1;
85 				exit(0);
86 			}
87 			iprint("iallocb: limited %lud/%lud\n",
88 				ialloc.bytes, conf.ialloc);
89 		}
90 		return nil;
91 	}
92 
93 	if((b = _allocb(size)) == nil){
94 		if((m2++%10000)==0){
95 			if(mp++ > 1000){
96 				active.exiting = 1;
97 				exit(0);
98 			}
99 			iprint("iallocb: no memory %lud/%lud\n",
100 				ialloc.bytes, conf.ialloc);
101 		}
102 		return nil;
103 	}
104 	setmalloctag(b, getcallerpc(&size));
105 	b->flag = BINTR;
106 
107 	ilock(&ialloc);
108 	ialloc.bytes += b->lim - b->base;
109 	iunlock(&ialloc);
110 
111 	return b;
112 }
113 
114 void
115 freeb(Block *b)
116 {
117 	void *dead = (void*)Bdead;
118 
119 	if(b == nil)
120 		return;
121 
122 	/*
123 	 * drivers which perform non cache coherent DMA manage their own buffer
124 	 * pool of uncached buffers and provide their own free routine.
125 	 */
126 	if(b->free) {
127 		b->free(b);
128 		return;
129 	}
130 	if(b->flag & BINTR) {
131 		ilock(&ialloc);
132 		ialloc.bytes -= b->lim - b->base;
133 		iunlock(&ialloc);
134 	}
135 
136 	/* poison the block in case someone is still holding onto it */
137 	b->next = dead;
138 	b->rp = dead;
139 	b->wp = dead;
140 	b->lim = dead;
141 	b->base = dead;
142 
143 	free(b);
144 }
145 
146 void
147 checkb(Block *b, char *msg)
148 {
149 	void *dead = (void*)Bdead;
150 
151 	if(b == dead)
152 		panic("checkb b %s %lux", msg, b);
153 	if(b->base == dead || b->lim == dead || b->next == dead
154 	  || b->rp == dead || b->wp == dead){
155 		print("checkb: base 0x%8.8luX lim 0x%8.8luX next 0x%8.8luX\n",
156 			b->base, b->lim, b->next);
157 		print("checkb: rp 0x%8.8luX wp 0x%8.8luX\n", b->rp, b->wp);
158 		panic("checkb dead: %s\n", msg);
159 	}
160 
161 	if(b->base > b->lim)
162 		panic("checkb 0 %s %lux %lux", msg, b->base, b->lim);
163 	if(b->rp < b->base)
164 		panic("checkb 1 %s %lux %lux", msg, b->base, b->rp);
165 	if(b->wp < b->base)
166 		panic("checkb 2 %s %lux %lux", msg, b->base, b->wp);
167 	if(b->rp > b->lim)
168 		panic("checkb 3 %s %lux %lux", msg, b->rp, b->lim);
169 	if(b->wp > b->lim)
170 		panic("checkb 4 %s %lux %lux", msg, b->wp, b->lim);
171 
172 }
173 
174 void
175 iallocsummary(void)
176 {
177 	print("ialloc %lud/%lud\n", ialloc.bytes, conf.ialloc);
178 }
179