bug-cvs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: lossage due to non-blocking stderr


From: Mark D. Baushke
Subject: Re: lossage due to non-blocking stderr
Date: Tue, 17 Aug 2004 01:24:52 -0700

Hi Frank,

Many thanks for your description of the steps to reproduce the problem
in addition to your patch to client.c to help resolve it.

I have devised a test script that lets me reproduce the problem and I
converted it into a santiy.sh test.

I am planning to commit this patch to the cvs1-11-x-branch and then
merge it into the feature branch.

The test script reproduced the problem for cvs 1.11.x on these three
hosts:

   Redhat 7.3 GNU/Linux
   Gentoo 1.4.16 GNU/Linux
   Solaris 9

I also checked using Redhat 7.3 GNU/Linux and the same script shows a
problem with cvs 1.12.9.1, so I will also be merging the change forward
into the feature branch as well.

(Note: The problem does not seem to arise on FreeBSD 4.x systems.)

Does anyone see any problems with this patch?

        Thanks,   
        -- Mark

Index: src/ChangeLog
===================================================================
RCS file: /cvs/ccvs/src/ChangeLog,v
retrieving revision 1.2336.2.289
diff -u -p -r1.2336.2.289 ChangeLog
--- src/ChangeLog       23 Jun 2004 01:52:25 -0000      1.2336.2.289
+++ src/ChangeLog       17 Aug 2004 08:23:00 -0000
@@ -1,3 +1,14 @@
+2004-08-17  Mark D. Baushke  <mdb@cvshome.org>
+
+       * client.c (handle_m): Workaround to deal with stdio getting put
+       into non-blocking via redirection of stderr and interaction with
+       ssh on some platforms. On those boxes, stdio can put stdout
+       unexpectedly into non-blocking mode which may lead to fwrite() or
+       fflush() failing with EAGAIN, but cvs not checking for the error.
+       (Patch suggested by Frank Hemer <frank@hemer.org>.)
+
+       * sanity.sh (sshstdio): New test for non-blocking stdio via ssh.
+       
 2004-06-22  Derek Price  <derek@ximbiot.com>
 
        * wrapper.c: Add explicit "void" return type to "wrap_clean_fmt_str"
Index: src/client.c
===================================================================
RCS file: /cvs/ccvs/src/client.c,v
retrieving revision 1.318.4.20
diff -u -p -r1.318.4.20 client.c
--- src/client.c        26 Apr 2004 15:52:05 -0000      1.318.4.20
+++ src/client.c        17 Aug 2004 08:23:00 -0000
@@ -3068,6 +3068,9 @@ handle_m (args, len)
     char *args;
     int len;
 {
+    fd_set wfds;
+    int s;
+
     /* In the case where stdout and stderr point to the same place,
        fflushing stderr will make output happen in the correct order.
        Often stderr will be line-buffered and this won't be needed,
@@ -3075,6 +3078,11 @@ handle_m (args, len)
        based on being confused between default buffering between
        stdout and stderr.  But I'm not sure).  */
     fflush (stderr);
+    FD_ZERO (&wfds);
+    FD_SET (STDOUT_FILENO, &wfds);
+    s = select (STDOUT_FILENO+1, NULL, &wfds, NULL, NULL);
+    if (s < 1)
+        perror ("cannot write to stdout");
     fwrite (args, len, sizeof (*args), stdout);
     putc ('\n', stdout);
 }
Index: src/sanity.sh
===================================================================
RCS file: /cvs/ccvs/src/sanity.sh,v
retrieving revision 1.752.2.124
diff -u -p -r1.752.2.124 sanity.sh
--- src/sanity.sh       9 Jun 2004 13:17:46 -0000       1.752.2.124
+++ src/sanity.sh       17 Aug 2004 08:23:01 -0000
@@ -805,6 +805,7 @@ if test x"$*" = x; then
        # Repository Storage (RCS file format, CVS lock files, creating
        # a repository without "cvs init", &c).
        tests="${tests} crerepos rcs rcs2 rcs3 lockfiles backuprecover"
+       tests="${tests} sshstdio"
        # More history browsing, &c.
        tests="${tests} history"
        tests="${tests} big modes modes2 modes3 stamps"
@@ -19892,6 +19893,100 @@ done"
          rm -rf ${CVSROOT_DIRNAME}/first-dir
          ;;
 
+        sshstdio)
+          # CVS_RSH=ssh can have a problem with a non-blocking stdio
+          # in some cases. So, this test is all about testing :ext:
+          # with CVS_RSH=ssh
+
+          if $remote; then
+            CVS_RSH_save=$CVS_RSH
+            CVS_RSH=ssh; export CVS_RSH
+            # Work around X11Forarding by ssh
+            if [ -n "$DISPLAY" ]; then
+                DISPLAY_save=$DISPLAY
+                unset DISPLAY
+            fi
+  
+            if test -n "$remotehost"; then
+                  SSHSTDIO_ROOT=:ext:$remotehost${CVSROOT_DIRNAME}
+            else
+                  SSHSTDIO_ROOT=:ext:`hostname`:${CVSROOT_DIRNAME}
+            fi
+  
+            # If we're going to do remote testing, make sure 'ssh' works first.
+            host="`hostname`"
+            if test "x`${CVS_RSH} $host -n 'echo hi'`" != "xhi"; then
+              echo "ERROR: cannot test remote CVS, because \`${CVS_RSH} $host' 
fails." >&2
+              exit 1
+            fi
+  
+            mkdir sshstdio; cd sshstdio
+            dotest sshstdio-1 "${testcvs} -d ${SSHSTDIO_ROOT} -q co -l ." ''
+            mkdir first-dir
+            dotest sshstdio-2 "${testcvs} add first-dir" \
+  "Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
+            cd first-dir
+            
a='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
+            
c='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
+            # Generate 1024 lines of $a
+            cnt=0
+            echo $a > aaa
+            while [ $cnt -lt 5 ] ; do
+                cnt=`expr $cnt + 1` ;
+                mv aaa aaa.old
+                cat aaa.old aaa.old aaa.old aaa.old > aaa
+            done
+            dotest sshstdio-3 "${testcvs} -q add aaa" \
+"${PROG} add: use .${PROG} commit. to add this file permanently"
+          dotest sshstdio-4 "${testcvs} -q ci -mcreate aaa" \
+"RCS file: $CVSROOT_DIRNAME/first-dir/aaa,v
+done
+Checking in aaa;
+$CVSROOT_DIRNAME/first-dir/aaa,v  <--  aaa
+initial revision: 1\.1
+done"
+            # replace lines 1, 512, 513, 1024 with $c
+            sed 510q < aaa > aaa.old
+            (echo $c; cat aaa.old; echo $c; \
+             echo $c; cat aaa.old; echo $c) > aaa
+            dotest sshstdio-5 "${testcvs} -q ci -mmodify-it aaa" \
+"Checking in aaa;
+${CVSROOT_DIRNAME}/first-dir/aaa,v  <--  aaa
+new revision: 1\.2; previous revision: 1\.1
+done"
+            cat > wrapper.sh <<EOF
+#!${TESTSHELL}
+exec "\$@" 2>&1 < /dev/null | cat
+EOF
+            chmod +x wrapper.sh
+            ./wrapper.sh \
+             ${testcvs} -z5 -Q diff --side-by-side -W 500 -r 1.1 -r 1.2 \
+               aaa >wrapper.dif
+  
+            ${testcvs} -z5 -Q diff --side-by-side -W 500 -r 1.1 -r 1.2 \
+               aaa >good.dif
+  
+            dotest sshstdio-6 "cmp wrapper.dif good.dif" ""
+  
+            CVS_RSH=$CVS_RSH_save; export CVS_RSH
+            if [ -n "$DISPLAY" ]; then
+                DISPLAY=$DISPLAY_save; export DISPLAY
+            fi
+
+            if $keep; then
+                echo Keeping ${TESTDIR} and exiting due to --keep
+                exit 0
+            fi
+  
+            cd ../..
+            rm -r sshstdio
+            rm -rf ${CVSROOT_DIRNAME}/first-dir
+          else
+            :  # nothing to do unless $remote
+          fi
+          ;;
+
+
        history)
          # CVSROOT/history tests:
          # history: various "cvs history" invocations




reply via email to

[Prev in Thread] Current Thread [Next in Thread]