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