xref: /plan9-contrib/sys/src/9k/port/image.c (revision 094d68186d4cdde21fdab9786d6c843a03693e4e)
19ef1f84bSDavid du Colombier #include	"u.h"
29ef1f84bSDavid du Colombier #include	"../port/lib.h"
39ef1f84bSDavid du Colombier #include	"mem.h"
49ef1f84bSDavid du Colombier #include	"dat.h"
59ef1f84bSDavid du Colombier #include	"fns.h"
69ef1f84bSDavid du Colombier #include	"../port/error.h"
79ef1f84bSDavid du Colombier 
89ef1f84bSDavid du Colombier #define NFREECHAN	64
99ef1f84bSDavid du Colombier #define IHASHSIZE	64
109ef1f84bSDavid du Colombier #define ihash(s)	imagealloc.hash[s%IHASHSIZE]
119ef1f84bSDavid du Colombier 
129ef1f84bSDavid du Colombier enum
139ef1f84bSDavid du Colombier {
149ef1f84bSDavid du Colombier 	NIMAGE = 200,
159ef1f84bSDavid du Colombier };
169ef1f84bSDavid du Colombier 
179ef1f84bSDavid du Colombier static struct Imagealloc
189ef1f84bSDavid du Colombier {
199ef1f84bSDavid du Colombier 	Lock;
209ef1f84bSDavid du Colombier 	Image	*free;
219ef1f84bSDavid du Colombier 	Image	*hash[IHASHSIZE];
229ef1f84bSDavid du Colombier 	QLock	ireclaim;		/* mutex on reclaiming free images */
239ef1f84bSDavid du Colombier 
249ef1f84bSDavid du Colombier 	Chan	**freechan;		/* free image channels */
259ef1f84bSDavid du Colombier 	int	nfreechan;		/* number of free channels */
269ef1f84bSDavid du Colombier 	int	szfreechan;		/* size of freechan array */
279ef1f84bSDavid du Colombier 	QLock	fcreclaim;		/* mutex on reclaiming free channels */
289ef1f84bSDavid du Colombier } imagealloc;
299ef1f84bSDavid du Colombier 
309ef1f84bSDavid du Colombier static struct {
319ef1f84bSDavid du Colombier 	int	calls;			/* times imagereclaim was called */
329ef1f84bSDavid du Colombier 	int	loops;			/* times the main loop was run */
339ef1f84bSDavid du Colombier 	uvlong	ticks;			/* total time in the main loop */
349ef1f84bSDavid du Colombier 	uvlong	maxt;			/* longest time in main loop */
359ef1f84bSDavid du Colombier } irstats;
369ef1f84bSDavid du Colombier 
379ef1f84bSDavid du Colombier void
initimage(void)389ef1f84bSDavid du Colombier initimage(void)
399ef1f84bSDavid du Colombier {
409ef1f84bSDavid du Colombier 	Image *i, *ie;
419ef1f84bSDavid du Colombier 
429ef1f84bSDavid du Colombier 	imagealloc.free = malloc(NIMAGE*sizeof(Image));
439ef1f84bSDavid du Colombier 	if(imagealloc.free == nil)
449ef1f84bSDavid du Colombier 		panic("imagealloc: no memory");
459ef1f84bSDavid du Colombier 	ie = &imagealloc.free[NIMAGE-1];
469ef1f84bSDavid du Colombier 	for(i = imagealloc.free; i < ie; i++)
479ef1f84bSDavid du Colombier 		i->next = i+1;
489ef1f84bSDavid du Colombier 	i->next = 0;
499ef1f84bSDavid du Colombier 	imagealloc.freechan = malloc(NFREECHAN * sizeof(Chan*));
509ef1f84bSDavid du Colombier 	imagealloc.szfreechan = NFREECHAN;
519ef1f84bSDavid du Colombier }
529ef1f84bSDavid du Colombier 
539ef1f84bSDavid du Colombier static void
imagereclaim(void)549ef1f84bSDavid du Colombier imagereclaim(void)
559ef1f84bSDavid du Colombier {
569ef1f84bSDavid du Colombier 	uvlong ticks;
579ef1f84bSDavid du Colombier 
589ef1f84bSDavid du Colombier 	irstats.calls++;
599ef1f84bSDavid du Colombier 	/* Somebody is already cleaning the page cache */
609ef1f84bSDavid du Colombier 	if(!canqlock(&imagealloc.ireclaim))
619ef1f84bSDavid du Colombier 		return;
629ef1f84bSDavid du Colombier 
639ef1f84bSDavid du Colombier 	ticks = pagereclaim(1000);
649ef1f84bSDavid du Colombier 
659ef1f84bSDavid du Colombier 	irstats.loops++;
669ef1f84bSDavid du Colombier 	irstats.ticks += ticks;
679ef1f84bSDavid du Colombier 	if(ticks > irstats.maxt)
689ef1f84bSDavid du Colombier 		irstats.maxt = ticks;
699ef1f84bSDavid du Colombier 	//print("T%llud+", ticks);
709ef1f84bSDavid du Colombier 	qunlock(&imagealloc.ireclaim);
719ef1f84bSDavid du Colombier }
729ef1f84bSDavid du Colombier 
739ef1f84bSDavid du Colombier /*
749ef1f84bSDavid du Colombier  *  since close can block, this has to be called outside of
759ef1f84bSDavid du Colombier  *  spin locks.
769ef1f84bSDavid du Colombier  */
779ef1f84bSDavid du Colombier static void
imagechanreclaim(void)789ef1f84bSDavid du Colombier imagechanreclaim(void)
799ef1f84bSDavid du Colombier {
809ef1f84bSDavid du Colombier 	Chan *c;
819ef1f84bSDavid du Colombier 
829ef1f84bSDavid du Colombier 	/* Somebody is already cleaning the image chans */
839ef1f84bSDavid du Colombier 	if(!canqlock(&imagealloc.fcreclaim))
849ef1f84bSDavid du Colombier 		return;
859ef1f84bSDavid du Colombier 
869ef1f84bSDavid du Colombier 	/*
879ef1f84bSDavid du Colombier 	 * We don't have to recheck that nfreechan > 0 after we
889ef1f84bSDavid du Colombier 	 * acquire the lock, because we're the only ones who decrement
899ef1f84bSDavid du Colombier 	 * it (the other lock contender increments it), and there's only
909ef1f84bSDavid du Colombier 	 * one of us thanks to the qlock above.
919ef1f84bSDavid du Colombier 	 */
929ef1f84bSDavid du Colombier 	while(imagealloc.nfreechan > 0){
939ef1f84bSDavid du Colombier 		lock(&imagealloc);
949ef1f84bSDavid du Colombier 		imagealloc.nfreechan--;
959ef1f84bSDavid du Colombier 		c = imagealloc.freechan[imagealloc.nfreechan];
969ef1f84bSDavid du Colombier 		unlock(&imagealloc);
979ef1f84bSDavid du Colombier 		cclose(c);
989ef1f84bSDavid du Colombier 	}
999ef1f84bSDavid du Colombier 
1009ef1f84bSDavid du Colombier 	qunlock(&imagealloc.fcreclaim);
1019ef1f84bSDavid du Colombier }
1029ef1f84bSDavid du Colombier 
1039ef1f84bSDavid du Colombier Image*
attachimage(int type,Chan * c,int color,uintptr base,uintptr top)104*094d6818SDavid du Colombier attachimage(int type, Chan *c, int color, uintptr base, uintptr top)
1059ef1f84bSDavid du Colombier {
1069ef1f84bSDavid du Colombier 	Image *i, **l;
1079ef1f84bSDavid du Colombier 
1089ef1f84bSDavid du Colombier 	/* reclaim any free channels from reclaimed segments */
1099ef1f84bSDavid du Colombier 	if(imagealloc.nfreechan)
1109ef1f84bSDavid du Colombier 		imagechanreclaim();
1119ef1f84bSDavid du Colombier 
1129ef1f84bSDavid du Colombier 	lock(&imagealloc);
1139ef1f84bSDavid du Colombier 
1149ef1f84bSDavid du Colombier 	/*
1159ef1f84bSDavid du Colombier 	 * Search the image cache for remains of the text from a previous
1169ef1f84bSDavid du Colombier 	 * or currently running incarnation
1179ef1f84bSDavid du Colombier 	 */
1189ef1f84bSDavid du Colombier 	for(i = ihash(c->qid.path); i; i = i->hash) {
1199ef1f84bSDavid du Colombier 		if(c->qid.path == i->qid.path) {
1209ef1f84bSDavid du Colombier 			lock(i);
1219ef1f84bSDavid du Colombier 			if(eqqid(c->qid, i->qid) &&
1229ef1f84bSDavid du Colombier 			   eqqid(c->mqid, i->mqid) &&
1239ef1f84bSDavid du Colombier 			   c->mchan == i->mchan &&
1249ef1f84bSDavid du Colombier 			   c->dev->dc == i->dc) {
1259ef1f84bSDavid du Colombier //subtype
1269ef1f84bSDavid du Colombier 				goto found;
1279ef1f84bSDavid du Colombier 			}
1289ef1f84bSDavid du Colombier 			unlock(i);
1299ef1f84bSDavid du Colombier 		}
1309ef1f84bSDavid du Colombier 	}
1319ef1f84bSDavid du Colombier 
1329ef1f84bSDavid du Colombier 	/*
1339ef1f84bSDavid du Colombier 	 * imagereclaim dumps pages from the free list which are cached by image
1349ef1f84bSDavid du Colombier 	 * structures. This should free some image structures.
1359ef1f84bSDavid du Colombier 	 */
1369ef1f84bSDavid du Colombier 	while(!(i = imagealloc.free)) {
1379ef1f84bSDavid du Colombier 		unlock(&imagealloc);
1389ef1f84bSDavid du Colombier 		imagereclaim();
1399ef1f84bSDavid du Colombier 		sched();
1409ef1f84bSDavid du Colombier 		lock(&imagealloc);
1419ef1f84bSDavid du Colombier 	}
1429ef1f84bSDavid du Colombier 
1439ef1f84bSDavid du Colombier 	imagealloc.free = i->next;
1449ef1f84bSDavid du Colombier 
1459ef1f84bSDavid du Colombier 	lock(i);
1469ef1f84bSDavid du Colombier 	incref(c);
1479ef1f84bSDavid du Colombier 	i->c = c;
1489ef1f84bSDavid du Colombier 	i->dc = c->dev->dc;
1499ef1f84bSDavid du Colombier //subtype
1509ef1f84bSDavid du Colombier 	i->qid = c->qid;
1519ef1f84bSDavid du Colombier 	i->mqid = c->mqid;
1529ef1f84bSDavid du Colombier 	i->mchan = c->mchan;
153*094d6818SDavid du Colombier 	i->color = color;
1549ef1f84bSDavid du Colombier 	l = &ihash(c->qid.path);
1559ef1f84bSDavid du Colombier 	i->hash = *l;
1569ef1f84bSDavid du Colombier 	*l = i;
1579ef1f84bSDavid du Colombier found:
1589ef1f84bSDavid du Colombier 	unlock(&imagealloc);
1599ef1f84bSDavid du Colombier 
1609ef1f84bSDavid du Colombier 	if(i->s == 0) {
1619ef1f84bSDavid du Colombier 		/* Disaster after commit in exec */
1629ef1f84bSDavid du Colombier 		if(waserror()) {
1639ef1f84bSDavid du Colombier 			unlock(i);
1649ef1f84bSDavid du Colombier 			pexit(Enovmem, 1);
1659ef1f84bSDavid du Colombier 		}
1669ef1f84bSDavid du Colombier 		i->s = newseg(type, base, top);
1679ef1f84bSDavid du Colombier 		i->s->image = i;
168*094d6818SDavid du Colombier 		i->s->color = color;
1699ef1f84bSDavid du Colombier 		i->ref++;
1709ef1f84bSDavid du Colombier 		poperror();
1719ef1f84bSDavid du Colombier 	}
1729ef1f84bSDavid du Colombier 	else
1739ef1f84bSDavid du Colombier 		incref(i->s);
1749ef1f84bSDavid du Colombier 
1759ef1f84bSDavid du Colombier 	return i;
1769ef1f84bSDavid du Colombier }
1779ef1f84bSDavid du Colombier 
1789ef1f84bSDavid du Colombier void
putimage(Image * i)1799ef1f84bSDavid du Colombier putimage(Image *i)
1809ef1f84bSDavid du Colombier {
1819ef1f84bSDavid du Colombier 	Chan *c, **cp;
1829ef1f84bSDavid du Colombier 	Image *f, **l;
1839ef1f84bSDavid du Colombier 
1849ef1f84bSDavid du Colombier 	if(i->notext)
1859ef1f84bSDavid du Colombier 		return;
1869ef1f84bSDavid du Colombier 
1879ef1f84bSDavid du Colombier 	lock(i);
1889ef1f84bSDavid du Colombier 	if(--i->ref == 0) {
1899ef1f84bSDavid du Colombier 		l = &ihash(i->qid.path);
1909ef1f84bSDavid du Colombier 		mkqid(&i->qid, ~0, ~0, QTFILE);
1919ef1f84bSDavid du Colombier 		unlock(i);
1929ef1f84bSDavid du Colombier 		c = i->c;
1939ef1f84bSDavid du Colombier 
1949ef1f84bSDavid du Colombier 		lock(&imagealloc);
1959ef1f84bSDavid du Colombier 		for(f = *l; f; f = f->hash) {
1969ef1f84bSDavid du Colombier 			if(f == i) {
1979ef1f84bSDavid du Colombier 				*l = i->hash;
1989ef1f84bSDavid du Colombier 				break;
1999ef1f84bSDavid du Colombier 			}
2009ef1f84bSDavid du Colombier 			l = &f->hash;
2019ef1f84bSDavid du Colombier 		}
2029ef1f84bSDavid du Colombier 
2039ef1f84bSDavid du Colombier 		i->next = imagealloc.free;
2049ef1f84bSDavid du Colombier 		imagealloc.free = i;
2059ef1f84bSDavid du Colombier 
2069ef1f84bSDavid du Colombier 		/* defer freeing channel till we're out of spin lock's */
2079ef1f84bSDavid du Colombier 		if(imagealloc.nfreechan == imagealloc.szfreechan){
2089ef1f84bSDavid du Colombier 			imagealloc.szfreechan += NFREECHAN;
2099ef1f84bSDavid du Colombier 			cp = malloc(imagealloc.szfreechan*sizeof(Chan*));
2109ef1f84bSDavid du Colombier 			if(cp == nil)
2119ef1f84bSDavid du Colombier 				panic("putimage");
2129ef1f84bSDavid du Colombier 			memmove(cp, imagealloc.freechan, imagealloc.nfreechan*sizeof(Chan*));
2139ef1f84bSDavid du Colombier 			free(imagealloc.freechan);
2149ef1f84bSDavid du Colombier 			imagealloc.freechan = cp;
2159ef1f84bSDavid du Colombier 		}
2169ef1f84bSDavid du Colombier 		imagealloc.freechan[imagealloc.nfreechan++] = c;
2179ef1f84bSDavid du Colombier 		unlock(&imagealloc);
2189ef1f84bSDavid du Colombier 
2199ef1f84bSDavid du Colombier 		return;
2209ef1f84bSDavid du Colombier 	}
2219ef1f84bSDavid du Colombier 	unlock(i);
2229ef1f84bSDavid du Colombier }
223