From dean-debian@arctic.org Tue Dec 10 22:56:20 2002
Date: Tue, 10 Dec 2002 22:55:50 -0800 (PST)
From: dean gaudet <dean-debian@arctic.org>
To: submit@bugs.debian.org
Subject: various problems with "nonblock" option
X-comment: visit http://arctic.org/~dean/legal for information regarding
    copyright and disclaimer.

Package: screen
Version: 3.9.13-2

the "nonblock" option sounds wonderful for dealing with sessions which are
stuck on network problems and so forth... except that it doesn't appear to
work at all.

- the "nonblock" command uses an uninitialized variable `i' to set
  D_nonblock... sometimes it works, sometimes it doesn't.  the fix
  for this is a tiny portion of the patch below.

- there is a routine muchpending() which appears to completely ignore the
  nonblock setting and decides to stop output to all displays when one
  display on a window is frozen.

  here is how you can reproduce this problem:

  - get yourself two ssh sessions on the host you'd like to test on

  - start a screen in one, and screen -x to it in the second

  - now you need to manually enable nonblock in both displays --
    but because of the first bug mentioned above you'll have to try a
    few times to get it to work.  when you try "C-a :nonblock on"
    you should completely ignore the message screen responds with,
    and instead issue "C-a :displays" and look for two small letters
    "nb" beside your display to ensure that non-blocking is on.

  - now that you've got nonblock on in both displays, use "pstree -p"
    to find the pids of the sshd parents of one of your screen sessions.
    i.e. you'll find one line such as:

	|-sshd(29182)---sshd(29219)---tcsh(29221)---screen(29265)

  - issue "kill -STOP 29182 29219" using the pids you found in the
    previous step.  this will suspend all i/o for one of your
    displays... which is a fine way to simulate network stoppage.

  - in the working display, issue "cat /usr/share/dict/words".
    you should see a few pages of output then it should hang.

  - that's the bug in action.

  - issue kill -CONT to unstick your sshds.

  the patch below fixes these muchpending() bugs.

- the final problem with nonblock is that there is no way to specify it
  in your .screenrc -- it needs a "defnonblock" version similar to all
  the other "deffoo" commands.  the patch below adds defnonblock.

as mentioned, this patch fixes all three problems above... and i've
given it some light testing so far.

-dean

diff -ru screen-3.9.13/comm.c screen-3.9.13.dg1/comm.c
--- screen-3.9.13/comm.c	Mon Aug 12 06:30:21 2002
+++ screen-3.9.13.dg1/comm.c	Tue Dec 10 22:25:14 2002
@@ -147,6 +147,9 @@
 #endif
   { "defmode",		ARGS_1 },
   { "defmonitor",	ARGS_1 },
+#ifdef MULTI
+  { "defnonblock",	ARGS_1 },
+#endif
   { "defobuflimit",	ARGS_1 },
 #ifdef COPY_PASTE
   { "defscrollback",	ARGS_1 },
diff -ru screen-3.9.13/debian/changelog screen-3.9.13.dg1/debian/changelog
--- screen-3.9.13/debian/changelog	Tue Dec 10 22:32:38 2002
+++ screen-3.9.13.dg1/debian/changelog	Tue Dec 10 22:35:50 2002
@@ -1,3 +1,14 @@
+screen (3.9.13-2.dg1) unstable; urgency=low
+
+  * the muchpending() routine halted display output regardless
+    of the D_nonblock setting.
+  * the nonblock command used an unitialized variable i for setting
+    D_nonblock.
+  * there was no way to set nonblock in .screenrc so i added a
+    "defnonblock" command similar to other default commands.
+
+ -- dean gaudet <dean@arctic.org>  Tue, 10 Dec 2002 22:34:09 -0800
+
 screen (3.9.13-2) unstable; urgency=medium

   * avoid pkg installing docs resulting in /usr/share/info/dir.gz files in
diff -ru screen-3.9.13/display.c screen-3.9.13.dg1/display.c
--- screen-3.9.13/display.c	Tue Dec 10 22:32:38 2002
+++ screen-3.9.13.dg1/display.c	Tue Dec 10 22:22:23 2002
@@ -95,6 +95,7 @@
  *  The default values
  */
 int defobuflimit = OBUF_MAX;
+int defnonblock = 0;
 #ifdef AUTO_NUKE
 int defautonuke = 0;
 #endif
@@ -215,7 +216,7 @@
   display->d_next = displays;
   displays = display;
   D_flow = 1;
-  D_nonblock = 0;
+  D_nonblock = defnonblock;
   D_userfd = fd;
   D_readev.fd = D_writeev.fd = fd;
   D_readev.type  = EV_READ;
diff -ru screen-3.9.13/doc/screen.1 screen-3.9.13.dg1/doc/screen.1
--- screen-3.9.13/doc/screen.1	Tue Dec 10 22:32:38 2002
+++ screen-3.9.13.dg1/doc/screen.1	Tue Dec 10 22:31:43 2002
@@ -1483,6 +1483,12 @@
 windows is changed. Initial setting is `off'.
 .sp
 .ne 3
+.BR "defnonblock on" | off
+.PP
+Same as the \fBnonblock\fP command except that the default setting for new
+windows is changed. Initial setting is `off'.
+.sp
+.ne 3
 .BI "defobuflimit " limit
 .PP
 Same as the \fBobuflimit\fP command except that the default setting for new displays is changed. Initial setting is 256 bytes.
diff -ru screen-3.9.13/process.c screen-3.9.13.dg1/process.c
--- screen-3.9.13/process.c	Tue Dec 10 22:32:38 2002
+++ screen-3.9.13.dg1/process.c	Tue Dec 10 22:29:42 2002
@@ -71,6 +71,7 @@
 extern char *printcmd;
 extern int default_startup;
 extern int defobuflimit;
+extern int defnonblock;
 extern int ZombieKey_destroy;
 extern int ZombieKey_resurrect;
 #ifdef AUTO_NUKE
@@ -3158,9 +3159,16 @@
       break;
 #endif
 #ifdef MULTI
+    case RC_DEFNONBLOCK:
+      if (ParseOnOff(act, &defnonblock) == 0 && msgok)
+	Msg(0, "default nonblock set to %sblocking mode.", defnonblock ? "non" : "");
+      if (display && *rc_name)
+	D_nonblock = defnonblock;
+      break;
     case RC_NONBLOCK:
+      i = (D_nonblock != 0);
       if (!ParseSwitch(act, &i) && msgok)
-        Msg(0, "display set to %sblocking mode.", D_nonblock ? "non" : "");
+        Msg(0, "display set to %sblocking mode.", i ? "non" : "");
       D_nonblock = i;
       break;
 #endif
diff -ru screen-3.9.13/window.c screen-3.9.13.dg1/window.c
--- screen-3.9.13/window.c	Mon Aug 12 06:37:07 2002
+++ screen-3.9.13.dg1/window.c	Tue Dec 10 21:40:58 2002
@@ -1688,7 +1688,7 @@
   for (cv = p->w_layer.l_cvlist; cv; cv = cv->c_lnext)
     {
       display = cv->c_display;
-      if (D_status == STATUS_ON_WIN && !D_status_bell)
+      if (D_nonblock == 0 && D_status == STATUS_ON_WIN && !D_status_bell)
 	{
 	  /* wait 'til status is gone */
 	  debug("BLOCKING because of status\n");
@@ -1696,7 +1696,7 @@
 	  ev->condneg = &D_status;
 	  return 1;
 	}
-      if (D_obufp - D_obuf > D_obufmax)
+      if (D_nonblock == 0 && D_obufp - D_obuf > D_obufmax)
 	{
 	  debug("BLOCKING because of full obuf\n");
 	  ev->condpos = &D_obuffree;
