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