Browse Source

Plan 9 from Bell Labs 2007-09-19

David du Colombier 16 years ago
parent
commit
ecffa84bf1

+ 10 - 9
dist/replica/_plan9.db

@@ -582,7 +582,7 @@
 386/lib/libstdio.a - 664 sys sys 1176432133 126062
 386/lib/libsunrpc.a - 664 sys sys 1187061209 353148
 386/lib/libthread.a - 664 sys sys 1184731247 71918
-386/lib/libventi.a - 664 sys sys 1189048123 189448
+386/lib/libventi.a - 664 sys sys 1190141465 190048
 386/mbr - 775 sys sys 1131317338 407
 386/mkfile - 664 sys sys 948141303 46
 386/pbs - 775 sys sys 1143465402 495
@@ -7337,7 +7337,7 @@ sys/man - 20000000775 sys sys 1041446473 0
 sys/man/1 - 20000000775 sys sys 1158800370 0
 sys/man/1/0intro - 664 sys sys 1188516607 9586
 sys/man/1/2a - 664 sys sys 1158281866 1196
-sys/man/1/2c - 664 sys sys 1186687706 9488
+sys/man/1/2c - 664 sys sys 1190150125 9524
 sys/man/1/2l - 664 sys sys 1158281887 4376
 sys/man/1/INDEX - 664 sys sys 1183260468 3139
 sys/man/1/INDEX.html - 664 sys sys 1183240466 16845
@@ -12818,19 +12818,20 @@ sys/src/cmd/oventi/venti.conf - 664 sys sys 1019867537 397
 sys/src/cmd/oventi/wrtape - 775 sys sys 1019678881 555
 sys/src/cmd/p.c - 664 sys sys 1121977162 1504
 sys/src/cmd/page - 20000000775 sys sys 1045606937 0
+sys/src/cmd/page/cache.c - 664 sys sys 1190093304 3114
 sys/src/cmd/page/filter.c - 664 sys sys 1069793856 2166
 sys/src/cmd/page/gfx.c - 664 sys sys 1084470500 6894
 sys/src/cmd/page/gs.c - 664 sys sys 1137459165 6553
-sys/src/cmd/page/mkfile - 664 sys sys 1035998247 411
+sys/src/cmd/page/mkfile - 664 sys sys 1190093307 422
 sys/src/cmd/page/nrotate.c - 664 sys sys 944961365 5806
-sys/src/cmd/page/page.c - 664 sys sys 1143759342 4420
-sys/src/cmd/page/page.h - 664 sys sys 1137459166 2159
+sys/src/cmd/page/page.c - 664 sys sys 1190093304 4444
+sys/src/cmd/page/page.h - 664 sys sys 1190093304 2222
 sys/src/cmd/page/pdf.c - 664 sys sys 1137459165 2942
 sys/src/cmd/page/pdfprolog.ps - 664 sys sys 1137459166 519
-sys/src/cmd/page/ps.c - 664 sys sys 1137459165 9187
+sys/src/cmd/page/ps.c - 664 sys sys 1190093304 9191
 sys/src/cmd/page/rotate.c - 664 sys sys 1136377361 10435
 sys/src/cmd/page/util.c - 664 sys sys 944961364 2090
-sys/src/cmd/page/view.c - 664 sys sys 1136377361 22893
+sys/src/cmd/page/view.c - 664 sys sys 1190093303 22159
 sys/src/cmd/paqfs - 20000000775 sys sys 1039727564 0
 sys/src/cmd/paqfs/mkfile - 664 sys sys 1032060366 228
 sys/src/cmd/paqfs/mkpaqfs.c - 664 sys sys 1072729575 8836
@@ -14324,7 +14325,7 @@ sys/src/cmd/venti/srv/conf.rc - 775 sys sys 1189304120 1416
 sys/src/cmd/venti/srv/config.c - 664 sys sys 1178160303 5566
 sys/src/cmd/venti/srv/conv.c - 664 sys sys 1178160303 14052
 sys/src/cmd/venti/srv/dat.h - 664 sys sys 1178160303 19018
-sys/src/cmd/venti/srv/dcache.c - 664 sys sys 1189738448 18608
+sys/src/cmd/venti/srv/dcache.c - 664 sys sys 1190092637 18695
 sys/src/cmd/venti/srv/disksched.c - 664 sys sys 1142736352 2125
 sys/src/cmd/venti/srv/dump.c - 664 sys sys 1142736352 1642
 sys/src/cmd/venti/srv/findscore.c - 664 sys sys 1179863768 2195
@@ -15701,7 +15702,7 @@ sys/src/libventi/fcall.c - 664 sys sys 1177189441 3765
 sys/src/libventi/fcallfmt.c - 664 sys sys 1177189441 1912
 sys/src/libventi/file.c - 664 sys sys 1177189441 23509
 sys/src/libventi/hangup.c - 664 sys sys 1177189441 547
-sys/src/libventi/log.c - 664 sys sys 1179957535 3742
+sys/src/libventi/log.c - 664 sys sys 1190092827 3936
 sys/src/libventi/mem.c - 664 sys sys 1177189441 1184
 sys/src/libventi/mkfile - 664 sys sys 1188621815 512
 sys/src/libventi/packet.acid - 664 sys sys 1143389340 21446

+ 10 - 9
dist/replica/plan9.db

@@ -582,7 +582,7 @@
 386/lib/libstdio.a - 664 sys sys 1176432133 126062
 386/lib/libsunrpc.a - 664 sys sys 1187061209 353148
 386/lib/libthread.a - 664 sys sys 1184731247 71918
-386/lib/libventi.a - 664 sys sys 1189048123 189448
+386/lib/libventi.a - 664 sys sys 1190141465 190048
 386/mbr - 775 sys sys 1131317338 407
 386/mkfile - 664 sys sys 948141303 46
 386/pbs - 775 sys sys 1143465402 495
@@ -7337,7 +7337,7 @@ sys/man - 20000000775 sys sys 1041446473 0
 sys/man/1 - 20000000775 sys sys 1158800370 0
 sys/man/1/0intro - 664 sys sys 1188516607 9586
 sys/man/1/2a - 664 sys sys 1158281866 1196
-sys/man/1/2c - 664 sys sys 1186687706 9488
+sys/man/1/2c - 664 sys sys 1190150125 9524
 sys/man/1/2l - 664 sys sys 1158281887 4376
 sys/man/1/INDEX - 664 sys sys 1183260468 3139
 sys/man/1/INDEX.html - 664 sys sys 1183240466 16845
@@ -12818,19 +12818,20 @@ sys/src/cmd/oventi/venti.conf - 664 sys sys 1019867537 397
 sys/src/cmd/oventi/wrtape - 775 sys sys 1019678881 555
 sys/src/cmd/p.c - 664 sys sys 1121977162 1504
 sys/src/cmd/page - 20000000775 sys sys 1045606937 0
+sys/src/cmd/page/cache.c - 664 sys sys 1190093304 3114
 sys/src/cmd/page/filter.c - 664 sys sys 1069793856 2166
 sys/src/cmd/page/gfx.c - 664 sys sys 1084470500 6894
 sys/src/cmd/page/gs.c - 664 sys sys 1137459165 6553
-sys/src/cmd/page/mkfile - 664 sys sys 1035998247 411
+sys/src/cmd/page/mkfile - 664 sys sys 1190093307 422
 sys/src/cmd/page/nrotate.c - 664 sys sys 944961365 5806
-sys/src/cmd/page/page.c - 664 sys sys 1143759342 4420
-sys/src/cmd/page/page.h - 664 sys sys 1137459166 2159
+sys/src/cmd/page/page.c - 664 sys sys 1190093304 4444
+sys/src/cmd/page/page.h - 664 sys sys 1190093304 2222
 sys/src/cmd/page/pdf.c - 664 sys sys 1137459165 2942
 sys/src/cmd/page/pdfprolog.ps - 664 sys sys 1137459166 519
-sys/src/cmd/page/ps.c - 664 sys sys 1137459165 9187
+sys/src/cmd/page/ps.c - 664 sys sys 1190093304 9191
 sys/src/cmd/page/rotate.c - 664 sys sys 1136377361 10435
 sys/src/cmd/page/util.c - 664 sys sys 944961364 2090
-sys/src/cmd/page/view.c - 664 sys sys 1136377361 22893
+sys/src/cmd/page/view.c - 664 sys sys 1190093303 22159
 sys/src/cmd/paqfs - 20000000775 sys sys 1039727564 0
 sys/src/cmd/paqfs/mkfile - 664 sys sys 1032060366 228
 sys/src/cmd/paqfs/mkpaqfs.c - 664 sys sys 1072729575 8836
@@ -14324,7 +14325,7 @@ sys/src/cmd/venti/srv/conf.rc - 775 sys sys 1189304120 1416
 sys/src/cmd/venti/srv/config.c - 664 sys sys 1178160303 5566
 sys/src/cmd/venti/srv/conv.c - 664 sys sys 1178160303 14052
 sys/src/cmd/venti/srv/dat.h - 664 sys sys 1178160303 19018
-sys/src/cmd/venti/srv/dcache.c - 664 sys sys 1189738448 18608
+sys/src/cmd/venti/srv/dcache.c - 664 sys sys 1190092637 18695
 sys/src/cmd/venti/srv/disksched.c - 664 sys sys 1142736352 2125
 sys/src/cmd/venti/srv/dump.c - 664 sys sys 1142736352 1642
 sys/src/cmd/venti/srv/findscore.c - 664 sys sys 1179863768 2195
@@ -15701,7 +15702,7 @@ sys/src/libventi/fcall.c - 664 sys sys 1177189441 3765
 sys/src/libventi/fcallfmt.c - 664 sys sys 1177189441 1912
 sys/src/libventi/file.c - 664 sys sys 1177189441 23509
 sys/src/libventi/hangup.c - 664 sys sys 1177189441 547
-sys/src/libventi/log.c - 664 sys sys 1179957535 3742
+sys/src/libventi/log.c - 664 sys sys 1190092827 3936
 sys/src/libventi/mem.c - 664 sys sys 1177189441 1184
 sys/src/libventi/mkfile - 664 sys sys 1188621815 512
 sys/src/libventi/packet.acid - 664 sys sys 1143389340 21446

+ 10 - 0
dist/replica/plan9.log

@@ -52783,3 +52783,13 @@
 1190077204 2 c sys/man/1/leak - 664 sys sys 1190076657 4373
 1190077204 3 c sys/src/cmd/venti/srv/fixarenas.c - 664 sys sys 1190076775 40524
 1190077204 4 c sys/src/cmd/venti/srv/icachewrite.c - 664 sys sys 1190076776 7787
+1190093403 0 c sys/src/cmd/venti/srv/dcache.c - 664 sys sys 1190092637 18695
+1190093403 1 a sys/src/cmd/page/cache.c - 664 sys sys 1190093304 3114
+1190093403 2 c sys/src/cmd/page/mkfile - 664 sys sys 1190093307 422
+1190093403 3 c sys/src/cmd/page/page.c - 664 sys sys 1190093304 4444
+1190093403 4 c sys/src/cmd/page/page.h - 664 sys sys 1190093304 2222
+1190093403 5 c sys/src/cmd/page/ps.c - 664 sys sys 1190093304 9191
+1190093403 6 c sys/src/cmd/page/view.c - 664 sys sys 1190093303 22159
+1190093403 7 c sys/src/libventi/log.c - 664 sys sys 1190092827 3936
+1190142004 0 c 386/lib/libventi.a - 664 sys sys 1190141465 190048
+1190151004 0 c sys/man/1/2c - 664 sys sys 1190150125 9524

+ 14 - 8
sys/man/1/2c

@@ -1,4 +1,4 @@
-.TH 2C 1 
+.TH 2C 1
 .SH NAME
 0c, 1c, 2c, 5c, 6c, 7c, 8c, kc, qc, vc \- C compilers
 .SH SYNOPSIS
@@ -23,7 +23,9 @@ compilations running concurrently.
 Associated with each compiler is a string
 .IR objtype ,
 for example
-.TP 1.5i
+.TF "6c amd64 "
+.PD
+.TP
 .B "0c spim
 little-endian MIPS 3000 family
 .TP
@@ -99,7 +101,9 @@ for preconditioning
 .IR mk (1).
 .PP
 The compiler options are:
-.TP 1i
+.TF Dname
+.PD
+.TP
 .BI -o " obj"
 Place output in file
 .I obj
@@ -142,11 +146,11 @@ of extensions, below.
 .BI -I \*Sdir
 An
 .L #include
-file whose name does not begin with 
+file whose name does not begin with
 slash
 or is enclosed in double quotes
 is always
-sought first in the directory 
+sought first in the directory
 of the
 .I file
 argument.  If this fails,
@@ -155,7 +159,7 @@ the
 flag is given or the name is enclosed in
 .BR <> ,
 it is then sought
-in directories named in 
+in directories named in
 .B -I
 options,
 then in
@@ -215,6 +219,8 @@ for input
 and not on standard output.
 .PP
 The compilers support several extensions to ANSI C:
+.TF \|
+.PD
 .TP
 \-
 A structure or union may contain unnamed substructures and subunions.
@@ -226,7 +232,7 @@ that is only legal for the unnamed substructure, the compiler promotes
 the type and adjusts the pointer value to point at the substructure.
 If the unnamed structure or union is of a type with a tag name specified by a
 .B typedef
-statement, 
+statement,
 the unnamed structure or union can be explicitly referenced
 by <struct variable>.<tagname>.
 .TP
@@ -476,7 +482,7 @@ Some features of C99, the 1999 ANSI C standard,
 are implemented.
 .PP
 .B switch
-expressions may not be either flavor of
+expressions may not be either signedness of
 .B vlong
 on 32-bit architectures
 .RI ( 8c

+ 184 - 0
sys/src/cmd/page/cache.c

@@ -0,0 +1,184 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <cursor.h>
+#include <event.h>
+#include <bio.h>
+#include <plumb.h>
+#include <ctype.h>
+#include <keyboard.h>
+#include "page.h"
+
+typedef struct Cached Cached;
+struct Cached
+{
+	Document *doc;
+	int page;
+	int angle;
+	Image *im;
+};
+
+static Cached cache[5];
+
+static Image*
+questionmark(void)
+{
+	static Image *im;
+
+	if(im)
+		return im;	
+	im = xallocimage(display, Rect(0,0,50,50), GREY1, 1, DBlack);
+	if(im == nil)
+		return nil;
+	string(im, ZP, display->white, ZP, display->defaultfont, "?");
+	return im;
+}
+
+void
+cacheflush(void)
+{
+	int i;
+	Cached *c;
+
+	for(i=0; i<nelem(cache); i++){
+		c = &cache[i];
+		if(c->im)
+			freeimage(c->im);
+		c->im = nil;
+		c->doc = nil;
+	}
+}
+
+static Image*
+_cachedpage(Document *doc, int angle, int page, char *ra)
+{
+	int i;
+	Cached *c, old;
+	Image *im, *tmp;
+	static int lastpage = -1;
+
+	if((page < 0 || page >= doc->npage) && !doc->fwdonly)
+		return nil;
+
+Again:
+	for(i=0; i<nelem(cache); i++){
+		c = &cache[i];
+		if(c->doc == doc && c->angle == angle && c->page == page){
+			if(chatty) fprint(2, "cache%s hit %d\n", ra, page);
+			goto Found;
+		}
+		if(c->doc == nil)
+			break;
+	}
+
+	if(i >= nelem(cache))
+		i = nelem(cache)-1;
+	c = &cache[i];
+	if(c->im)
+		freeimage(c->im);
+	c->im = nil;
+	c->doc = nil;
+	c->page = -1;
+
+	if(chatty) fprint(2, "cache%s load %d\n", ra, page);
+	im = doc->drawpage(doc, page);
+	if(im == nil){
+		if(doc->fwdonly)	/* end of file */
+			wexits(0);
+		im = questionmark();
+		if(im == nil){
+		Flush:
+			if(i > 0){
+				cacheflush();
+				goto Again;
+			}
+			fprint(2, "out of memory: %r\n");
+			wexits("memory");
+		}
+		return im;
+	}
+
+	if(im->r.min.x != 0 || im->r.min.y != 0){
+		/* translate to 0,0 */
+		tmp = xallocimage(display, Rect(0, 0, Dx(im->r), Dy(im->r)), im->chan, 0, DNofill);
+		if(tmp == nil){
+			freeimage(im);
+			goto Flush;
+		}
+		drawop(tmp, tmp->r, im, nil, im->r.min, S);
+		freeimage(im);
+		im = tmp;
+	}
+
+	switch(angle){
+	case 90:
+		im = rot90(im);
+		break;
+	case 180:
+		rot180(im);
+		break;
+	case 270:
+		im = rot270(im);
+		break;
+	}
+	if(im == nil)
+		goto Flush;
+
+	c->doc = doc;
+	c->page = page;
+	c->angle = angle;
+	c->im = im;
+
+Found:
+	if(chatty) fprint(2, "cache%s mtf %d @%d:", ra, c->page, i);
+	old = *c;
+	memmove(cache+1, cache, (c-cache)*sizeof cache[0]);
+	cache[0] = old;
+	if(chatty){
+		for(i=0; i<nelem(cache); i++)
+			fprint(2, " %d", cache[i].page);
+		fprint(2, "\n");
+	}
+	if(chatty) fprint(2, "cache%s return %d %p\n", ra, old.page, old.im);
+	return old.im;
+}
+
+Image*
+cachedpage(Document *doc, int angle, int page)
+{
+	static int lastpage = -1;
+	static int rabusy;
+	Image *im;
+	int ra;
+	
+	im = _cachedpage(doc, angle, page, "");
+	if(im == nil)
+		return nil;
+
+	/* readahead */
+	ra = -1;
+	if(!rabusy){
+		if(page == lastpage+1)
+			ra = page+1;
+		else if(page == lastpage-1)
+			ra = page-1;
+	}
+	lastpage = page;
+	if(ra >= 0){
+		rabusy = 1;
+		switch(rfork(RFPROC|RFMEM|RFNOWAIT)){
+		case -1:
+			rabusy = 0;
+			break;
+		case 0:
+			lockdisplay(display);
+			_cachedpage(doc, angle, ra, "-ra");
+			rabusy = 0;
+			unlockdisplay(display);
+			_exits(nil);
+		default:
+			break;
+		}
+	}
+	return im;
+}

+ 1 - 0
sys/src/cmd/page/mkfile

@@ -4,6 +4,7 @@ TARG=page
 
 HFILES=page.h
 OFILES=\
+	cache.$O\
 	filter.$O\
 	gfx.$O\
 	gs.$O\

+ 2 - 0
sys/src/cmd/page/page.c

@@ -221,6 +221,8 @@ main(int argc, char **argv)
 		fprint(2, "page: initdraw failed: %r\n");
 		wexits("initdraw");
 	}
+	display->locking = 1;
+
 	truecolor = screen->depth > 8;
 	viewer(doc);
 	wexits(0);

+ 2 - 0
sys/src/cmd/page/page.h

@@ -70,6 +70,8 @@ void	wexits(char*);
 Image*	xallocimage(Display*, Rectangle, ulong, int, ulong);
 int	bell(void*, char*);
 int	opentemp(char *template);
+Image*	cachedpage(Document*, int, int);
+void	cacheflush(void);
 
 extern int stdinfd;
 extern int truecolor;

+ 1 - 1
sys/src/cmd/page/ps.c

@@ -198,7 +198,7 @@ initps(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf)
 Keepreading:
 	while(p = Brdline(b, eol)) {
 		if(p[0] == '%')
-			if(chatty) fprint(2, "ps %.*s\n", utfnlen(p, Blinelen(b)-1), p);
+			if(chatty > 1) fprint(2, "ps %.*s\n", utfnlen(p, Blinelen(b)-1), p);
 		if(npage == mpage) {
 			mpage *= 2;
 			page = erealloc(page, mpage*sizeof(*page));

+ 31 - 62
sys/src/cmd/page/view.c

@@ -15,6 +15,7 @@
 
 Document *doc;
 Image *im;
+Image *tofree;
 int page;
 int angle = 0;
 int showbottom = 0;		/* on the next showpage, move the image so the bottom is visible. */
@@ -58,6 +59,16 @@ enum {
 	RMenu = 3,
 };
 
+static void
+delayfreeimage(Image *m)
+{
+	if(m == tofree)
+		return;
+	if(tofree)
+		freeimage(tofree);
+	tofree = m;
+}
+
 void
 unhide(void)
 {
@@ -118,55 +129,18 @@ menugen(int n)
 void
 showpage(int page, Menu *m)
 {
-	Image *tmp;
-
 	if(doc->fwdonly)
 		m->lasthit = 0;	/* this page */
 	else
 		m->lasthit = reverse ? doc->npage-1-page : page;
 	
 	esetcursor(&reading);
-	freeimage(im);
-	if((page < 0 || page >= doc->npage) && !doc->fwdonly){
-		im = nil;
-		return;
-	}
-	im = doc->drawpage(doc, page);
-	if(im == nil) {
-		if(doc->fwdonly)	/* this is how we know we're out of pages */
-			wexits(0);
-
-		im = xallocimage(display, Rect(0,0,50,50), GREY1, 1, DBlack);
-		if(im == nil) {
-			fprint(2, "out of memory: %r\n");
-			wexits("memory");
-		}
-		string(im, ZP, display->white, ZP, display->defaultfont, "?");
-	}else if(resizing){
+	delayfreeimage(nil);
+	im = cachedpage(doc, angle, page);
+	if(im == nil)
+		wexits(0);
+	if(resizing)
 		resize(Dx(im->r), Dy(im->r));
-	}
-	if(im->r.min.x > 0 || im->r.min.y > 0) {
-		tmp = xallocimage(display, Rect(0, 0, Dx(im->r), Dy(im->r)), im->chan, 0, DNofill);
-		if(tmp == nil) {
-			fprint(2, "out of memory during showpage: %r\n");
-			wexits("memory");
-		}
-		drawop(tmp, tmp->r, im, nil, im->r.min, S);
-		freeimage(im);
-		im = tmp;
-	}
-
-	switch(angle){
-	case 90:
-		im = rot90(im);
-		break;
-	case 180:
-		rot180(im);
-		break;
-	case 270:
-		im = rot270(im);
-		break;
-	}
 
 	esetcursor(nil);
 	if(showbottom){
@@ -344,7 +318,10 @@ viewer(Document *dd)
 		 * a fair amount.  we don't care about doc->npage anymore, and
 		 * all that can be done is select the next page.
 		 */
-		switch(eread(Emouse|Ekeyboard|Eplumb, &e)){
+		unlockdisplay(display);
+		i = eread(Emouse|Ekeyboard|Eplumb, &e);
+		lockdisplay(display);
+		switch(i){
 		case Ekeyboard:
 			if(e.kbdc <= 0xFF && isdigit(e.kbdc)) {
 				nxt = nxt*10+e.kbdc-'0';
@@ -396,12 +373,8 @@ viewer(Document *dd)
 			case 'u':
 				if(im==nil)
 					break;
-				esetcursor(&reading);
-				rot180(im);
-				esetcursor(nil);
 				angle = (angle+180) % 360;
-				redraw(screen);
-				flushimage(display, 1);
+				showpage(page, &menu);
 				break;
 			case '-':
 			case '\b':
@@ -486,7 +459,9 @@ viewer(Document *dd)
 					dxy = subpt(m.xy, oxy);
 					oxy = m.xy;	
 					translate(dxy);
+					unlockdisplay(display);
 					m = emouse();
+					lockdisplay(display);
 				} while(m.buttons == Left);
 				if(m.buttons) {
 					dxy = subpt(xy0, oxy);
@@ -498,7 +473,9 @@ viewer(Document *dd)
 				if(doc->npage == 0)
 					break;
 
+				unlockdisplay(display);
 				n = emenuhit(Middle, &m, &midmenu);
+				lockdisplay(display);
 				if(n == -1)
 					break;
 				switch(n){
@@ -561,8 +538,8 @@ viewer(Document *dd)
 							wexits("memory");
 						}
 						resample(im, tmp);
-						freeimage(im);
 						im = tmp;
+						delayfreeimage(tmp);
 						esetcursor(nil);
 						ul = screen->r.min;
 						redraw(screen);
@@ -586,8 +563,8 @@ viewer(Document *dd)
 							wexits("memory");
 						}
 						resample(im, tmp);
-						freeimage(im);
 						im = tmp;
+						delayfreeimage(tmp);
 						esetcursor(nil);
 						ul = screen->r.min;
 						redraw(screen);
@@ -595,22 +572,12 @@ viewer(Document *dd)
 						break;
 					}
 				case Rot:	/* rotate 90 */
-					esetcursor(&reading);
-					im = rot90(im);
-					esetcursor(nil);
 					angle = (angle+90) % 360;
-					redraw(screen);
-					flushimage(display, 1);
+					showpage(page, &menu);
 					break;
 				case Upside: 	/* upside-down */
-					if(im==nil)
-						break;
-					esetcursor(&reading);
-					rot180(im);
-					esetcursor(nil);
 					angle = (angle+180) % 360;
-					redraw(screen);
-					flushimage(display, 1);
+					showpage(page, &menu);
 					break;
 				case Restore:	/* restore */
 					showpage(page, &menu);
@@ -662,7 +629,9 @@ viewer(Document *dd)
 					break;
 
 				oldpage = page;
+				unlockdisplay(display);
 				n = emenuhit(RMenu, &m, &menu);
+				lockdisplay(display);
 				if(n == -1)
 					break;
 	

+ 16 - 19
sys/src/cmd/venti/srv/dcache.c

@@ -377,6 +377,11 @@ found:
 	if(b->heap != TWID32)
 		fixheap(b->heap, b);
 
+	if((mode == ORDWR || mode == OWRITE) && part->writechan == nil){
+		trace(TraceBlock, "getdblock allocwriteproc %s", part->name);
+		part->writechan = chancreate(sizeof(DBlock*), dcache.nblocks);
+		vtproc(writeproc, part);
+	}
 	qunlock(&dcache.lock);
 
 	trace(TraceBlock, "getdblock lock");
@@ -450,8 +455,6 @@ void
 dirtydblock(DBlock *b, int dirty)
 {
 	int odirty;
-	Part *p;
-	static int bitched;
 
 	trace(TraceBlock, "dirtydblock enter %s 0x%llux %d from 0x%lux",
 		b->part->name, b->addr, dirty, getcallerpc(&b));
@@ -464,16 +467,6 @@ dirtydblock(DBlock *b, int dirty)
 	else
 		b->dirty = dirty;
 
-	p = b->part;
-	if(p->writechan == nil){
-		trace(TraceBlock, "dirtydblock allocwriteproc %s", p->name);
-		/* XXX hope this doesn't fail! */
-		p->writechan = chancreate(sizeof(DBlock*), dcache.nblocks);
-		if (p->writechan == nil && bitched++ == 0)
-			fprint(2, "%s: dirtydblock: couldn't create writechan\n",
-				argv0);
-		vtproc(writeproc, p);
-	}
 	qlock(&dcache.lock);
 	if(!odirty){
 		dcache.ndirty++;
@@ -783,13 +776,13 @@ flushproc(void *v)
 		waitforkick(&dcache.round);
 
 		trace(TraceWork, "start");
+		t0 = nsec()/1000;
+		trace(TraceProc, "build t=%lud", (ulong)(nsec()/1000)-t0);
+
 		qlock(&dcache.lock);
 		as = dcache.state;
 		qunlock(&dcache.lock);
 
-		t0 = nsec()/1000;
-
-		trace(TraceProc, "build t=%lud", (ulong)(nsec()/1000)-t0);
 		write = dcache.write;
 		n = 0;
 		for(i=0; i<dcache.nblocks; i++){
@@ -816,10 +809,14 @@ flushproc(void *v)
 			abort();
 		}
 
-/*
- * XXX the locking here is suspect.  what if a block is redirtied
- * after the write happens?  we'll still decrement dcache.ndirty here.
- */
+		/*
+		 * b->dirty is protected by b->lock while ndirty is protected
+		 * by dcache.lock, so the --ndirty below is the delayed one
+		 * from clearing b->dirty in the write proc.  It may happen
+		 * that some other proc has come along and redirtied b since
+		 * the write.  That's okay, it just means that ndirty may be
+		 * one too high until we catch up and do the decrement.
+		 */
 		trace(TraceProc, "undirty.%d t=%lud", j, (ulong)(nsec()/1000)-t0);
 		qlock(&dcache.lock);
 		dcache.diskstate = as;

+ 11 - 4
sys/src/libventi/log.c

@@ -169,11 +169,18 @@ timefmt(Fmt *fmt)
 {
 	static uvlong t0;
 	uvlong t;
+	Tm tm;
 
-	if(t0 == 0)
-		t0 = nsec();
-	t = nsec()-t0;
-	return fmtprint(fmt, "T+%d.%04d", (uint)(t/1000000000), (uint)(t%1000000000)/100000);
+	if(fmt->flags&FmtSharp){
+		if(t0 == 0)
+			t0 = nsec();
+		t = nsec()-t0;
+		return fmtprint(fmt, "T+%d.%04d", (uint)(t/1000000000), (uint)(t%1000000000)/100000);
+	}else{
+		tm = *localtime(time(0));
+		return fmtprint(fmt, "%04d/%02d%02d %02d:%02d:%02d",
+			1900+tm.year, tm.mon+1, tm.mday, tm.hour, tm.min, tm.sec);
+	}
 }
 
 void