git: 9front

Download patch

ref: 139bfdc4624b731fe14d08d730beee4b3fab98f3
parent: e1d82d684fb64641422bf647be3674556c5e1551
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");
--