public inbox for cygwin@cygwin.com
 help / color / mirror / Atom feed
From: Takashi Yano <takashi.yano@nifty.ne.jp>
To: cygwin@cygwin.com
Subject: Re: TIOCPKT mode of PTY is broken if ONLCR bit is cleared.
Date: Mon, 02 Mar 2015 12:05:00 -0000	[thread overview]
Message-ID: <20150302210508.1be5c1ed4753508431842913@nifty.ne.jp> (raw)
In-Reply-To: <20150228135947.GZ11124@calimero.vinschen.de>

[-- Attachment #1: Type: text/plain, Size: 645 bytes --]

On Sat, 28 Feb 2015 14:59:47 +0100
Corinna Vinschen <corinna-cygwin@cygwin.com> wrote:

> As soon as we have your CA, we can discuss this patch further.

Can I send CA form by e-mail? Or should I send it as a postal mail?

> For the time being, your patch is lacking a ChangeLog entry.  I scanned
> your patch a bit, and it looks pretty good, but I'll need some more
> explanations and the patch should definitely be made against current
> CVS (soon to be git), not the latest release version.

Thank you for advice. I have revised the patch to follow your direction.
Please find new patch attached.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

[-- Attachment #2: cygwin.patch.20150302 --]
[-- Type: application/octet-stream, Size: 12750 bytes --]

Index: src/winsup/cygwin/ChangeLog
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/ChangeLog,v
retrieving revision 1.6666
diff -u -p -r1.6666 ChangeLog
--- src/winsup/cygwin/ChangeLog	2 Mar 2015 10:52:07 -0000	1.6666
+++ src/winsup/cygwin/ChangeLog	2 Mar 2015 10:59:22 -0000
@@ -1,3 +1,31 @@
+2015-03-02  Takashi Yano <takashi.yano@nifty.ne.jp>
+
+	* tty.h (class tty_min): Add variable "column" for handling ONOCR.
+	Remove variable "write_error" to which any errors are not currently
+	set at anywhere.
+	* tty.cc (tty::init): Add initialization code for variable "column".
+	* fhandler.h (class fhandler_pty_master): Remove variable "need_nl"
+	which is not necessary any more. "need_nl" was needed by OPOST process
+	in fhandler_pty_master::process_slave_output().
+	(class fhandler_pty_common): Add function process_opost_output() for
+	handling post processing for OPOST in write process.
+	* fhandler_tty.cc (fhandler_pty_master::process_slave_output): Count
+	TIOCPKT control byte into length to be read in TIOCPKT mode. Move
+	post processing for OPOST to write process. Remove code related to
+	variable "write_error". Return with EIO error if slave is already
+	closed.
+	(fhandler_pty_master::fhandler_pty_master): Remove initialization
+	code for variable "need_nl".
+	(fhandler_pty_common::process_opost_output): Add this function for
+	handling of OPOST in write process. Add code to avoid blocking in
+	non-blocking mode when output is suspended by ^S.
+	(fhandler_pty_slave::write): Call fhandler_pty_common::
+	process_opost_output() instead of WriteFile(). Remove code related to
+	variable "write_error". 
+	(fhandler_pty_master::doecho): Call fhandler_pty_common::
+	 process_opost_output() instead of WriteFile().
+	* select.cc (peek_pipe): Remove code related to variable "need_nl".
+
 2015-03-02  Corinna Vinschen  <corinna@vinschen.de>
 
 	* security.cc (get_attribute_from_acl): Don't spill Everyone permissions
Index: src/winsup/cygwin/fhandler.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/fhandler.h,v
retrieving revision 1.513
diff -u -p -r1.513 fhandler.h
--- src/winsup/cygwin/fhandler.h	24 Feb 2015 11:05:02 -0000	1.513
+++ src/winsup/cygwin/fhandler.h	2 Mar 2015 10:59:23 -0000
@@ -1507,6 +1507,9 @@ class fhandler_pty_common: public fhandl
     copyto (fh);
     return fh;
   }
+
+ protected:
+  BOOL process_opost_output (HANDLE h, const void *ptr, ssize_t& len, bool is_echo);
 };
 
 class fhandler_pty_slave: public fhandler_pty_common
@@ -1572,8 +1575,6 @@ class fhandler_pty_master: public fhandl
   DWORD dwProcessId;		// Owner of master handles
 
 public:
-  int need_nl;			// Next read should start with \n
-
   /* Constructor */
   fhandler_pty_master (int);
 
Index: src/winsup/cygwin/fhandler_tty.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/fhandler_tty.cc,v
retrieving revision 1.290
diff -u -p -r1.290 fhandler_tty.cc
--- src/winsup/cygwin/fhandler_tty.cc	25 Feb 2015 16:46:57 -0000	1.290
+++ src/winsup/cygwin/fhandler_tty.cc	2 Mar 2015 10:59:23 -0000
@@ -145,10 +145,9 @@ fhandler_pty_common::__release_output_mu
 void
 fhandler_pty_master::doecho (const void *str, DWORD len)
 {
-  acquire_output_mutex (INFINITE);
-  if (!WriteFile (to_master, str, len, &len, NULL))
+  ssize_t towrite = len;
+  if (!process_opost_output (to_master, str, towrite, true))
     termios_printf ("Write to %p failed, %E", to_master);
-  release_output_mutex ();
 }
 
 int
@@ -219,9 +218,8 @@ int
 fhandler_pty_master::process_slave_output (char *buf, size_t len, int pktmode_on)
 {
   size_t rlen;
-  char outbuf[OUT_BUFFER_SIZE + 1];
+  char outbuf[OUT_BUFFER_SIZE];
   DWORD n;
-  int column = 0;
   int rc = 0;
 
   flush_to_slave ();
@@ -229,34 +227,8 @@ fhandler_pty_master::process_slave_outpu
   if (len == 0)
     goto out;
 
-  if (need_nl)
-    {
-      /* We need to return a left over \n character, resulting from
-	 \r\n conversion.  Note that we already checked for FLUSHO and
-	 output_stopped at the time that we read the character, so we
-	 don't check again here.  */
-      if (buf)
-	buf[0] = '\n';
-      need_nl = 0;
-      rc = 1;
-      goto out;
-    }
-
   for (;;)
     {
-      /* Set RLEN to the number of bytes to read from the pipe.  */
-      rlen = len;
-      if (get_ttyp ()->ti.c_oflag & OPOST && get_ttyp ()->ti.c_oflag & ONLCR)
-	{
-	  /* We are going to expand \n to \r\n, so don't read more than
-	     half of the number of bytes requested.  */
-	  rlen /= 2;
-	  if (rlen == 0)
-	    rlen = 1;
-	}
-      if (rlen > sizeof outbuf)
-	rlen = sizeof outbuf;
-
       n = 0;
       for (;;)
 	{
@@ -265,7 +237,11 @@ fhandler_pty_master::process_slave_outpu
 	  if (n)
 	    break;
 	  if (hit_eof ())
-	    goto out;
+	    {
+	      set_errno (EIO);
+	      rc = -1;
+	      goto out;
+	    }
 	  /* DISCARD (FLUSHO) and tcflush can finish here. */
 	  if ((get_ttyp ()->ti.c_lflag & FLUSHO || !buf))
 	    goto out;
@@ -287,6 +263,26 @@ fhandler_pty_master::process_slave_outpu
 	  flush_to_slave ();
 	}
 
+      /* Set RLEN to the number of bytes to read from the pipe.  */
+      rlen = len;
+
+      char *optr;
+      optr = buf;
+      if (pktmode_on && buf)
+	{
+	  *optr++ = TIOCPKT_DATA;
+	  rlen -= 1;
+	}
+
+      if (rlen == 0)
+	{
+	  rc = optr - buf;
+	  goto out;
+	}
+
+      if (rlen > sizeof outbuf)
+	rlen = sizeof outbuf;
+
       if (!ReadFile (get_handle (), outbuf, rlen, &n, NULL))
 	{
 	  termios_printf ("ReadFile failed, %E");
@@ -294,68 +290,12 @@ fhandler_pty_master::process_slave_outpu
 	}
 
       termios_printf ("bytes read %u", n);
-      get_ttyp ()->write_error = 0;
 
       if (get_ttyp ()->ti.c_lflag & FLUSHO || !buf)
 	continue;
 
-      char *optr;
-      optr = buf;
-      if (pktmode_on)
-	*optr++ = TIOCPKT_DATA;
-
-      if (!(get_ttyp ()->ti.c_oflag & OPOST))	// post-process output
-	{
-	  memcpy (optr, outbuf, n);
-	  optr += n;
-	}
-      else					// raw output mode
-	{
-	  char *iptr = outbuf;
-
-	  while (n--)
-	    {
-	      switch (*iptr)
-		{
-		case '\r':
-		  if ((get_ttyp ()->ti.c_oflag & ONOCR) && column == 0)
-		    {
-		      iptr++;
-		      continue;
-		    }
-		  if (get_ttyp ()->ti.c_oflag & OCRNL)
-		    *iptr = '\n';
-		  else
-		    column = 0;
-		  break;
-		case '\n':
-		  if (get_ttyp ()->ti.c_oflag & ONLCR)
-		    {
-		      *optr++ = '\r';
-		      column = 0;
-		    }
-		  if (get_ttyp ()->ti.c_oflag & ONLRET)
-		    column = 0;
-		  break;
-		default:
-		  column++;
-		  break;
-		}
-
-	      /* Don't store data past the end of the user's buffer.  This
-		 can happen if the user requests a read of 1 byte when
-		 doing \r\n expansion.  */
-	      if (optr - buf >= (int) len)
-		{
-		  if (*iptr != '\n' || n != 0)
-		    system_printf ("internal error: %u unexpected characters", n);
-		  need_nl = 1;
-		  break;
-		}
-
-	      *optr++ = *iptr++;
-	    }
-	}
+      memcpy (optr, outbuf, n);
+      optr += n;
       rc = optr - buf;
       break;
 
@@ -633,7 +573,6 @@ fhandler_pty_slave::init (HANDLE h, DWOR
 ssize_t __stdcall
 fhandler_pty_slave::write (const void *ptr, size_t len)
 {
-  DWORD n;
   ssize_t towrite = len;
 
   bg_check_types bg = bg_check (SIGTTOU);
@@ -644,46 +583,19 @@ fhandler_pty_slave::write (const void *p
 
   push_process_state process_state (PID_TTYOU);
 
-  while (len)
+  if (!process_opost_output (get_output_handle (), ptr, towrite, false))
     {
-      n = MIN (OUT_BUFFER_SIZE, len);
-      char *buf = (char *)ptr;
-      ptr = (char *) ptr + n;
-      len -= n;
-
-      while (tc ()->output_stopped)
-	cygwait (10);
-      acquire_output_mutex (INFINITE);
-
-      /* Previous write may have set write_error to != 0.  Check it here.
-	 This is less than optimal, but the alternative slows down pty
-	 writes enormously. */
-      if (get_ttyp ()->write_error)
-	{
-	  set_errno (get_ttyp ()->write_error);
-	  towrite = -1;
-	  get_ttyp ()->write_error = 0;
-	  release_output_mutex ();
-	  break;
-	}
-
-      BOOL res = WriteFile (get_output_handle (), buf, n, &n, NULL);
-      release_output_mutex ();
-      if (!res)
+      DWORD err = GetLastError ();
+      termios_printf ("WriteFile failed, %E");
+      switch (err)
 	{
-	  DWORD err = GetLastError ();
-	  termios_printf ("WriteFile failed, %E");
-	  switch (err)
-	    {
-	    case ERROR_NO_DATA:
-	      err = ERROR_IO_DEVICE;
-	    default:
-	      __seterrno_from_win_error (err);
-	    }
-	  raise (SIGHUP);		/* FIXME: Should this be SIGTTOU? */
-	  towrite = -1;
-	  break;
+	case ERROR_NO_DATA:
+	  err = ERROR_IO_DEVICE;
+	default:
+	  __seterrno_from_win_error (err);
 	}
+      raise (SIGHUP);		/* FIXME: Should this be SIGTTOU? */
+      towrite = -1;
     }
   return towrite;
 }
@@ -1228,7 +1140,7 @@ errout:
 fhandler_pty_master::fhandler_pty_master (int unit)
   : fhandler_pty_common (), pktmode (0), master_ctl (NULL),
     master_thread (NULL), from_master (NULL), to_master (NULL),
-    dwProcessId (0), need_nl (0)
+    dwProcessId (0)
 {
   if (unit >= 0)
     dev ().parse (DEV_PTYM_MAJOR, unit);
@@ -1763,3 +1675,94 @@ fhandler_pty_master::fixup_after_exec ()
   else
     from_master = to_master = NULL;
 }
+
+BOOL
+fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& len, bool is_echo)
+{
+  ssize_t towrite = len;
+  BOOL res = TRUE;
+  while (towrite)
+    {
+      if (!is_echo)
+	{
+	  if (tc ()->output_stopped && is_nonblocking ())
+	    {
+	      if (towrite < len)
+		break;
+	      else
+		{
+		  set_errno(EAGAIN);
+		  len = -1;
+		  return TRUE;
+		}
+	    }
+	  while (tc ()->output_stopped)
+	    cygwait (10);
+	}
+
+      acquire_output_mutex (INFINITE);
+
+      if (!(get_ttyp ()->ti.c_oflag & OPOST))	// raw output mode
+	{
+	  DWORD n = MIN (OUT_BUFFER_SIZE, towrite);
+	  res = WriteFile (h, ptr, n, &n, NULL);
+	  if (!res)
+	    break;
+	  ptr = (char *) ptr + n;
+	  towrite -= n;
+	}
+      else					// post-process output
+	{
+	  char outbuf[OUT_BUFFER_SIZE + 1];
+	  char *buf = (char *)ptr;
+	  DWORD n = 0;
+	  ssize_t rc = 0;
+	  while (n < OUT_BUFFER_SIZE && rc < towrite)
+	    {
+	      switch (buf[rc])
+		{
+		case '\r':
+		  if ((get_ttyp ()->ti.c_oflag & ONOCR) && get_ttyp ()->column == 0)
+		    {
+		      rc ++;
+		      continue;
+		    }
+		  if (get_ttyp ()->ti.c_oflag & OCRNL)
+		    {
+		      outbuf[n++] = '\n';
+		      rc ++;
+		    }
+		  else
+		    {
+		      outbuf[n++] = buf[rc++];
+		      get_ttyp ()->column = 0;
+		    }
+		  break;
+		case '\n':
+		  if (get_ttyp ()->ti.c_oflag & ONLCR)
+		    {
+		      outbuf[n++] = '\r';
+		      get_ttyp ()->column = 0;
+		    }
+		  if (get_ttyp ()->ti.c_oflag & ONLRET)
+		    get_ttyp ()->column = 0;
+		  outbuf[n++] = buf[rc++];
+		  break;
+		default:
+		  outbuf[n++] = buf[rc++];
+		  get_ttyp ()->column ++;
+		  break;
+		}
+	    }
+	  res = WriteFile (h, outbuf, n, &n, NULL);
+	  if (!res)
+	    break;
+	  ptr = (char *) ptr + rc;
+	  towrite -= rc;
+	}
+
+      release_output_mutex ();
+    }
+  len -= towrite;
+  return res;
+}
Index: src/winsup/cygwin/select.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/select.cc,v
retrieving revision 1.223
diff -u -p -r1.223 select.cc
--- src/winsup/cygwin/select.cc	11 Oct 2014 12:14:29 -0000	1.223
+++ src/winsup/cygwin/select.cc	2 Mar 2015 10:59:23 -0000
@@ -604,11 +604,6 @@ peek_pipe (select_record *s, bool from_s
 	  {
 	    fhandler_pty_master *fhm = (fhandler_pty_master *) fh;
 	    fhm->flush_to_slave ();
-	    if (fhm->need_nl)
-	      {
-		gotone = s->read_ready = true;
-		goto out;
-	      }
 	  }
 	  break;
 	default:
Index: src/winsup/cygwin/tty.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/tty.cc,v
retrieving revision 1.96
diff -u -p -r1.96 tty.cc
--- src/winsup/cygwin/tty.cc	18 Oct 2013 20:07:35 -0000	1.96
+++ src/winsup/cygwin/tty.cc	2 Mar 2015 10:59:23 -0000
@@ -237,6 +237,7 @@ tty::init ()
   was_opened = false;
   master_pid = 0;
   is_console = false;
+  column = 0;
 }
 
 HANDLE
Index: src/winsup/cygwin/tty.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/tty.h,v
retrieving revision 1.37
diff -u -p -r1.37 tty.h
--- src/winsup/cygwin/tty.h	23 Apr 2013 09:44:34 -0000	1.37
+++ src/winsup/cygwin/tty.h	2 Mar 2015 10:59:23 -0000
@@ -67,7 +67,8 @@ public:
    * -ERRNO
    */
   int ioctl_retval;
-  int write_error;
+
+  int column;	/* Current Column */
 
   void setntty (_major_t t, _minor_t n) {ntty = (fh_devices) FHDEV (t, n);}
   dev_t getntty () const {return ntty;}

[-- Attachment #3: Type: text/plain, Size: 218 bytes --]

--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple

  reply	other threads:[~2015-03-02 12:05 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-02-28 12:16 Takashi Yano
2015-02-28 17:02 ` Corinna Vinschen
2015-03-02 12:05   ` Takashi Yano [this message]
2015-03-02 14:27     ` Corinna Vinschen
2015-03-05 10:53       ` Takashi Yano
2015-03-05 12:47         ` Corinna Vinschen
2015-03-18 15:16     ` Corinna Vinschen
2015-03-18 16:27       ` Bengt-Arne Fjellner
2015-03-18 18:46         ` Corinna Vinschen
2015-03-18 23:22       ` Takashi Yano
2015-03-19  8:36         ` Corinna Vinschen
2015-03-20 19:21           ` Corinna Vinschen
2015-03-20 19:44             ` Eric Blake
2015-03-20 21:22               ` Corinna Vinschen
2015-03-21  2:14             ` Takashi Yano
2015-03-23 16:39               ` Corinna Vinschen
2015-03-24 15:07                 ` Corinna Vinschen
2015-03-25 12:41                 ` Takashi Yano

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20150302210508.1be5c1ed4753508431842913@nifty.ne.jp \
    --to=takashi.yano@nifty.ne.jp \
    --cc=cygwin@cygwin.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).