git: plan9front

Download patch

ref: 312d556a0a9a721c68c9bda4b9b43f9b3fc46ce1
parent: 463db8a57248556543f1483f8394aca183d32120
author: rodri <rgl@antares-labs.eu>
date: Sat Sep 13 08:16:44 EDT 2025

libdraw: no more racey Drawops

In draw(2) calls that take a Drawop as an argument
(namely draw [d], line [L], string [sx], ellipse
[eE] and poly [pP]) a message for setting the op
is sent before the actual drawing message, each
using a separate bufimage(2) call.  This caused
issues with programs that draw concurrently, where
a process or thread using an op other than SoverD
would set it, then be rescheduled to another proc
or thread that draws using another op and
overwrite the former's op, which ends up being
forced to use SoverD.  Another case is when the
second bufimage(2) call (the drawing message)
fails for the first proc, then a second one that
doesn't set an op (uses SoverD) will end up
inheriting the outstanding operator.

This changes the procedure to always allocate the
space necessary to hold both the operator setting
and drawing messages when necessary.

--- a/sys/include/ape/draw.h
+++ b/sys/include/ape/draw.h
@@ -521,7 +521,7 @@
 extern	Image	*screen;
 extern	Screen	*_screen;
 extern	int	_cursorfd;
-extern	void	_setdrawop(Display*, Drawop);
+extern	uchar*	_bufimageop(Display*, int, Drawop);
 
 #define	BGSHORT(p)	((p)[0]|((p)[1]<<8))
 #define	BGLONG(p)	((p)[0]|((p)[1]<<8)|((p)[2]<<16)|((p)[3]<<24))
--- a/sys/include/draw.h
+++ b/sys/include/draw.h
@@ -515,7 +515,7 @@
 extern	Image	*screen;
 extern	Screen	*_screen;
 extern	int	_cursorfd;
-extern	void	_setdrawop(Display*, Drawop);
+extern	uchar*	_bufimageop(Display*, int, Drawop);
 
 #define	BGSHORT(p)	((p)[0]|((p)[1]<<8))
 #define	BGLONG(p)	((p)[0]|((p)[1]<<8)|((p)[2]<<16)|((p)[3]<<24))
--- a/sys/src/libdraw/draw.c
+++ b/sys/src/libdraw/draw.c
@@ -2,33 +2,13 @@
 #include <libc.h>
 #include <draw.h>
 
-void
-_setdrawop(Display *d, Drawop op)
-{
-	uchar *a;
-
-	if(op != SoverD){
-		_lockdisplay(d);
-		a = bufimage(d, 1+1);
-		if(a == nil){
-			_unlockdisplay(d);
-			return;
-		}
-		a[0] = 'O';
-		a[1] = op;
-		_unlockdisplay(d);
-	}
-}
-		
 static void
 draw1(Image *dst, Rectangle *r, Image *src, Point *p0, Image *mask, Point *p1, Drawop op)
 {
 	uchar *a;
 
-	_setdrawop(dst->display, op);
-
 	_lockdisplay(dst->display);
-	a = bufimage(dst->display, 1+4+4+4+4*4+2*4+2*4);
+	a = _bufimageop(dst->display, 1+4+4+4+4*4+2*4+2*4, op);
 	if(a == nil){
 		_unlockdisplay(dst->display);
 		return;
--- a/sys/src/libdraw/ellipse.c
+++ b/sys/src/libdraw/ellipse.c
@@ -8,10 +8,8 @@
 {
 	uchar *a;
 
-	_setdrawop(dst->display, op);
-
 	_lockdisplay(dst->display);
-	a = bufimage(dst->display, 1+4+4+2*4+4+4+4+2*4+2*4);
+	a = _bufimageop(dst->display, 1+4+4+2*4+4+4+4+2*4+2*4, op);
 	if(a == nil){
 		_unlockdisplay(dst->display);
 		fprint(2, "image ellipse: %r\n");
--- a/sys/src/libdraw/init.c
+++ b/sys/src/libdraw/init.c
@@ -473,3 +473,19 @@
 	d->bufp += n;
 	return p;
 }
+
+uchar*
+_bufimageop(Display *d, int n, Drawop op)
+{
+	uchar *a;
+
+	if(op != SoverD){
+		a = bufimage(d, 1+1+n);
+		if(a == nil)
+			return nil;
+		a[0] = 'O';
+		a[1] = op;
+		return a+2;
+	}
+	return bufimage(d, n);
+}
--- a/sys/src/libdraw/line.c
+++ b/sys/src/libdraw/line.c
@@ -13,10 +13,8 @@
 {
 	uchar *a;
 
-	_setdrawop(dst->display, op);
-
 	_lockdisplay(dst->display);
-	a = bufimage(dst->display, 1+4+2*4+2*4+4+4+4+4+2*4);
+	a = _bufimageop(dst->display, 1+4+2*4+2*4+4+4+4+4+2*4, op);
 	if(a == nil){
 		_unlockdisplay(dst->display);
 		fprint(2, "image line: %r\n");
--- a/sys/src/libdraw/poly.c
+++ b/sys/src/libdraw/poly.c
@@ -41,10 +41,8 @@
 		oy = pp[i].y;
 	}
 
-	_setdrawop(dst->display, op);
-
 	_lockdisplay(dst->display);
-	a = bufimage(dst->display, 1+4+2+4+4+4+4+2*4+(u-t));
+	a = _bufimageop(dst->display, 1+4+2+4+4+4+4+2*4+(u-t), op);
 	if(a == nil){
 		_unlockdisplay(dst->display);
 		free(t);
--- a/sys/src/libdraw/string.c
+++ b/sys/src/libdraw/string.c
@@ -106,13 +106,11 @@
 		}
 		try = 0;
 
-		_setdrawop(dst->display, op);
-
 		m = 47+2*n;
 		if(bg)
 			m += 4+2*4;
 		_lockdisplay(dst->display);
-		b = bufimage(dst->display, m);
+		b = _bufimageop(dst->display, m, op);
 		if(b == nil){
 			_unlockdisplay(dst->display);
 			fprint(2, "string: %r\n");
--