This is the mail archive of the
cygwin
mailing list for the Cygwin project.
Re: gdb pty problem [Was: emacs gud-interface is not updated after gdb command execution (maybe because of incomplete output from gdb)]
- From: Takashi Yano <takashi dot yano at nifty dot ne dot jp>
- To: cygwin at cygwin dot com
- Date: Mon, 6 Jun 2016 19:12:31 +0900
- Subject: Re: gdb pty problem [Was: emacs gud-interface is not updated after gdb command execution (maybe because of incomplete output from gdb)]
- Authentication-results: sourceware.org; auth=none
- Dkim-filter: OpenDKIM Filter v2.10.3 conuserg-06.nifty.com u56ACNc4024754
- References: <466943424 dot 37628 dot 394d161a-7219-415d-a659-0f774811ad2d dot open-xchange at email dot 1und1 dot de> <44459aa0-4381-2368-ab63-5dffc26f3344 at cornell dot edu> <e29d08b0-aaed-46ea-a4eb-960b1e462692 at cornell dot edu> <a50d8bef-cc9b-3b35-8812-b26360591662 at cornell dot edu> <20160531094115 dot GE24015 at calimero dot vinschen dot de> <34c9cf10-4930-a017-92fc-fd56171671b1 at cornell dot edu> <20160601141820 dot GF11431 at calimero dot vinschen dot de>
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>
#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;
}
--
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