aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog8
-rw-r--r--gdb/ser-base.c19
-rw-r--r--gdb/testsuite/ChangeLog5
-rw-r--r--gdb/testsuite/gdb.base/long-inferior-output.c38
-rw-r--r--gdb/testsuite/gdb.base/long-inferior-output.exp75
5 files changed, 145 insertions, 0 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 9e7c342..6625a03 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,13 @@
2017-10-19 Pedro Alves <palves@redhat.com>
+ * ser-base.c (ser_base_read_error_fd): Delete the file handler if
+ async.
+ (handle_error_fd): New function.
+ (ser_base_async): Add/delete an event loop file handler for
+ error_fd.
+
+2017-10-19 Pedro Alves <palves@redhat.com>
+
* xml-support.c (xml_fetch_content_from_file): Don't read in
chunks. Instead use fseek to determine the file's size, and read
it in one go.
diff --git a/gdb/ser-base.c b/gdb/ser-base.c
index 790cb1b..2bfe82b 100644
--- a/gdb/ser-base.c
+++ b/gdb/ser-base.c
@@ -288,6 +288,8 @@ ser_base_read_error_fd (struct serial *scb, int close_fd)
if (s == 0 && close_fd)
{
/* End of file. */
+ if (serial_is_async_p (scb))
+ delete_file_handler (scb->error_fd);
close (scb->error_fd);
scb->error_fd = -1;
break;
@@ -313,6 +315,17 @@ ser_base_read_error_fd (struct serial *scb, int close_fd)
}
}
+/* Event-loop callback for a serial's error_fd. Flushes any error
+ output we might have. */
+
+static void
+handle_error_fd (int error, gdb_client_data client_data)
+{
+ serial *scb = (serial *) client_data;
+
+ ser_base_read_error_fd (scb, 0);
+}
+
/* Read a character with user-specified timeout. TIMEOUT is number of
seconds to wait, or -1 to wait forever. Use timeout of 0 to effect
a poll. Returns char if successful. Returns SERIAL_TIMEOUT if
@@ -589,6 +602,9 @@ ser_base_async (struct serial *scb,
fprintf_unfiltered (gdb_stdlog, "[fd%d->asynchronous]\n",
scb->fd);
reschedule (scb);
+
+ if (scb->error_fd != -1)
+ add_file_handler (scb->error_fd, handle_error_fd, scb);
}
else
{
@@ -607,5 +623,8 @@ ser_base_async (struct serial *scb,
delete_timer (scb->async_state);
break;
}
+
+ if (scb->error_fd != -1)
+ delete_file_handler (scb->error_fd);
}
}
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index de13645..e8f95ed 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2017-10-19 Pedro Alves <palves@redhat.com>
+
+ * gdb.base/long-inferior-output.c: New file.
+ * gdb.base/long-inferior-output.exp: New file.
+
2017-11-18 Keith Seitz <keiths@redhat.com>
* gdb.cp/cpexprs.cc (base) <operator fluff const* const*>: New
diff --git a/gdb/testsuite/gdb.base/long-inferior-output.c b/gdb/testsuite/gdb.base/long-inferior-output.c
new file mode 100644
index 0000000..eb3d5c5
--- /dev/null
+++ b/gdb/testsuite/gdb.base/long-inferior-output.c
@@ -0,0 +1,38 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2017 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+
+static size_t total_bytes = 0;
+
+int
+main ()
+{
+ int i = 0;
+
+ /* When testing with "target remote |", stdout is a pipe, and thus
+ block buffered by default. Force it to be line buffered. */
+ setvbuf (stdout, NULL, _IOLBF, 0);
+
+ /* This outputs > 70 KB which is larger than the default pipe buffer
+ size on most systems (typically 16 KB or 64 KB). */
+ for (i = 0; i < 3000; i++)
+ total_bytes += printf ("this is line number %d\n", i);
+
+ printf ("total bytes written = %u\n", (unsigned) total_bytes);
+ return 0; /* printing done */
+}
diff --git a/gdb/testsuite/gdb.base/long-inferior-output.exp b/gdb/testsuite/gdb.base/long-inferior-output.exp
new file mode 100644
index 0000000..ae9386c
--- /dev/null
+++ b/gdb/testsuite/gdb.base/long-inferior-output.exp
@@ -0,0 +1,75 @@
+# Copyright 2017 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# When debugging with "target remote |", the inferior's output is
+# connected to a pipe, and if GDB doesn't flush the pipe while the
+# inferior is running and the pipe becomes full, then the inferior
+# deadlocks:
+#
+# 1. User sets breakpoint, and types "continue"
+#
+# 2. Inferior prints to stdout/stderr before reaching breakpoint
+# location.
+#
+# 3. The output pipe becomes full, so the inferior blocks forever in
+# the printf/write call.
+#
+# 4. The breakpoint is never reached.
+
+if [target_info exists gdb,noinferiorio] {
+ verbose "Skipping because of noinferiorio."
+ return
+}
+
+standard_testfile
+
+if [prepare_for_testing "failed to prepare" $testfile {} {debug}] {
+ return -1
+}
+
+if { ![runto_main] } then {
+ fail "run to main"
+ return
+}
+
+set printing_done_line [gdb_get_line_number "printing done"]
+gdb_test "break $printing_done_line" ".*" "set breakpoint after printing"
+
+send_gdb "continue\n"
+
+set expected_lines 3000
+set more 1
+set i 0
+while {$more} {
+ set more 0
+ gdb_expect {
+ -i $inferior_spawn_id
+ -ex "this is line number $i" {
+ incr i
+ if {$i != $expected_lines} {
+ set more 1
+ }
+ }
+ }
+}
+
+gdb_assert {$i == $expected_lines} "saw all lines"
+
+set test "breakpoint reached"
+gdb_test_multiple "" $test {
+ -re "Breakpoint .* main .*$srcfile:$printing_done_line.*$gdb_prompt $" {
+ pass $test
+ }
+}