xref: /plan9-contrib/sys/src/9k/port/image.c (revision 094d68186d4cdde21fdab9786d6c843a03693e4e)
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