diff options
-rw-r--r-- | gdb/ChangeLog | 8 | ||||
-rw-r--r-- | gdb/ser-base.c | 19 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/long-inferior-output.c | 38 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/long-inferior-output.exp | 75 |
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 + } +} |