shithub: riscv

Download patch

ref: 99216e01291ab687f74a54dd21dc0b8aa27de8d5
parent: 54d2424a7cab7fe1808f7bdb7acade6af0e3428a
author: cinap_lenrek <cinap_lenrek@gmx.de>
date: Mon Oct 22 03:03:47 EDT 2012

rio: fix deadlock

we can't really change the Window *input from
outside the winctl() thread. the problem is
that the window might end up reading the
mouse (scroll, select) which makes the w->cctl
channel block once you try to talk to the
window again (from the mousethread). this also
means we have to coordinate window switchin
from the winctl proc waiting for the current
window to release the input and then take over.
thers a new Winctl message Topped that basically
does that now using Wakeup and a chan to
synchronize.

--- a/sys/src/cmd/rio/dat.h
+++ b/sys/src/cmd/rio/dat.h
@@ -61,6 +61,8 @@
 	Wakeup,
 	Reshaped,
 	Moved,
+	Topped,
+	Repaint,
 	Refresh,
 	Movemouse,
 	Rawon,
@@ -67,7 +69,6 @@
 	Rawoff,
 	Holdon,
 	Holdoff,
-	Repaint,
 	Deleted,
 	Exited,
 };
@@ -76,7 +77,7 @@
 {
 	int		type;
 	Rectangle	r;
-	Image	*image;
+	void		*p;
 };
 
 struct Conswritemesg
@@ -132,7 +133,7 @@
 	Mousectl		mc;
 	Mouseinfo	mouse;
 	Channel		*ck;			/* chan(char*) */
-	Channel		*cctl;		/* chan(Wctlmesg)[20] */
+	Channel		*cctl;		/* chan(Wctlmesg)[4] */
 	Channel		*conswrite;	/* chan(Conswritemesg) */
 	Channel		*consread;	/* chan(Consreadmesg) */
 	Channel		*mouseread;	/* chan(Mousereadmesg) */
@@ -188,8 +189,7 @@
 int		wbswidth(Window*, Rune);
 int		wclickmatch(Window*, int, int, int, uint*);
 int		wclose(Window*);
-int		wctlmesg(Window*, int, Rectangle, Image*);
-int		wctlmesg(Window*, int, Rectangle, Image*);
+int		wctlmesg(Window*, int, Rectangle, void*);
 uint		wbacknl(Window*, uint, uint);
 uint		winsert(Window*, Rune*, int, uint);
 void		waddraw(Window*, Rune*, int);
@@ -213,7 +213,7 @@
 void		wscrdraw(Window*);
 void		wscroll(Window*, int);
 void		wselect(Window*);
-void		wsendctlmesg(Window*, int, Rectangle, Image*);
+void		wsendctlmesg(Window*, int, Rectangle, void*);
 void		wsetcursor(Window*, int);
 void		wsetname(Window*);
 void		wsetorigin(Window*, uint, int);
--- a/sys/src/cmd/rio/rio.c
+++ b/sys/src/cmd/rio/rio.c
@@ -345,7 +345,7 @@
 	while(s = recvp(kbdchan)){
 		if(*s == 'k' || *s == 'K')
 			shiftdown = utfrune(s+1, Kshift) != nil;
-		if(input == nil || input->deleted || sendp(input->ck, s) <= 0)
+		if(input == nil || sendp(input->ck, s) <= 0)
 			free(s);
 	}
 }
@@ -1113,10 +1113,8 @@
 		return;
 	incref(w);
 	i = sweep();
-	if(i){
+	if(i)
 		wsendctlmesg(w, Reshaped, i->r, i);
-		wcurrent(w);
-	}
 	wclose(w);
 }
 
@@ -1132,10 +1130,8 @@
 		return;
 	incref(w);
 	i = drag(w, &r);
-	if(i){
+	if(i)
 		wsendctlmesg(w, Moved, r, i);
-		wcurrent(w);
-	}
 	cornercursor(w, mouse->xy, 1);
 	wclose(w);
 }
@@ -1154,8 +1150,6 @@
 	incref(w);
 	i = allocimage(display, w->screenr, w->i->chan, 0, DNofill);
 	if(i){
-		if(w == input)
-			input = nil;
 		hidden[nhidden++] = w;
 		wsendctlmesg(w, Reshaped, ZR, i);
 	}
@@ -1180,7 +1174,6 @@
 		--nhidden;
 		memmove(hidden+j, hidden+j+1, (nhidden-j)*sizeof(Window*));
 		wsendctlmesg(w, Reshaped, w->i->r, i);
-		wcurrent(w);
 	}
 	wclose(w);
 	return i!=0;
@@ -1257,7 +1250,6 @@
 	threadcreate(winctl, w, 8192);
 	if(!hideit)
 		wcurrent(w);
-	flushimage(display, 1);
 	if(pid == 0){
 		arg = emalloc(5*sizeof(void*));
 		arg[0] = w;
--- a/sys/src/cmd/rio/wctl.c
+++ b/sys/src/cmd/rio/wctl.c
@@ -388,6 +388,7 @@
 		wbottomme(w);
 		return 1;
 	case Current:
+		wtopme(w);
 		wcurrent(w);
 		return 1;
 	case Hide:
--- a/sys/src/cmd/rio/wind.c
+++ b/sys/src/cmd/rio/wind.c
@@ -113,10 +113,7 @@
 		wsetselect(w, w->q0, w->q1);
 		wscrdraw(w);
 	}
-	if(w == input)
-		wborder(w, Selborder);
-	else
-		wborder(w, Unselborder);
+	wborder(w, Selborder);
 	wsetname(w);
 	w->topped = ++topped;
 	w->resized = TRUE;
@@ -312,7 +309,7 @@
 			send(mrm.cm, &m.Mouse);
 			continue;
 		case WCtl:
-			if(wctlmesg(w, wcm.type, wcm.r, wcm.image) == Exited){
+			if(wctlmesg(w, wcm.type, wcm.r, wcm.p) == Exited){
 				for(i=0; i<nelem(kbdq); i++)
 					free(kbdq[i]);
 				chanfree(crm.c1);
@@ -1058,20 +1055,21 @@
 }
 
 void
-wsendctlmesg(Window *w, int type, Rectangle r, Image *image)
+wsendctlmesg(Window *w, int type, Rectangle r, void *p)
 {
 	Wctlmesg wcm;
 
 	wcm.type = type;
 	wcm.r = r;
-	wcm.image = image;
+	wcm.p = p;
 	send(w->cctl, &wcm);
 }
 
 int
-wctlmesg(Window *w, int m, Rectangle r, Image *i)
+wctlmesg(Window *w, int m, Rectangle r, void *p)
 {
 	char buf[64];
+	Image *i = p;
 
 	switch(m){
 	default:
@@ -1078,6 +1076,8 @@
 		error("unknown control message");
 		break;
 	case Wakeup:
+		if(p!=nil)
+			sendp((Channel*)p, w);
 		break;
 	case Moved:
 	case Reshaped:
@@ -1090,6 +1090,55 @@
 		wresize(w, i, m==Moved);
 		proccreate(deletetimeoutproc, estrdup(buf), 4096);
 		flushimage(display, 1);
+		if(Dx(r)<=0){	/* window got hidden, if we had the input, drop it */
+			if(w==input)
+				input = nil;
+			break;
+		}
+		/* fall through to get input if needed */
+	case Topped:
+		if(w->deleted || w==input)
+			break;
+		if(input!=nil){
+			Window *oi;
+			Channel *c;
+	
+			oi = input;
+			incref(oi);
+
+			/*
+			 * have to wait until old input responds before
+			 * changing input to us because the window might
+			 * currently be mouse tracking and it is not
+			 * prepared for getting its input revoked.
+			 */
+			c = chancreate(sizeof(void*), 0);
+			wsendctlmesg(oi, Wakeup, ZR, c);
+			recv(c, nil);
+			chanfree(c);
+
+			/*
+			 * if we are still top window and nobody else has taken
+			 * input from original window, take the input.
+			 */
+			if(!w->deleted && w->topped==topped && oi==input){
+				input = w;
+
+				oi->wctlready = 1;
+				wsendctlmesg(oi, Repaint, ZR, nil);
+			}
+			wclose(oi);
+		} else
+			input = w;
+		w->wctlready = 1;
+		if(m!=Topped && w==input)
+			break;
+		/* fall thrugh for redraw after input change */
+	case Repaint:
+		if(w->deleted || Dx(w->screenr)<=0)
+			break;
+		wrepaint(w);
+		flushimage(display, 1);
 		break;
 	case Refresh:
 		if(w->deleted || Dx(w->screenr)<=0 || !rectclip(&r, w->i->r) || w->mouseopen)
@@ -1114,12 +1163,10 @@
 		break;
 	case Holdon:
 	case Holdoff:
-		if(w == input)
-			wsetcursor(w, 0);
-		/* no break */
-	case Repaint:
 		if(w->deleted)
 			break;
+		if(w==input)
+			wsetcursor(w, 0);
 		wrepaint(w);
 		flushimage(display, 1);
 		break;
@@ -1206,22 +1253,8 @@
 void
 wcurrent(Window *w)
 {
-	Window *oi;
-
-	if(wkeyboard!=nil && w==wkeyboard)
-		return;
-	oi = input;
-	input = w;
-	if(w != oi){
-		if(oi){
-			oi->wctlready = 1;
-			wsendctlmesg(oi, Repaint, ZR, nil);
-		}
-		if(w){
-			w->wctlready = 1;
-			wsendctlmesg(w, Repaint, ZR, nil);
-		}
-	}
+	if(w!=nil && w!=input)
+		wsendctlmesg(w, Topped, ZR, nil);
 }
 
 void
--- a/sys/src/cmd/rio/xfid.c
+++ b/sys/src/cmd/rio/xfid.c
@@ -190,7 +190,6 @@
 				if(pid == 0)
 					pid = -1;	/* make sure we don't pop a shell! - UGH */
 				w = new(i, hideit, scrollit, pid, nil, nil, nil);
-				flushimage(display, 1);
 				newlymade = TRUE;
 			}else
 				err = Ewindow;
@@ -550,7 +549,6 @@
 			filsysrespond(x->fs, x, &fc, buf);
 			return;
 		}
-		flushimage(display, 1);
 		break;
 
 	default:
--