+2015-01-23 Pedro Alves <palves@redhat.com>
+
+ * linux-nat.c (linux_is_async_p): New macro.
+ (linux_nat_is_async_p):
+ (linux_nat_terminal_inferior): Check whether the target can async
+ instead of whether it is already async.
+ (linux_nat_terminal_ours): Don't check whether the target is
+ async.
+ (linux_async_pipe): Use linux_is_async_p.
+
2015-01-22 Jan Kratochvil <jan.kratochvil@redhat.com>
* NEWS (Changes since GDB 7.9): Add 'thread apply all' option
event loop. */
static int linux_nat_event_pipe[2] = { -1, -1 };
+/* True if we're currently in async mode. */
+#define linux_is_async_p() (linux_nat_event_pipe[0] != -1)
+
/* Flush the event pipe. */
static void
static int
linux_nat_is_async_p (struct target_ops *ops)
{
- /* NOTE: palves 2008-03-21: We're only async when the user requests
- it explicitly with the "set target-async" command.
- Someday, linux will always be async. */
- return target_async_permitted;
+ return linux_is_async_p ();
}
/* target_can_async_p implementation. */
static void
linux_nat_terminal_inferior (struct target_ops *self)
{
- if (!target_is_async_p ())
+ /* Like target_terminal_inferior, use target_can_async_p, not
+ target_is_async_p, since at this point the target is not async
+ yet. If it can async, then we know it will become async prior to
+ resume. */
+ if (!target_can_async_p ())
{
/* Async mode is disabled. */
child_terminal_inferior (self);
static void
linux_nat_terminal_ours (struct target_ops *self)
{
- if (!target_is_async_p ())
- {
- /* Async mode is disabled. */
- child_terminal_ours (self);
- return;
- }
-
/* GDB should never give the terminal to the inferior if the
inferior is running in the background (run&, continue&, etc.),
but claiming it sure should. */
static int
linux_async_pipe (int enable)
{
- int previous = (linux_nat_event_pipe[0] != -1);
+ int previous = linux_is_async_p ();
if (previous != enable)
{
+2015-01-23 Pedro Alves <palves@redhat.com>
+
+ * gdb.threads/continue-pending-after-query.c: New file.
+ * gdb.threads/continue-pending-after-query.exp: New file.
+
2015-01-22 Anders Granlund <anders.granlund@ericsson.com>
Simon Marchi <simon.marchi@ericsson.com>
--- /dev/null
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2013-2015 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 <pthread.h>
+
+static int global;
+
+static void
+break_function (void)
+{
+ global = 42; /* set break here */
+}
+
+static void *
+thread_function (void *arg)
+{
+ break_function ();
+
+ return arg;
+}
+
+int
+main (void)
+{
+ pthread_t th;
+
+ pthread_create (&th, NULL, thread_function, NULL);
+
+ break_function ();
+
+ pthread_join (th, NULL);
+
+ return 0;
+}
--- /dev/null
+# This testcase is part of GDB, the GNU debugger.
+#
+# Copyright 2013-2015 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/>.
+
+# Regression test for a bug that would go like this:
+#
+# - Run to a breakpoint that is hit by two threads (A and B)
+# simultaneously.
+#
+# - One of the breakpoint hits is processed (e.g., thread A) and
+# causes a user-visible stop. The other (thread B) is left pending.
+#
+# - The user deletes the breakpoint with "del", which causes a
+# confirmation query.
+#
+# - By mistake, that would result in the target being left with async
+# enabled, even though it wasn't to begin with.
+#
+# - GDB reacts to target async enablement by polling for target
+# events. As no thread is resumed the target replies
+# TARGET_WAITKIND_NO_RESUMED.
+#
+# - The user continues the program, expecting it to exit. The thread
+# that has an event pending (thread B) is not really resumed.
+#
+# - But, nothing signals the event loop that there's a pending event
+# waiting to be collected for thread B, so that event is never
+# processed, thread B is never resumed and the program never exits.
+#
+# Ref: https://sourceware.org/ml/gdb-patches/2015-01/msg00592.html
+
+standard_testfile
+
+if {[prepare_for_testing "failed to prepare" $testfile $srcfile {debug pthreads}] == -1} {
+ return -1
+}
+
+proc test {} {
+ global srcfile gdb_prompt
+
+ if ![runto_main] {
+ return -1
+ }
+
+ delete_breakpoints
+
+ set bp_line [gdb_get_line_number "set break here" $srcfile]
+
+ gdb_breakpoint "break_function"
+ gdb_continue_to_breakpoint "cont to break_function" ".*$srcfile:$bp_line\r\n.*"
+
+ # Do something that causes a query/secondary prompt.
+
+ set test "delete breakpoints, answer prompt"
+ set saw_prompt 0
+ gdb_test_multiple "delete breakpoints" $test {
+ -re "Delete all breakpoints.*y or n.*$" {
+ set saw_prompt 1
+ send_gdb "y\n"
+ exp_continue
+ }
+ -re "$gdb_prompt $" {
+ gdb_assert $saw_prompt $test
+ }
+ }
+
+ gdb_continue_to_end "" "continue" 1
+}
+
+# Test a few times to make sure an event is left pending. At the time
+# of writing, the bug always triggers, but that might naturally depend
+# on machine.
+for {set i 1} {$i <= 10} {incr i} {
+ with_test_prefix "iter $i" {
+ test
+ }
+}