1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "../port/error.h"
7
8 #define NFREECHAN 64
9 #define IHASHSIZE 64
10 #define ihash(s) imagealloc.hash[s%IHASHSIZE]
11
12 enum
13 {
14 NIMAGE = 200,
15 };
16
17 static struct Imagealloc
18 {
19 Lock;
20 Image *free;
21 Image *hash[IHASHSIZE];
22 QLock ireclaim; /* mutex on reclaiming free images */
23
24 Chan **freechan; /* free image channels */
25 int nfreechan; /* number of free channels */
26 int szfreechan; /* size of freechan array */
27 QLock fcreclaim; /* mutex on reclaiming free channels */
28 } imagealloc;
29
30 static struct {
31 int calls; /* times imagereclaim was called */
32 int loops; /* times the main loop was run */
33 uvlong ticks; /* total time in the main loop */
34 uvlong maxt; /* longest time in main loop */
35 } irstats;
36
37 void
initimage(void)38 initimage(void)
39 {
40 Image *i, *ie;
41
42 imagealloc.free = malloc(NIMAGE*sizeof(Image));
43 if(imagealloc.free == nil)
44 panic("imagealloc: no memory");
45 ie = &imagealloc.free[NIMAGE-1];
46 for(i = imagealloc.free; i < ie; i++)
47 i->next = i+1;
48 i->next = 0;
49 imagealloc.freechan = malloc(NFREECHAN * sizeof(Chan*));
50 imagealloc.szfreechan = NFREECHAN;
51 }
52
53 static void
imagereclaim(void)54 imagereclaim(void)
55 {
56 uvlong ticks;
57
58 irstats.calls++;
59 /* Somebody is already cleaning the page cache */
60 if(!canqlock(&imagealloc.ireclaim))
61 return;
62
63 ticks = pagereclaim(1000);
64
65 irstats.loops++;
66 irstats.ticks += ticks;
67 if(ticks > irstats.maxt)
68 irstats.maxt = ticks;
69 //print("T%llud+", ticks);
70 qunlock(&imagealloc.ireclaim);
71 }
72
73 /*
74 * since close can block, this has to be called outside of
75 * spin locks.
76 */
77 static void
imagechanreclaim(void)78 imagechanreclaim(void)
79 {
80 Chan *c;
81
82 /* Somebody is already cleaning the image chans */
83 if(!canqlock(&imagealloc.fcreclaim))
84 return;
85
86 /*
87 * We don't have to recheck that nfreechan > 0 after we
88 * acquire the lock, because we're the only ones who decrement
89 * it (the other lock contender increments it), and there's only
90 * one of us thanks to the qlock above.
91 */
92 while(imagealloc.nfreechan > 0){
93 lock(&imagealloc);
94 imagealloc.nfreechan--;
95 c = imagealloc.freechan[imagealloc.nfreechan];
96 unlock(&imagealloc);
97 cclose(c);
98 }
99
100 qunlock(&imagealloc.fcreclaim);
101 }
102
103 Image*
attachimage(int type,Chan * c,int color,uintptr base,uintptr top)104 attachimage(int type, Chan *c, int color, uintptr base, uintptr top)
105 {
106 Image *i, **l;
107
108 /* reclaim any free channels from reclaimed segments */
109 if(imagealloc.nfreechan)
110 imagechanreclaim();
111
112 lock(&imagealloc);
113
114 /*
115 * Search the image cache for remains of the text from a previous
116 * or currently running incarnation
117 */
118 for(i = ihash(c->qid.path); i; i = i->hash) {
119 if(c->qid.path == i->qid.path) {
120 lock(i);
121 if(eqqid(c->qid, i->qid) &&
122 eqqid(c->mqid, i->mqid) &&
123 c->mchan == i->mchan &&
124 c->dev->dc == i->dc) {
125 //subtype
126 goto found;
127 }
128 unlock(i);
129 }
130 }
131
132 /*
133 * imagereclaim dumps pages from the free list which are cached by image
134 * structures. This should free some image structures.
135 */
136 while(!(i = imagealloc.free)) {
137 unlock(&imagealloc);
138 imagereclaim();
139 sched();
140 lock(&imagealloc);
141 }
142
143 imagealloc.free = i->next;
144
145 lock(i);
146 incref(c);
147 i->c = c;
148 i->dc = c->dev->dc;
149 //subtype
150 i->qid = c->qid;
151 i->mqid = c->mqid;
152 i->mchan = c->mchan;
153 i->color = color;
154 l = &ihash(c->qid.path);
155 i->hash = *l;
156 *l = i;
157 found:
158 unlock(&imagealloc);
159
160 if(i->s == 0) {
161 /* Disaster after commit in exec */
162 if(waserror()) {
163 unlock(i);
164 pexit(Enovmem, 1);
165 }
166 i->s = newseg(type, base, top);
167 i->s->image = i;
168 i->s->color = color;
169 i->ref++;
170 poperror();
171 }
172 else
173 incref(i->s);
174
175 return i;
176 }
177
178 void
putimage(Image * i)179 putimage(Image *i)
180 {
181 Chan *c, **cp;
182 Image *f, **l;
183
184 if(i->notext)
185 return;
186
187 lock(i);
188 if(--i->ref == 0) {
189 l = &ihash(i->qid.path);
190 mkqid(&i->qid, ~0, ~0, QTFILE);
191 unlock(i);
192 c = i->c;
193
194 lock(&imagealloc);
195 for(f = *l; f; f = f->hash) {
196 if(f == i) {
197 *l = i->hash;
198 break;
199 }
200 l = &f->hash;
201 }
202
203 i->next = imagealloc.free;
204 imagealloc.free = i;
205
206 /* defer freeing channel till we're out of spin lock's */
207 if(imagealloc.nfreechan == imagealloc.szfreechan){
208 imagealloc.szfreechan += NFREECHAN;
209 cp = malloc(imagealloc.szfreechan*sizeof(Chan*));
210 if(cp == nil)
211 panic("putimage");
212 memmove(cp, imagealloc.freechan, imagealloc.nfreechan*sizeof(Chan*));
213 free(imagealloc.freechan);
214 imagealloc.freechan = cp;
215 }
216 imagealloc.freechan[imagealloc.nfreechan++] = c;
217 unlock(&imagealloc);
218
219 return;
220 }
221 unlock(i);
222 }
223