This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: [PATCH with testcase] Bug 11568 - delete thread-specific breakpoint on the thread exit
- From: Muhammad Waqas <mwaqas at codesourcery dot com>
- To: Pedro Alves <palves at redhat dot com>
- Cc: Yao Qi <yao at codesourcery dot com>, <gdb-patches at sourceware dot org>, <tromey at redhat dot com>, <ali_anwar at codesourcery dot com>
- Date: Mon, 5 Aug 2013 17:01:34 +0500
- Subject: Re: [PATCH with testcase] Bug 11568 - delete thread-specific breakpoint on the thread exit
- References: <51F619CE dot 5040407 at codesourcery dot com> <51F633E5 dot 7000302 at codesourcery dot com> <51F65519 dot 2080806 at codesourcery dot com> <51F67992 dot 30704 at codesourcery dot com> <51F7967E dot 3060900 at codesourcery dot com> <51FA4D21 dot 4000309 at redhat dot com> <51FA5806 dot 7050505 at codesourcery dot com> <51FB7F9E dot 30701 at redhat dot com>
On 08/02/2013 02:45 PM, Pedro Alves wrote:
On 08/01/2013 01:43 PM, Muhammad Waqas wrote:
+ || !target_thread_alive (tp->ptid)))
+ if ( tp != NULL && (tp->state == THREAD_EXITED
+ || !target_thread_alive (tp->ptid)))
Do we really need this target_thread_alive call? It
means we have extra remote traffic whenever we have a thread
specific breakpoint in the list. If the user (or GDB itself)
hasn't refreshed the thread list, is there any harm in delaying
deleting the breakpoint?
But, I think I agree with Yao in that this doesn't look like
the right way to do this.
In fact, breakpoint_auto_delete is only called when the
target reports some stop. If you're trying to delete
stale thread specific breakpoints, then you'd want to
do that even if the target hasn't reported a stop, right?
Say, in non-stop mode, w/ the remote target, if you have two
threads, set a thread-specific break on thread 2, and while
all threads are running free in busy loops, not reporting
any event, keep doing "info threads", and "info break". At some
point thread #2 exits. You can see that from "info threads".
But "info break" will still show you the stale breakpoint...
If breakpoint will be deleted when thread list is updated through
user or GDB and also when info break command is executed
by user, Will it work? What will you say about this technique?
I wouldn't even consider special casing "info break". Otherwise,
you end up considering whether to handle all sorts of breakpoint
manipulation commands, like "enable", "disable", etc., and what
to do if the thread is already gone.
Tie this to GDB's own lifetime of the inferior's threads. If GDB
learns the thread is gone, remove the breakpoint. Otherwise,
leave it there. Whether to remove the breakpoint immediately,
or mark it as disp_del_at_next_stop (and hide it, say, set its
bp->num to 0) is another question. You'll note that
clear_thread_inferior_resources does the latter. (That's because
most of GDB's native targets can't touch memory of running processes.)
Thanks for review and helping me out.
Now I register a function for deletion of breakpoint with thread_exit if breakpoint
is on thread so breakpoint will be deleted when thread finished.
Changlog
2013-08-05 Muhammad Waqas <mwaqas@codesourcery.com>
PR gdb/11568
* breakpoint.c (remove_threaded_breakpoints): New function.
* breakpoint.c (install_breakpoint): If breakpoint is on specific
thread remove_threaded_breakpoints will be registered with thread_exit.
Index: ./../../breakpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.c,v
retrieving revision 1.773
diff -u -p -r1.773 breakpoint.c
--- ./../../breakpoint.c 24 Jul 2013 19:50:32 -0000 1.773
+++ ./../../breakpoint.c 5 Aug 2013 11:51:43 -0000
@@ -200,6 +200,8 @@ typedef enum
}
insertion_state_t;
+static void remove_threaded_breakpoints (struct thread_info *tp, int silent);
+
static int remove_breakpoint (struct bp_location *, insertion_state_t);
static int remove_breakpoint_1 (struct bp_location *, insertion_state_t);
@@ -2928,6 +2930,21 @@ remove_breakpoints (void)
return val;
}
+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;
+ b->number = 0;
+ }
+ }
+}
+
/* Remove breakpoints of process PID. */
int
@@ -8450,7 +8467,12 @@ install_breakpoint (int internal, struct
if (!internal)
mention (b);
observer_notify_breakpoint_created (b);
-
+
+ if (b->thread > 0)
+ {
+ observer_attach_thread_exit (remove_threaded_breakpoints);
+ }
+
if (update_gll)
update_global_location_list (1);
}
Changlog
2013-07-24 Muhammad Waqas <mwaqas@codesourccery.com>
Jan Kratochvil <jan.kartochvil@redhat.com>
PR gdb/11568
*gdb.thread/thread-specific-bp.c: Newfile.
*gdb.thread/thread-specific-bp.exp: Newfile.
testcase now testing All stop and non stop mode explicitly
Index: thread-specific-bp.c
===================================================================
RCS file: thread-specific-bp.c
diff -N thread-specific-bp.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ thread-specific-bp.c 5 Aug 2013 11:51:51 -0000
@@ -0,0 +1,33 @@
+/* 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;
+}
+
+int
+main (void)
+{
+ pthread_t thread;
+ pthread_create (&thread, NULL, start, NULL);
+ pthread_join (thread, NULL);
+ return 0; /*set break here*/
+}
Index: thread-specific-bp.exp
===================================================================
RCS file: thread-specific-bp.exp
diff -N thread-specific-bp.exp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ thread-specific-bp.exp 5 Aug 2013 11:52:03 -0000
@@ -0,0 +1,84 @@
+# 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
+
+set mode "All stop"
+
+if {[gdb_compile_pthreads \
+ "${srcdir}/${subdir}/${srcfile}" \
+ "${binfile}" executable {debug} ] != "" } {
+ return -1
+}
+
+clean_restart ${binfile}
+
+proc check_threaded_breakpoint {} {
+ global gdb_prompt mode
+ gdb_breakpoint "start"
+ gdb_continue_to_breakpoint "start"
+ set thre 0
+ gdb_test_multiple "info threads" "get thread 1 id" {
+ -re "(\[0-9\]+)(\[^\n\r\]*Thread\[^\n\r\]*start.*)($gdb_prompt $)" {
+ pass "$mode: thread created"
+ # get the id of thread
+ set thre $expect_out(1,string)
+ }
+ }
+ gdb_breakpoint [gdb_get_line_number "set break here"]
+
+ # Force GDB to update its knowledge on existing threads when this
+ # breakpoint is hit. Otherwise, GDB doesn't realize thread $thre
+ # has exited and doesn't remove the thread specific breakpoint.
+ gdb_test "commands\ninfo threads\nend" "End with.*" "$mode: add breakpoint commands"
+ gdb_breakpoint "main thread $thre"
+ gdb_test "info break" ".*breakpoint.*thread $thre" "$mode: Breakpoint set"
+ gdb_test "thread $thre" "Switching to thread $thre.*" "$mode: Thread $thre selected"
+ gdb_continue_to_breakpoint "$mode: set break here"
+ set test "$mode: thread-specific breakpoint is deleted"
+ gdb_test_multiple "info breakpoint" $test {
+ -re "thread $thre.*$gdb_prompt $" {
+ fail $test
+ }
+ -re "$gdb_prompt $" {
+ pass $test
+ }
+ }
+}
+
+if ![runto_main] {
+ untested "could not run to main"
+ return -1
+}
+
+# Testing in all stop mode.
+check_threaded_breakpoint
+
+clean_restart ${binfile}
+
+gdb_test "set target-async on" ".*" "Set async mode"
+gdb_test "set non-stop on" ".*" "Set non stop mode"
+
+if ![runto_main] {
+ untested "could not run to main"
+ return -1
+}
+
+# Testing in non-stop+async mode.
+set mode "non-stop\\async"
+check_threaded_breakpoint