ref: 6b250a5ca888f3a3cfcb94cbdb3865ae9bcf26e8
parent: 2e4717b4e21ee49ef77271fed6e4ad6b38f532b1
author: rodri <rgl@antares-labs.eu>
date: Sat Sep 6 21:56:06 EDT 2025
libdraw: locking revamp Guard the display buffer behind an internal QLock and provide an RWLock instead for the user. This makes it possible to draw in parallel. The behavior by default (when doing the display->locking=1 and (un)?lockdisplay dance) is the same, so existing programs won't break. Update the manuals and document the special behavior of menuhit(2) and enter(2) when used in concurrent programs, since they steal the input entirely and the user has no way of letting them know when a resize occurs. Because of this, when using screen or _screen, or a custom Screen based on a volatile image, they may become invisible while kidnapping the input or end up committing a despicable use-after-free.
--- a/sys/include/ape/draw.h
+++ b/sys/include/ape/draw.h
@@ -182,8 +182,9 @@
struct Display
{- QLock qlock;
- int locking; /*program is using lockdisplay */
+ QLock qlock;
+ RWLock usrlock; /* for getwindow(2) and the globals */
+ int locking; /* ignored (kept for backwards compatibility) */
int dirno;
int fd;
int reffd;
@@ -201,13 +202,13 @@
Image *transparent;
Image *image;
uchar *buf;
- int bufsize;
+ int bufsize;
uchar *bufp;
Font *defaultfont;
Subfont *defaultsubfont;
Image *windows;
Image *screenimage;
- int _isnewdisplay;
+ int _isnewdisplay;
};
struct Image
@@ -490,8 +491,16 @@
extern char* subfontname(char*, char*, int);
extern Subfont* _getsubfont(Display*, char*);
extern Subfont* getdefont(Display*);
-extern void lockdisplay(Display*);
+
+/*
+ * Concurrency
+ */
+extern void lockdisplay(Display*);
extern void unlockdisplay(Display*);
+extern void rlockdisplay(Display*);
+extern void runlockdisplay(Display*);
+extern void _lockdisplay(Display*);
+extern void _unlockdisplay(Display*);
/*
* Predefined
--- a/sys/include/ape/qlock.h
+++ b/sys/include/ape/qlock.h
@@ -26,6 +26,16 @@
QLp *tail;
} QLock;
+typedef
+struct RWLock
+{+ Lock lock;
+ int readers; /* number of readers */
+ int writer; /* number of writers */
+ QLp *head; /* list of waiting processes */
+ QLp *tail;
+} RWLock;
+
#ifdef __cplusplus
extern "C" {#endif
@@ -33,6 +43,13 @@
extern void qlock(QLock*);
extern void qunlock(QLock*);
extern int canqlock(QLock*);
+
+extern void rlock(RWLock*);
+extern void runlock(RWLock*);
+extern int canrlock(RWLock*);
+extern void wlock(RWLock*);
+extern void wunlock(RWLock*);
+extern int canwlock(RWLock*);
#ifdef __cplusplus
}
--- a/sys/include/draw.h
+++ b/sys/include/draw.h
@@ -175,7 +175,8 @@
struct Display
{QLock qlock;
- int locking; /*program is using lockdisplay */
+ RWLock usrlock; /* for getwindow(2) and the globals */
+ int locking; /* ignored (kept for backwards compatibility) */
int dirno;
int fd;
int reffd;
@@ -484,8 +485,16 @@
extern char* subfontname(char*, char*, int);
extern Subfont* _getsubfont(Display*, char*);
extern Subfont* getdefont(Display*);
-extern void lockdisplay(Display*);
+
+/*
+ * Concurrency
+ */
+extern void lockdisplay(Display*);
extern void unlockdisplay(Display*);
+extern void rlockdisplay(Display*);
+extern void runlockdisplay(Display*);
+extern void _lockdisplay(Display*);
+extern void _unlockdisplay(Display*);
/*
* Predefined
--- a/sys/man/2/graphics
+++ b/sys/man/2/graphics
@@ -52,6 +52,12 @@
void unlockdisplay(Display *d)
.PP
.B
+void rlockdisplay(Display *d)
+.PP
+.B
+void runlockdisplay(Display *d)
+.PP
+.B
int getwindow(Display *d, int ref)
.PP
.B
@@ -417,18 +423,18 @@
.I initdraw
calls them as needed.
.PP
-The data structures associated with the display must be protected in a multi-process program,
-because they assume only one process will be using them at a time.
-Multi-process programs should set
-.B display->locking
-to
-.BR 1 ,
-to notify the library to use a locking protocol for its own accesses,
-and call
+When drawing concurrently programs must call
.I lockdisplay
and
.I unlockdisplay
-around any calls to the graphics library that will cause messages to be sent to the display device.
+around any calls to
+.I getwindow
+or any other procedures that could change its global variables (read
+below), and
+.I rlockdisplay
+and
+.I runlockdisplay
+around any access to such variables.
.I Initdraw
and
.I geninitdraw
@@ -592,7 +598,7 @@
sysfatal("can't open $wsys: %r");/* mount creates window; see \f2rio\fP(4) */
-if(mount(fd, -1, "/tmp", MREPL, "new -dx 300-dy 200") < 0)
+if(mount(fd, -1, "/tmp", MREPL, "new -dx 300 -dy 200") < 0)
sysfatal("can't mount new window: %r");if(gengetwindow(display, "/tmp/winname",
&screen2, &_screen2, Refnone) < 0)
@@ -636,3 +642,6 @@
.B white
and
.BR black .
+.br
+.B Display->locking
+is now ignored, but is kept for backwards compatibility.
--- a/sys/man/2/mouse
+++ b/sys/man/2/mouse
@@ -263,3 +263,21 @@
.IR event (2),
.IR keyboard (2),
.IR thread (2).
+.SH BUGS
+.I Menuhit
+and
+.I enter
+are not re-entrant and will break when used concurrently with an
+independent window whose
+.B Screen
+changes during their execution (as is the case when receiving a resize
+event while using
+.BR _screen ).
+In such cases they must be recreated after acquiring the new screen.
+When used with a
+.B Screen
+that has an independent backing window (i.e. not
+.BR display->image / screen ),
+this backing window must be drawn periodically to the
+.BR display->image / screen
+to be able to see the changes induced by the input.
--- a/sys/src/ape/lib/ap/plan9/qlock.c
+++ b/sys/src/ape/lib/ap/plan9/qlock.c
@@ -22,6 +22,8 @@
enum
{Queuing,
+ QueuingR,
+ QueuingW,
};
/* find a free shared memory location to queue ourselves in */
@@ -107,4 +109,170 @@
}
unlock(&q->lock);
return 0;
+}
+
+void
+rlock(RWLock *q)
+{+ QLp *p, *mp;
+
+ lock(&q->lock);
+ if(q->writer == 0 && q->head == nil){+ /* no writer, go for it */
+ q->readers++;
+ unlock(&q->lock);
+ return;
+ }
+
+ mp = getqlp();
+ p = q->tail;
+ if(p == nil)
+ q->head = mp;
+ else
+ p->next = mp;
+ q->tail = mp;
+ mp->state = QueuingR;
+ unlock(&q->lock);
+
+ /* wait in kernel */
+ while((*_rendezvousp)(mp, (void*)1) == (void*)~0)
+ ;
+ mp->inuse = 0;
+}
+
+int
+canrlock(RWLock *q)
+{+ lock(&q->lock);
+ if (q->writer == 0 && q->head == nil) {+ /* no writer; go for it */
+ q->readers++;
+ unlock(&q->lock);
+ return 1;
+ }
+ unlock(&q->lock);
+ return 0;
+}
+
+void
+runlock(RWLock *q)
+{+ QLp *p;
+
+ lock(&q->lock);
+ if(q->readers <= 0)
+ abort();
+ p = q->head;
+ if(--(q->readers) > 0 || p == nil){+ unlock(&q->lock);
+ return;
+ }
+
+ /* start waiting writer */
+ if(p->state != QueuingW)
+ abort();
+ q->head = p->next;
+ if(q->head == nil)
+ q->tail = nil;
+ q->writer = 1;
+ unlock(&q->lock);
+
+ /* wakeup waiter */
+ while((*_rendezvousp)(p, 0) == (void*)~0)
+ ;
+}
+
+void
+wlock(RWLock *q)
+{+ QLp *p, *mp;
+
+ lock(&q->lock);
+ if(q->readers == 0 && q->writer == 0){+ /* noone waiting, go for it */
+ q->writer = 1;
+ unlock(&q->lock);
+ return;
+ }
+
+ /* wait */
+ mp = getqlp();
+ p = q->tail;
+ if(p == nil)
+ q->head = mp;
+ else
+ p->next = mp;
+ q->tail = mp;
+ mp->state = QueuingW;
+ unlock(&q->lock);
+
+ /* wait in kernel */
+ while((*_rendezvousp)(mp, (void*)1) == (void*)~0)
+ ;
+ mp->inuse = 0;
+}
+
+int
+canwlock(RWLock *q)
+{+ lock(&q->lock);
+ if (q->readers == 0 && q->writer == 0) {+ /* no one waiting; go for it */
+ q->writer = 1;
+ unlock(&q->lock);
+ return 1;
+ }
+ unlock(&q->lock);
+ return 0;
+}
+
+void
+wunlock(RWLock *q)
+{+ QLp *p, *x;
+
+ lock(&q->lock);
+ if(q->writer == 0)
+ abort();
+ p = q->head;
+ if(p == nil){+ q->writer = 0;
+ unlock(&q->lock);
+ return;
+ }
+ if(p->state == QueuingW){+ /* start waiting writer */
+ q->head = p->next;
+ if(q->head == nil)
+ q->tail = nil;
+ unlock(&q->lock);
+ while((*_rendezvousp)(p, 0) == (void*)~0)
+ ;
+ return;
+ }
+ if(p->state != QueuingR)
+ abort();
+
+ /* collect waiting readers */
+ q->readers = 1;
+ for(x = p->next; x != nil && x->state == QueuingR; x = x->next){+ q->readers++;
+ p = x;
+ }
+ p->next = nil;
+ p = q->head;
+
+ /* queue remaining writers */
+ q->head = x;
+ if(x == nil)
+ q->tail = nil;
+ q->writer = 0;
+ unlock(&q->lock);
+
+ /* wakeup waiting readers */
+ for(; p != nil; p = x){+ x = p->next;
+ while((*_rendezvousp)(p, 0) == (void*)~0)
+ ;
+ }
}
--- a/sys/src/libdraw/alloc.c
+++ b/sys/src/libdraw/alloc.c
@@ -47,9 +47,12 @@
return nil;
}
+ _lockdisplay(d);
a = bufimage(d, 1+4+4+1+4+1+4*4+4*4+4);
- if(a == nil)
+ if(a == nil){+ _unlockdisplay(d);
goto Error;
+ }
d->imageid++;
id = d->imageid;
a[0] = 'b';
@@ -72,6 +75,7 @@
BPLONG(a+39, clipr.max.x);
BPLONG(a+43, clipr.max.y);
BPLONG(a+47, col);
+ _unlockdisplay(d);
if(ai != nil)
i = ai;
@@ -78,12 +82,15 @@
else{i = malloc(sizeof(Image));
if(i == nil){+ _lockdisplay(d);
a = bufimage(d, 1+4);
if(a != nil){a[0] = 'f';
BPLONG(a+1, id);
+ _unlockdisplay(d);
flushimage(d, 0);
- }
+ }else
+ _unlockdisplay(d);
goto Error;
}
}
@@ -124,9 +131,12 @@
}
/* flush pending data so we don't get error allocating the image */
flushimage(d, 0);
+ _lockdisplay(d);
a = bufimage(d, 1+4+1+n);
- if(a == nil)
+ if(a == nil){+ _unlockdisplay(d);
goto Error;
+ }
d->imageid++;
id = d->imageid;
a[0] = 'n';
@@ -133,22 +143,30 @@
BPLONG(a+1, id);
a[5] = n;
memmove(a+6, name, n);
+ _unlockdisplay(d);
if(flushimage(d, 0) < 0)
goto Error;
- if(pread(d->ctlfd, buf, sizeof buf, 0) < 12*12)
+ _lockdisplay(d);
+ if(pread(d->ctlfd, buf, sizeof buf, 0) < 12*12){+ _unlockdisplay(d);
goto Error;
+ }
buf[12*12] = '\0';
+ _unlockdisplay(d);
i = malloc(sizeof(Image));
if(i == nil){Error1:
+ _lockdisplay(d);
a = bufimage(d, 1+4);
if(a != nil){a[0] = 'f';
BPLONG(a+1, id);
+ _unlockdisplay(d);
flushimage(d, 0);
- }
+ }else
+ _unlockdisplay(d);
goto Error;
}
i->display = d;
@@ -180,14 +198,18 @@
int n;
n = strlen(name);
+ _lockdisplay(i->display);
a = bufimage(i->display, 1+4+1+1+n);
- if(a == nil)
+ if(a == nil){+ _unlockdisplay(i->display);
return 0;
+ }
a[0] = 'N';
BPLONG(a+1, i->id);
a[5] = in;
a[6] = n;
memmove(a+7, name, n);
+ _unlockdisplay(i->display);
if(flushimage(i->display, 0) < 0)
return 0;
return 1;
@@ -198,29 +220,31 @@
{uchar *a;
Display *d;
- Image *w;
+ Image **w;
if(i == nil || i->display == nil)
return 0;
d = i->display;
- if(i->screen != nil){- w = d->windows;
- if(w == i)
- d->windows = i->next;
- else
- while(w != nil){- if(w->next == i){- w->next = i->next;
- break;
- }
- w = w->next;
- }
- }
+ _lockdisplay(d);
a = bufimage(d, 1+4);
- if(a == nil)
+ if(a == nil){+ _unlockdisplay(d);
return -1;
+ }
a[0] = 'f';
BPLONG(a+1, i->id);
+
+ if(i->screen != nil){+ w = &d->windows;
+ while(*w != nil){+ if(*w == i){+ *w = i->next;
+ break;
+ }
+ w = &(*w)->next;
+ }
+ }
+ _unlockdisplay(d);
return 0;
}
--- a/sys/src/libdraw/cloadimage.c
+++ b/sys/src/libdraw/cloadimage.c
@@ -30,9 +30,12 @@
werrstr("cloadimage: bad count %d", nb);return -1;
}
+ _lockdisplay(i->display);
a = bufimage(i->display, 21+nb);
- if(a == nil)
+ if(a == nil){+ _unlockdisplay(i->display);
return -1;
+ }
a[0] = 'Y';
BPLONG(a+1, i->id);
BPLONG(a+5, r.min.x);
@@ -40,6 +43,7 @@
BPLONG(a+13, r.max.x);
BPLONG(a+17, maxy);
memmove(a+21, data, nb);
+ _unlockdisplay(i->display);
miny = maxy;
data += nb;
ndata += nb;
--- a/sys/src/libdraw/creadimage.c
+++ b/sys/src/libdraw/creadimage.c
@@ -3,7 +3,7 @@
#include <draw.h>
Image *
-creadimage(Display *d, int fd, int dolock)
+creadimage(Display *d, int fd, int)
{char hdr[5*12+1];
Rectangle r;
@@ -55,11 +55,7 @@
}
if(d != nil){- if(dolock)
- lockdisplay(d);
i = allocimage(d, r, chan, 0, 0);
- if(dolock)
- unlockdisplay(d);
if(i == nil)
return nil;
}else{@@ -76,12 +72,7 @@
while(miny != r.max.y){ if(readn(fd, hdr, 2*12) != 2*12){Errout:
- if(dolock)
- lockdisplay(d);
- Erroutlock:
freeimage(i);
- if(dolock)
- unlockdisplay(d);
free(buf);
return nil;
}
@@ -98,11 +89,12 @@
if(readn(fd, buf, nb)!=nb)
goto Errout;
if(d != nil){- if(dolock)
- lockdisplay(d);
+ _lockdisplay(d);
a = bufimage(i->display, 21+nb);
- if(a == nil)
- goto Erroutlock;
+ if(a == nil){+ _unlockdisplay(d);
+ goto Errout;
+ }
a[0] = 'Y';
BPLONG(a+1, i->id);
BPLONG(a+5, r.min.x);
@@ -112,8 +104,7 @@
if(!new) /* old image: flip the data bits */
_twiddlecompressed(buf, nb);
memmove(a+21, buf, nb);
- if(dolock)
- unlockdisplay(d);
+ _unlockdisplay(d);
}
miny = maxy;
}
--- a/sys/src/libdraw/debug.c
+++ b/sys/src/libdraw/debug.c
@@ -6,11 +6,15 @@
drawsetdebug(int v)
{uchar *a;
+
+ _lockdisplay(display);
a = bufimage(display, 1+1);
if(a == nil){+ _unlockdisplay(display);
fprint(2, "drawsetdebug: %r\n");
return;
}
a[0] = 'D';
a[1] = v;
+ _unlockdisplay(display);
}
--- a/sys/src/libdraw/draw.c
+++ b/sys/src/libdraw/draw.c
@@ -8,11 +8,15 @@
uchar *a;
if(op != SoverD){+ _lockdisplay(d);
a = bufimage(d, 1+1);
- if(a == nil)
+ if(a == nil){+ _unlockdisplay(d);
return;
+ }
a[0] = 'O';
a[1] = op;
+ _unlockdisplay(d);
}
}
@@ -23,9 +27,12 @@
_setdrawop(dst->display, op);
+ _lockdisplay(dst->display);
a = bufimage(dst->display, 1+4+4+4+4*4+2*4+2*4);
- if(a == nil)
+ if(a == nil){+ _unlockdisplay(dst->display);
return;
+ }
if(src == nil)
src = dst->display->black;
if(mask == nil)
@@ -42,6 +49,7 @@
BPLONG(a+33, p0->y);
BPLONG(a+37, p1->x);
BPLONG(a+41, p1->y);
+ _unlockdisplay(dst->display);
}
void
--- a/sys/src/libdraw/ellipse.c
+++ b/sys/src/libdraw/ellipse.c
@@ -10,8 +10,10 @@
_setdrawop(dst->display, op);
+ _lockdisplay(dst->display);
a = bufimage(dst->display, 1+4+4+2*4+4+4+4+2*4+2*4);
if(a == nil){+ _unlockdisplay(dst->display);
fprint(2, "image ellipse: %r\n");
return;
}
@@ -27,6 +29,7 @@
BPLONG(a+33, sp->y);
BPLONG(a+37, alpha);
BPLONG(a+41, phi);
+ _unlockdisplay(dst->display);
}
void
--- a/sys/src/libdraw/emenuhit.c
+++ b/sys/src/libdraw/emenuhit.c
@@ -27,10 +27,11 @@
menucolors(void)
{/* Main tone is greenish, with negative selection */
+ menutxt = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DDarkgreen);
back = allocimagemix(display, DPalegreen, DWhite);
- high = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DDarkgreen); /* dark green */
- bord = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DMedgreen); /* not as dark green */
- if(back==nil || high==nil || bord==nil)
+ high = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DDarkgreen); /* dark green */
+ bord = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DMedgreen); /* not as dark green */
+ if(menutxt==nil || back==nil || high==nil || bord==nil)
goto Error;
text = display->black;
htext = back;
@@ -37,9 +38,11 @@
return;
Error:
+ freeimage(menutxt);
freeimage(back);
freeimage(high);
freeimage(bord);
+ menutxt = display->black;
back = display->white;
high = display->black;
bord = display->black;
@@ -108,10 +111,10 @@
int i;
paintitem(menu, textr, off, lasti, 1, save, nil);
- flushimage(display, 1); /* in case display->locking is set */
+ flushimage(display, 1);
*m = emouse();
while(m->buttons & (1<<(but-1))){- flushimage(display, 1); /* in case display->locking is set */
+ flushimage(display, 1);
*m = emouse();
i = menusel(textr, m->xy);
if(i != -1 && i == lasti)
@@ -148,10 +151,7 @@
if(r.max.y < r.min.y+2)
r.max.y = r.min.y+2;
border(screen, r, 1, bord, ZP);
- if(menutxt == 0)
- menutxt = allocimage(display, Rect(0, 0, 1, 1), CMAP8, 1, DDarkgreen);
- if(menutxt)
- draw(screen, insetrect(r, 1), menutxt, nil, ZP);
+ draw(screen, insetrect(r, 1), menutxt, nil, ZP);
}
int
@@ -252,7 +252,7 @@
menuscrollpaint(scrollr, off, nitem, nitemdrawn);
}
}
- flushimage(display, 1); /* in case display->locking is set */
+ flushimage(display, 1);
*m = emouse();
}
}
--- a/sys/src/libdraw/event.c
+++ b/sys/src/libdraw/event.c
@@ -261,19 +261,8 @@
int i, n;
uchar ebuf[EMAXMSG+1];
- /* avoid generating a message if there's nothing to show. */
- /* this test isn't perfect, though; could do flushimage(display, 0) then call extract */
- /* also: make sure we don't interfere if we're multiprocessing the display */
- if(display->locking){- /* if locking is being done by program, this means it can't depend on automatic flush in emouse() etc. */
- if(canqlock(&display->qlock)){- if(display->bufp > display->buf)
- flushimage(display, 1);
- unlockdisplay(display);
- }
- }else
- if(display->bufp > display->buf)
- flushimage(display, 1);
+ if(display->bufp > display->buf)
+ flushimage(display, 1);
loop:
if((n=read(epipe[0], ebuf, EMAXMSG+1)) < 0
|| ebuf[0] >= MAXSLAVE)
--- a/sys/src/libdraw/font.c
+++ b/sys/src/libdraw/font.c
@@ -284,9 +284,12 @@
c->left = fi->left;
if(f->display == nil)
return 1;
+ _lockdisplay(f->display);
b = bufimage(f->display, 37);
- if(b == nil)
+ if(b == nil){+ _unlockdisplay(f->display);
return 0;
+ }
top = fi->top + (f->ascent-subf->f->ascent);
bottom = fi->bottom + (f->ascent-subf->f->ascent);
b[0] = 'l';
@@ -301,6 +304,7 @@
BPLONG(b+31, fi->top);
b[35] = fi->left;
b[36] = fi->width;
+ _unlockdisplay(f->display);
return 1;
}
@@ -329,8 +333,10 @@
fprint(2, "font cache resize failed: %r\n");
goto Return;
}
+ _lockdisplay(d);
b = bufimage(d, 1+4+4+1);
if(b == nil){+ _unlockdisplay(d);
freeimage(new);
goto Return;
}
@@ -338,6 +344,7 @@
BPLONG(b+1, new->id);
BPLONG(b+5, ncache);
b[9] = f->ascent;
+ _unlockdisplay(d);
freeimage(f->cacheimage);
f->cacheimage = new;
Nodisplay:
--- a/sys/src/libdraw/getsubfont.c
+++ b/sys/src/libdraw/getsubfont.c
@@ -9,32 +9,19 @@
Subfont*
_getsubfont(Display *d, char *name)
{- int dolock, fd;
+ int fd;
Subfont *f;
- /*
- * unlock display so i/o happens with display released, unless
- * user is doing his own locking, in which case this could break things.
- * _getsubfont is called only from string.c and stringwidth.c,
- * which are known to be safe to have this done.
- */
- dolock = d != nil && d->locking == 0;
- if(dolock)
- unlockdisplay(d);
-
fd = open(name, OREAD|OCEXEC);
if(fd < 0) {fprint(2, "getsubfont: can't open %s: %r\n", name);
f = nil;
} else {- f = readsubfont(d, name, fd, dolock);
+ f = readsubfont(d, name, fd, 0);
if(f == nil)
fprint(2, "getsubfont: can't read %s: %r\n", name);
close(fd);
}
-
- if(dolock)
- lockdisplay(d);
return f;
}
--- a/sys/src/libdraw/init.c
+++ b/sys/src/libdraw/init.c
@@ -9,8 +9,6 @@
static char deffontname[] = "*default*";
Screen *_screen;
-int debuglockdisplay = 0;
-
static void _closedisplay(Display*, int);
/* note handler */
@@ -300,7 +298,7 @@
disp->error = error;
disp->windir = t;
disp->devdir = strdup(dev);
- qlock(&disp->qlock);
+ wlock(&disp->usrlock);
disp->white = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DWhite);
disp->black = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DBlack);
if(disp->white == nil || disp->black == nil){@@ -324,7 +322,6 @@
}
/*
- * Call with d unlocked.
* Note that disp->defaultfont and defaultsubfont are not freed here.
*/
void
@@ -369,7 +366,6 @@
close(disp->ctlfd);
/* should cause refresh slave to shut down */
close(disp->reffd);
- qunlock(&disp->qlock);
free(disp);
}
@@ -376,17 +372,36 @@
void
lockdisplay(Display *disp)
{- if(debuglockdisplay){- /* avoid busy looping; it's rare we collide anyway */
- while(!canqlock(&disp->qlock))
- sleep(1000);
- }else
- qlock(&disp->qlock);
+ wlock(&disp->usrlock);
}
void
unlockdisplay(Display *disp)
{+ wunlock(&disp->usrlock);
+}
+
+void
+rlockdisplay(Display *disp)
+{+ rlock(&disp->usrlock);
+}
+
+void
+runlockdisplay(Display *disp)
+{+ runlock(&disp->usrlock);
+}
+
+void
+_lockdisplay(Display *disp)
+{+ qlock(&disp->qlock);
+}
+
+void
+_unlockdisplay(Display *disp)
+{qunlock(&disp->qlock);
}
@@ -425,8 +440,11 @@
int
flushimage(Display *d, int visible)
{+ int rc;
+
if(d == nil)
return 0;
+ _lockdisplay(d);
if(visible){*d->bufp++ = 'v'; /* five bytes always reserved for this */
if(d->_isnewdisplay){@@ -434,7 +452,9 @@
d->bufp += 4;
}
}
- return doflush(d);
+ rc = doflush(d);
+ _unlockdisplay(d);
+ return rc;
}
uchar*
@@ -453,4 +473,3 @@
d->bufp += n;
return p;
}
-
--- a/sys/src/libdraw/line.c
+++ b/sys/src/libdraw/line.c
@@ -15,8 +15,10 @@
_setdrawop(dst->display, op);
+ _lockdisplay(dst->display);
a = bufimage(dst->display, 1+4+2*4+2*4+4+4+4+4+2*4);
if(a == nil){+ _unlockdisplay(dst->display);
fprint(2, "image line: %r\n");
return;
}
@@ -32,4 +34,5 @@
BPLONG(a+33, src->id);
BPLONG(a+37, sp.x);
BPLONG(a+41, sp.y);
+ _unlockdisplay(dst->display);
}
--- a/sys/src/libdraw/loadimage.c
+++ b/sys/src/libdraw/loadimage.c
@@ -36,8 +36,10 @@
return -1;
} else
n = dy*bpl;
+ _lockdisplay(i->display);
a = bufimage(i->display, 21+n);
if(a == nil){+ _unlockdisplay(i->display);
werrstr("loadimage: %r");return -1;
}
@@ -48,6 +50,7 @@
BPLONG(a+13, r.min.x+dx);
BPLONG(a+17, r.min.y+dy);
memmove(a+21, data, n);
+ _unlockdisplay(i->display);
ndata += dy*bpl;
data += dy*bpl;
r.min.y += dy;
--- a/sys/src/libdraw/menuhit.c
+++ b/sys/src/libdraw/menuhit.c
@@ -28,10 +28,11 @@
menucolors(void)
{/* Main tone is greenish, with negative selection */
+ menutxt = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DDarkgreen);
back = allocimagemix(display, DPalegreen, DWhite);
high = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DDarkgreen); /* dark green */
bord = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DMedgreen); /* not as dark green */
- if(back==nil || high==nil || bord==nil)
+ if(menutxt==nil || back==nil || high==nil || bord==nil)
goto Error;
text = display->black;
htext = back;
@@ -38,9 +39,11 @@
return;
Error:
+ freeimage(menutxt);
freeimage(back);
freeimage(high);
freeimage(bord);
+ menutxt = display->black;
back = display->white;
high = display->black;
bord = display->black;
@@ -145,10 +148,7 @@
if(r.max.y < r.min.y+2)
r.max.y = r.min.y+2;
border(m, r, 1, bord, ZP);
- if(menutxt == 0)
- menutxt = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DDarkgreen); /* border color; BUG? */
- if(menutxt)
- draw(m, insetrect(r, 1), menutxt, nil, ZP);
+ draw(m, insetrect(r, 1), menutxt, nil, ZP);
}
int
--- a/sys/src/libdraw/poly.c
+++ b/sys/src/libdraw/poly.c
@@ -43,8 +43,10 @@
_setdrawop(dst->display, op);
+ _lockdisplay(dst->display);
a = bufimage(dst->display, 1+4+2+4+4+4+4+2*4+(u-t));
if(a == nil){+ _unlockdisplay(dst->display);
free(t);
fprint(2, "image poly: %r\n");
return;
@@ -59,6 +61,7 @@
BPLONG(a+23, sp->x);
BPLONG(a+27, sp->y);
memmove(a+31, t, u-t);
+ _unlockdisplay(dst->display);
free(t);
}
--- a/sys/src/libdraw/readimage.c
+++ b/sys/src/libdraw/readimage.c
@@ -3,7 +3,7 @@
#include <draw.h>
Image*
-readimage(Display *d, int fd, int dolock)
+readimage(Display *d, int fd, int)
{char hdr[5*12+1];
int dy;
@@ -20,7 +20,7 @@
if(readn(fd, hdr, 11) != 11)
return nil;
if(memcmp(hdr, "compressed\n", 11) == 0){- if(i = creadimage(d, fd, dolock))
+ if(i = creadimage(d, fd, 0))
goto Done;
return nil;
}
@@ -82,11 +82,7 @@
if(l > chunk)
chunk = l;
if(d != nil){- if(dolock)
- lockdisplay(d);
i = allocimage(d, r, chan, 0, -1);
- if(dolock)
- unlockdisplay(d);
if(i == nil)
return nil;
}else{@@ -106,12 +102,7 @@
if(m != n){ werrstr("readimage: read count %d not %d: %r", m, n);Err:
- if(dolock)
- lockdisplay(d);
- Err1:
freeimage(i);
- if(dolock)
- unlockdisplay(d);
free(tmp);
return nil;
}
@@ -120,12 +111,8 @@
tmp[j] ^= 0xFF;
if(d != nil){- if(dolock)
- lockdisplay(d);
if(loadimage(i, Rect(r.min.x, miny, r.max.x, miny+dy), tmp, chunk) <= 0)
- goto Err1;
- if(dolock)
- unlockdisplay(d);
+ goto Err;
}
miny += dy;
}
--- a/sys/src/libdraw/readsubfont.c
+++ b/sys/src/libdraw/readsubfont.c
@@ -3,7 +3,7 @@
#include <draw.h>
Subfont*
-readsubfonti(Display*d, char *name, int fd, Image *ai, int dolock)
+readsubfonti(Display*d, char *name, int fd, Image *ai, int)
{char hdr[3*12+4+1];
int n;
@@ -14,7 +14,7 @@
i = ai;
if(i == nil){- i = readimage(d, fd, dolock);
+ i = readimage(d, fd, 0);
if(i == nil)
return nil;
}
@@ -39,11 +39,7 @@
if(fc == nil)
goto Err;
_unpackinfo(fc, p, n);
- if(dolock)
- lockdisplay(d);
f = allocsubfont(name, n, atoi(hdr+12), atoi(hdr+24), fc, i);
- if(dolock)
- unlockdisplay(d);
if(f == nil){free(fc);
goto Err;
@@ -58,7 +54,7 @@
}
Subfont*
-readsubfont(Display *d, char *name, int fd, int dolock)
+readsubfont(Display *d, char *name, int fd, int)
{- return readsubfonti(d, name, fd, nil, dolock);
+ return readsubfonti(d, name, fd, nil, 0);
}
--- a/sys/src/libdraw/replclipr.c
+++ b/sys/src/libdraw/replclipr.c
@@ -7,8 +7,10 @@
{uchar *b;
+ _lockdisplay(i->display);
b = bufimage(i->display, 22);
if(b == nil){+ _unlockdisplay(i->display);
fprint(2, "replclipr: %r\n");
return;
}
@@ -20,6 +22,7 @@
BPLONG(b+10, clipr.min.y);
BPLONG(b+14, clipr.max.x);
BPLONG(b+18, clipr.max.y);
+ _unlockdisplay(i->display);
i->repl = repl;
i->clipr = clipr;
}
--- a/sys/src/libdraw/string.c
+++ b/sys/src/libdraw/string.c
@@ -111,8 +111,10 @@
m = 47+2*n;
if(bg)
m += 4+2*4;
+ _lockdisplay(dst->display);
b = bufimage(dst->display, m);
if(b == nil){+ _unlockdisplay(dst->display);
fprint(2, "string: %r\n");
break;
}
@@ -142,6 +144,7 @@
ec = &cbuf[n];
for(c=cbuf; c<ec; c++, b+=2)
BPSHORT(b, *c);
+ _unlockdisplay(dst->display);
pt.x += wid;
bgp.x += wid;
agefont(f);
--- a/sys/src/libdraw/unloadimage.c
+++ b/sys/src/libdraw/unloadimage.c
@@ -36,8 +36,10 @@
dy = Dy(r);
n = bpl*dy;
}
+ _lockdisplay(d);
a = bufimage(d, 1+4+4*4);
if(a == nil){+ _unlockdisplay(d);
werrstr("unloadimage: %r");return -1;
}
@@ -47,10 +49,15 @@
BPLONG(a+9, r.min.y);
BPLONG(a+13, r.min.x+dx);
BPLONG(a+17, r.min.y+dy);
+ _unlockdisplay(d);
if(flushimage(d, 0) < 0)
return -1;
- if(read(d->fd, data, n) < 0)
+ _lockdisplay(d);
+ if(read(d->fd, data, n) < 0){+ _unlockdisplay(d);
return -1;
+ }
+ _unlockdisplay(d);
data += bpl*dy;
r.min.y += dy;
}
--- a/sys/src/libdraw/window.c
+++ b/sys/src/libdraw/window.c
@@ -2,8 +2,6 @@
#include <libc.h>
#include <draw.h>
-typedef struct Memimage Memimage;
-
static int screenid;
Screen*
@@ -22,13 +20,18 @@
s = malloc(sizeof(Screen));
if(s == nil)
return nil;
+ _lockdisplay(d);
if(!screenid)
screenid = getpid();
+ _unlockdisplay(d);
for(try=0; try<25; try++){- /* loop until find a free id */
+ /* loop until we find a free id */
+ _lockdisplay(d);
a = bufimage(d, 1+4+4+4+1);
- if(a == nil)
+ if(a == nil){+ _unlockdisplay(d);
break;
+ }
id = ++screenid & 0xffff; /* old devdraw bug */
a[0] = 'A';
BPLONG(a+1, id);
@@ -35,6 +38,7 @@
BPLONG(a+5, image->id);
BPLONG(a+9, fill->id);
a[13] = public;
+ _unlockdisplay(d);
if(flushimage(d, 0) != -1)
goto Found;
}
@@ -60,8 +64,10 @@
s = malloc(sizeof(Screen));
if(s == nil)
return nil;
+ _lockdisplay(d);
a = bufimage(d, 1+4+4);
if(a == nil){+ _unlockdisplay(d);
Error:
free(s);
return nil;
@@ -69,6 +75,7 @@
a[0] = 'S';
BPLONG(a+1, id);
BPLONG(a+5, chan);
+ _unlockdisplay(d);
if(flushimage(d, 0) < 0)
goto Error;
@@ -88,13 +95,16 @@
if(s == nil)
return 0;
d = s->display;
+ _lockdisplay(d);
a = bufimage(d, 1+4);
if(a == nil){+ _unlockdisplay(d);
free(s);
return -1;
}
a[0] = 'F';
BPLONG(a+1, s->id);
+ _unlockdisplay(d);
free(s);
return 1;
}
@@ -115,8 +125,10 @@
if(i == nil)
return nil;
i->screen = s;
- i->next = s->display->windows;
- s->display->windows = i;
+ _lockdisplay(d);
+ i->next = d->windows;
+ d->windows = i;
+ _unlockdisplay(d);
return i;
}
@@ -152,14 +164,18 @@
if(n==0)
return;
+ _lockdisplay(d);
b = bufimage(d, 1+1+2+4*n);
- if(b == nil)
+ if(b == nil){+ _unlockdisplay(d);
return;
+ }
b[0] = 't';
b[1] = top;
BPSHORT(b+2, n);
for(i=0; i<n; i++)
BPLONG(b+4+4*i, w[i]->id);
+ _unlockdisplay(d);
}
void
@@ -194,9 +210,12 @@
uchar *b;
Point delta;
+ _lockdisplay(w->display);
b = bufimage(w->display, 1+4+2*4+2*4);
- if(b == nil)
+ if(b == nil){+ _unlockdisplay(w->display);
return 0;
+ }
b[0] = 'o';
BPLONG(b+1, w->id);
BPLONG(b+5, log.x);
@@ -203,6 +222,7 @@
BPLONG(b+9, log.y);
BPLONG(b+13, scr.x);
BPLONG(b+17, scr.y);
+ _unlockdisplay(w->display);
delta = subpt(log, w->r.min);
w->r = rectaddpt(w->r, delta);
w->clipr = rectaddpt(w->clipr, delta);
--- a/sys/src/libdraw/writeimage.c
+++ b/sys/src/libdraw/writeimage.c
@@ -13,7 +13,7 @@
};
int
-writeimage(int fd, Image *i, int dolock)
+writeimage(int fd, Image *i, int)
{uchar *outbuf, *outp, *eout; /* encoded data, pointer, end */
uchar *loutp; /* start of encoded line */
@@ -47,11 +47,7 @@
return -1;
data = malloc(bpl);
for(miny = r.min.y; miny != r.max.y; miny++){- if(dolock)
- lockdisplay(i->display);
nb = unloadimage(i, Rect(r.min.x, miny, r.max.x, miny+1), data, bpl);
- if(dolock)
- unlockdisplay(i->display);
if(nb != bpl)
goto ErrOut0;
if(write(fd, data, nb) != nb)
@@ -74,12 +70,8 @@
dy = chunk/bpl;
if(dy <= 0)
dy = 1;
- if(dolock)
- lockdisplay(i->display);
nb = unloadimage(i, Rect(r.min.x, miny, r.max.x, miny+dy),
data+(miny-r.min.y)*bpl, dy*bpl);
- if(dolock)
- unlockdisplay(i->display);
if(nb != dy*bpl)
goto ErrOut0;
}
--
⑨