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: gdb pty problem [Was: emacs gud-interface is not updated after gdb command execution (maybe because of incomplete output from gdb)]
Date: Mon, 06 Jun 2016 10:12:00 -0000	[thread overview]
Message-ID: <20160606191231.a60b226a9867c15023e07fb1@nifty.ne.jp> (raw)
In-Reply-To: <20160601141820.GF11431@calimero.vinschen.de>

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

Hi Corinna,

I had looked into this problem, and found the cause.

'man termios' says:
"A read(2) returns at most one line of input" in canonical mode.

On cygwin 2.5.1, read(2) returns all data in buffer if the buffer
size specified is large enough. This behaviour is correct in
noncanonical mode, but is not correct in canonical mode.

So, I would like to propose a following patch.

diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 6c00d61..733644f 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -756,10 +756,6 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
 	  goto out;
 	}
 
-      /* On first peek determine no. of bytes to flush. */
-      if (!ptr && len == UINT_MAX)
-	len = (size_t) bytes_in_pipe;
-
       if (ptr && !bytes_in_pipe && !vmin && !time_to_wait)
 	{
 	  ReleaseMutex (input_mutex);
@@ -767,7 +763,9 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
 	  return;
 	}
 
-      readlen = MIN (bytes_in_pipe, MIN (len, sizeof (buf)));
+      readlen = bytes_in_pipe ? MIN (len, sizeof (buf)) : 0;
+      if (get_ttyp ()->ti.c_lflag & ICANON && ptr)
+	readlen = MIN (bytes_in_pipe, readlen);
 
 #if 0
       /* Why on earth is the read length reduced to vmin, even if more bytes
@@ -804,7 +802,8 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
 		}
 	      if (n)
 		{
-		  len -= n;
+		  if (!(!ptr && len == UINT_MAX)) /* not tcflush() */
+		    len -= n;
 		  totalread += n;
 		  if (ptr)
 		    {

While checking this problem, I found a bug of tcflush().
tcflush() flushes only partial data in the buffer.

The patch above also fixes this bug.

A test case attached (pty_readlen.c) is for confirming
the behaviour of read() and tcflush(). 

Test results are as follows.

debian GNU/Linux:
----------
01234
----------
56789
ABCDE
----------
----------

cygwin 2.5.1:
----------
01234
56789
----------
ABCDE
----------
KLMNO
----------

cygwin 2.5.2 (git head):
----------
01234
----------
56789
----------
FGHIJ
----------

cygwin with a patch I propose:
----------
01234
----------
56789
ABCDE
----------
----------

Of course, Ken's gdbstc works fine without sleep with this patch,
as well as original emacs case.



On Wed, 1 Jun 2016 16:18:20 +0200
Corinna Vinschen <corinna-cygwin@cygwin.com> wrote:

> Hi Takashi,
> 
> 
> can you please have a look?
> 
> 
> Thanks,
> Corinna
> 
> 
> On Jun  1 08:51, Ken Brown wrote:
> > On 5/31/2016 5:41 AM, Corinna Vinschen wrote:
> > > Any chance you could bisect Cygwin to help finding the culprit?
> > 
> > The culprit is
> > 
> > commit 252a07b0ad3353abcd0fcd9b1b65ff977acd679e
> > Author: Takashi Yano <takashi.yano@nifty.ne.jp>
> > Date:   Fri Apr 3 13:07:35 2015 +0900
> > 
> >    Cygwin hangs up if several keys are typed during outputting a lot of texts.
> > 
> >        * fhandler_tty.cc (fhandler_pty_slave::read): Change calculation of
> >        "readlen" not to use "bytes_in_pipe" value directly.
> > 
> > 
> > Reverting that commit fixes the problem.  To test, compile and run the attached file.
> > 
> > $ gcc gdbstc.cc
> > 
> > $ ./a
> > 1-inferior-tty-set /dev/pty3
> > 2-gdb-set height 0
> > 3-gdb-set non-stop 1
> > 4-file-list-exec-source-files
> > 5-file-list-exec-source-file
> > 6-gdb-show prompt
> > 7-stack-info-frame
> > 8-thread-info
> > 9-break-list
> > q
> > *** using gdb
> > =thread-group-added,id="i1"
> > ~"GNU gdb (GDB) (Cygwin 7.10.1-1) 7.10.1\n"
> > ~"Copyright (C) 2015 Free Software Foundation, Inc.\n"
> > ~"License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\nThis is free software: you are free to change and redistribute it.\nThere is NO WARRANTY, to the extent permitted by law.  Type \"show copying\"\nand \"show warranty\" for details.\n"
> > ~"This GDB was configured as \"i686-pc-cygwin\".\nType \"show configuration\" for configuration details."
> > ~"\nFor bug reporting instructions, please see:\n"
> > ~"<http://www.gnu.org/software/gdb/bugs/>.\n"
> > ~"Find the GDB manual and other documentation resources online at:\n<http://www.gnu.org/software/gdb/documentation/>.\n"
> > ~"For help, type \"help\".\n"
> > ~"Type \"apropos word\" to search for commands related to \"word\".\n"
> > =cmd-param-changed,param="auto-load safe-path",value="/"
> > (gdb)
> > ...
> > 
> > In bad cases (bug present), the program hangs and doesn't complete until the gdb process is killed from a different terminal.  In good cases it runs to completion.
> > 
> > Ken
> 
> > #include <stdio.h>
> > #include <stdlib.h>
> > #include <unistd.h>
> > #include <pty.h>
> > #include <string.h>
> > #include <sys/wait.h>
> > 
> > void get_output (int fd);
> > 
> > int
> > main (int argc, const char **argv) 
> > {
> >   int master;
> >   pid_t pid;
> > 
> >   if ((pid = forkpty (&master, NULL, NULL, NULL)) < 0)
> >     {
> >       perror ("forkpty");
> >       exit (1);
> >     }
> >   /* child */
> >   if (pid == 0) 
> >     {
> >       const char *av[100];
> >       // putenv ("HOME=/tmp");
> >       int i = 0;
> > #ifdef STRACE_GDB
> >       av[i++] = "strace";
> >       av[i++] = "-o";
> >       av[i++] = "/tmp/strace.out";
> > #ifdef __CYGWIN__
> >       av[i++] = "--mask=all+paranoid";
> > #endif
> > #endif
> >       av[i++] = argv[1] ?: "gdb";
> >       fprintf (stderr, "*** using %s\n", av[0]);
> >       av[i++] = "-i=mi";
> >       av[i] = NULL;
> >       execvp (av[0], (char * const *) av);
> >       /* shouldn't get here */
> >       exit (1);
> >     }
> >   /* parent */
> >   const char *input[20];
> > 
> >   int i = 0;
> >   input[i++] = "1-inferior-tty-set /dev/pty3\n";
> >   input[i++] = "2-gdb-set height 0\n";
> >   input[i++] = "3-gdb-set non-stop 1\n";
> >   input[i++] = "4-file-list-exec-source-files\n";
> >   input[i++] = "5-file-list-exec-source-file\n";
> >   input[i++] = "6-gdb-show prompt\n";
> >   input[i++] = "7-stack-info-frame\n";
> >   input[i++] = "8-thread-info\n";
> >   input[i++] = "9-break-list\n";
> >   input[i++] = "q\n";
> >   input[i] = NULL;
> > 
> >   for (int i = 0; input[i]; ++i)
> >     {
> >       write (master, input[i], strlen (input[i]));
> >       // sleep (1);
> >     }
> >   get_output (master);
> >   wait (NULL);
> > }
> > 
> > void
> > get_output (int fd)
> > {
> >   char buf[4096];
> > 
> >   while (1)
> >     {
> >       int nread = read (fd, buf, sizeof (buf));
> >       if (nread > 0)
> > 	write (STDOUT_FILENO, buf, nread);
> >       else
> > 	{
> > 	  printf ("No more output.  nread %d\n", nread);
> > 	  break;
> > 	}
> >     }
> > }
> > 
> > 
> 
> > --
> > 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
> 
> 
> -- 
> Corinna Vinschen                  Please, send mails regarding Cygwin to
> Cygwin Maintainer                 cygwin AT cygwin DOT com
> Red Hat


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

[-- Attachment #2: pty_readlen.c --]
[-- Type: text/x-csrc, Size: 1382 bytes --]

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <pty.h>

int main()
{
	int master, slave;
	struct termios tt;
	int val;
	char buf[1024];
	int len;

	if (openpty(&master, &slave, NULL, NULL, NULL) < 0) {
		perror("openpty()");
		exit(EXIT_FAILURE);
	}

	write(STDOUT_FILENO, "----------\n", 11);

	/* Write two messages */
	write(master, "01234\n", 6);
	write(master, "56789\n", 6);

	/* Read (Canonical Mode) */
	len = read(slave, buf, sizeof(buf));
	if (len>0) write(STDOUT_FILENO, buf, len);

	/* Rrset Canonical Mode */
	tcgetattr(slave, &tt);
	tt.c_lflag &= ~ICANON;
	tcsetattr(slave, TCSANOW, &tt);

	write(STDOUT_FILENO, "----------\n", 11);

	write(master, "ABCDE\n", 6);

	/* Read (Non-Canonical Mode) */
	len = read(slave, buf, sizeof(buf));
	if (len>0) write(STDOUT_FILENO, buf, len);

	write(STDOUT_FILENO, "----------\n", 11);

	/* Write two messages */
	write(master, "FGHIJ\n", 6);
	write(master, "KLMNO\n", 6);

	/* Set Canonical Mode */
	tcgetattr(slave, &tt);
	tt.c_lflag |= ICANON;
	tcsetattr(slave, TCSANOW, &tt);

	/* Flush buffer */
	tcflush(slave, TCIFLUSH);
	val = 1;
	ioctl(slave, FIONBIO, &val);

	/* Read */
	len = read(slave, buf, sizeof(buf));
	if (len>0) write(STDOUT_FILENO, buf, len);

	write(STDOUT_FILENO, "----------\n", 11);

	close(slave);
	close(master);

	return EXIT_SUCCESS;
}


[-- 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:[~2016-06-06 10:12 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-05-26 12:32 emacs gud-interface is not updated after gdb command execution (maybe because of incomplete output from gdb) Tobias Zawada
2016-05-26 15:48 ` William M. (Mike) Miller
2016-05-26 17:48 ` Ken Brown
2016-05-26 18:00   ` Tobias Zawada
2016-05-26 18:01     ` Ken Brown
2016-05-31  1:47   ` gdb pty problem [Was: emacs gud-interface is not updated after gdb command execution (maybe because of incomplete output from gdb)] Ken Brown
2016-05-31  9:35     ` Ken Brown
2016-05-31 22:41       ` Corinna Vinschen
2016-06-01 12:51         ` Ken Brown
2016-06-01 13:02           ` Ken Brown
2016-06-01 14:28             ` Corinna Vinschen
2016-06-01 14:29               ` Corinna Vinschen
2016-06-01 14:33               ` Ken Brown
2016-06-01 15:22                 ` Ken Brown
2016-06-01 18:29                   ` Corinna Vinschen
2016-06-01 19:05                     ` Ken Brown
2016-06-01 19:54                       ` Corinna Vinschen
2016-06-01 20:01                         ` Ken Brown
2016-06-01 21:05                           ` [GOLDSTAR] " Corinna Vinschen
2016-06-02  2:09                             ` Andrew Schulman
2016-06-01 14:18           ` Corinna Vinschen
2016-06-06 10:12             ` Takashi Yano [this message]
2016-06-06 13:16               ` Corinna Vinschen
2016-06-07 13:14                 ` Takashi Yano
2016-06-07 16:11                   ` Corinna Vinschen
2016-06-06 14:01               ` Ken Brown

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=20160606191231.a60b226a9867c15023e07fb1@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).