return val;
}
+/* When a thread exits, remove breakpoints that are related to
+ that thread. */
+
+static void
+remove_threaded_breakpoints (struct thread_info *tp, int silent)
+{
+ struct breakpoint *b, *b_tmp;
+
+ ALL_BREAKPOINTS_SAFE (b, b_tmp)
+ {
+ if (b->thread == tp->num)
+ {
+ b->disposition = disp_del_at_next_stop;
+
+ printf_filtered (_("\
+Thread-specific breakpoint %d deleted - thread %d is gone.\n"),
+ b->number, tp->num);
+
+ /* Hide it from the user. */
+ b->number = 0;
+ }
+ }
+}
+
/* Remove breakpoints of process PID. */
int
automatic_hardware_breakpoints = 1;
observer_attach_about_to_proceed (breakpoint_about_to_proceed);
+ observer_attach_thread_exit (remove_threaded_breakpoints);
}
--- /dev/null
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2013 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 void *
+start (void *arg)
+{
+ return NULL;
+}
+
+static void
+end (void)
+{
+}
+
+int
+main (void)
+{
+ pthread_t thread;
+
+ pthread_create (&thread, NULL, start, NULL);
+ pthread_join (thread, NULL);
+ end ();
+ return 0;
+}
--- /dev/null
+# Copyright (C) 2013 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/>.
+#
+# Verify that a thread-specific breakpoint is deleted when the
+# corresponding thread is gone.
+
+standard_testfile
+
+if {[gdb_compile_pthreads \
+ "${srcdir}/${subdir}/${srcfile}" \
+ "${binfile}" executable {debug} ] != "" } {
+ return -1
+}
+
+clean_restart ${binfile}
+
+# Extract and return the thread ID of the thread stopped at function
+# FUNC.
+
+proc get_thread_id {func} {
+ global gdb_prompt
+
+ set thre -1
+ set test "get $func thread id"
+ gdb_test_multiple "info threads" $test {
+ -re "(\[0-9\]+)\[^\n\r\]*Thread\[^\n\r\]*$func.*$gdb_prompt $" {
+ # Get the thread's id.
+ set thre $expect_out(1,string)
+ pass $test
+ }
+ }
+
+ return $thre
+}
+
+proc check_thread_specific_breakpoint {mode} {
+ with_test_prefix "$mode" {
+ global gdb_prompt
+
+ if ![runto_main] {
+ untested "could not run to main"
+ return -1
+ }
+
+ set main_thre [get_thread_id "main"]
+ if { $main_thre < 0 } {
+ return -1
+ }
+
+ gdb_breakpoint "start"
+ gdb_continue_to_breakpoint "start"
+
+ set start_thre [get_thread_id "start"]
+ if { $start_thre < 0 } {
+ return -1
+ }
+
+ # Set a thread-specific breakpoint at "main". This can't ever
+ # be hit, but that's OK.
+ gdb_breakpoint "main thread $start_thre"
+ gdb_test "info break" ".*breakpoint.*thread $start_thre" "breakpoint set"
+
+ # Set breakpoint at a place only reacheable after the "start"
+ # thread exits.
+ gdb_breakpoint "end"
+
+ # Switch back to the main thread, and resume all threads. The
+ # "start" thread exits, and the main thread reaches "end".
+ gdb_test "thread $main_thre" \
+ "Switching to thread $main_thre.*" \
+ "thread $main_thre selected"
+
+ if { $mode == "non-stop" } {
+ set cmd "continue -a"
+ } else {
+ set cmd "continue"
+ }
+ gdb_test "$cmd" \
+ "Breakpoint .* end .* at .*" \
+ "continue to end"
+
+ # Force GDB to update the thread list. Otherwise, depending
+ # on target, GDB may not realize that the start thread has
+ # exited and thus not remove the thread specific breakpoint.
+ set test "thread start is gone"
+ gdb_test_multiple "info threads" $test {
+ -re "\[0-9\]+.*start.*$gdb_prompt $" {
+ fail $test
+ }
+ -re "$gdb_prompt $" {
+ pass $test
+ }
+ }
+
+ set test "thread-specific breakpoint was deleted"
+ gdb_test_multiple "info breakpoint" $test {
+ -re "thread $start_thre\n$gdb_prompt $" {
+ fail $test
+ }
+ -re "$gdb_prompt $" {
+ pass $test
+ }
+ }
+ }
+}
+
+# Test all-stop mode.
+check_thread_specific_breakpoint "all-stop"
+
+clean_restart ${binfile}
+
+# Test non-stop mode.
+gdb_test_no_output "set target-async on" "set async mode"
+gdb_test_no_output "set non-stop on" "set non-stop mode"
+check_thread_specific_breakpoint "non-stop"