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");
--
⑨