Inform about new thread in a single place.
* thread.c (add_thread_silent): Renamed from add_thread. (print_thread_events): New variable definition. (show_print_thread_events): New function. (_initialize_thread): Add "set print thread-events" and "show print thread-events" commands. (add_thread): Announce new thread. * gdbthread.h (add_thread_silent): Declare. (print_thread_events): New variable declaration. * inf-ttrace.c (inf_ttrace_wait): Don't inform about new thread, as add_thread is always called too, and will take care of that. * infrun.c (handle_inferior_event): Likewise. * procfs.c (procfs_wait): Likewise. * remote.c (remote_currthread): Likewise. * sol-thread.c (sol_thread_wait): Likewise. * win32-nat.c (get_win32_debug_event): Likewise. * linux-thread-db.c (attach_thread): Likewise. Remove the verbose parameter. (check_event): Make detach_thread be verbose only if print_thread_events is set. * linux-nat.c (lin_lwp_attach_lwp): Don't inform about new thread. This is called only from linux-thread-db.c:attach_thread, which will take care. Remove the verbose parameter. * linux-nat.h (lin_lwp_attach_lwp): Adjust prototype.
This commit is contained in:
parent
73f4030dfa
commit
93815fbfa5
19 changed files with 327 additions and 62 deletions
|
@ -1,3 +1,33 @@
|
||||||
|
2008-01-23 Vladimir Prus <vladimir@codesourcery.com>
|
||||||
|
Chris Demetriou <cgd@google.com>
|
||||||
|
|
||||||
|
* thread.c (add_thread_silent): Renamed
|
||||||
|
from add_thread.
|
||||||
|
(print_thread_events): New variable definition.
|
||||||
|
(show_print_thread_events): New function.
|
||||||
|
(_initialize_thread): Add "set print thread-events" and
|
||||||
|
"show print thread-events" commands.
|
||||||
|
(add_thread): Announce new thread.
|
||||||
|
* gdbthread.h (add_thread_silent): Declare.
|
||||||
|
(print_thread_events): New variable declaration.
|
||||||
|
* inf-ttrace.c (inf_ttrace_wait): Don't
|
||||||
|
inform about new thread, as add_thread is always
|
||||||
|
called too, and will take care of that.
|
||||||
|
* infrun.c (handle_inferior_event): Likewise.
|
||||||
|
* procfs.c (procfs_wait): Likewise.
|
||||||
|
* remote.c (remote_currthread): Likewise.
|
||||||
|
* sol-thread.c (sol_thread_wait): Likewise.
|
||||||
|
* win32-nat.c (get_win32_debug_event): Likewise.
|
||||||
|
* linux-thread-db.c (attach_thread): Likewise.
|
||||||
|
Remove the verbose parameter.
|
||||||
|
(check_event): Make detach_thread be verbose
|
||||||
|
only if print_thread_events is set.
|
||||||
|
* linux-nat.c (lin_lwp_attach_lwp): Don't inform
|
||||||
|
about new thread. This is called only from
|
||||||
|
linux-thread-db.c:attach_thread, which will take care.
|
||||||
|
Remove the verbose parameter.
|
||||||
|
* linux-nat.h (lin_lwp_attach_lwp): Adjust prototype.
|
||||||
|
|
||||||
2008-01-23 Nick Roberts <nickrob@snap.net.nz>
|
2008-01-23 Nick Roberts <nickrob@snap.net.nz>
|
||||||
|
|
||||||
* mi/mi-cmd-var.c (mi_cmd_var_set_format): Add value field to output.
|
* mi/mi-cmd-var.c (mi_cmd_var_set_format): Add value field to output.
|
||||||
|
|
|
@ -366,7 +366,7 @@ bsd_uthread_wait (ptid_t ptid, struct target_waitstatus *status)
|
||||||
if (ptid_get_tid (ptid) != 0 && !in_thread_list (ptid)
|
if (ptid_get_tid (ptid) != 0 && !in_thread_list (ptid)
|
||||||
&& ptid_get_tid (inferior_ptid) == 0)
|
&& ptid_get_tid (inferior_ptid) == 0)
|
||||||
{
|
{
|
||||||
add_thread (ptid);
|
add_thread_silent (ptid);
|
||||||
inferior_ptid = ptid;
|
inferior_ptid = ptid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
2008-01-23 Chris Demetriou <cgd@google.com>
|
||||||
|
|
||||||
|
* gdb.texinfo (Threads): Document new "set print thread-events"
|
||||||
|
and "show print thread-events" commands.
|
||||||
|
|
||||||
2008-01-19 Eli Zaretskii <eliz@gnu.org>
|
2008-01-19 Eli Zaretskii <eliz@gnu.org>
|
||||||
|
|
||||||
* gdb.texinfo (Specify Location): New section.
|
* gdb.texinfo (Specify Location): New section.
|
||||||
|
|
|
@ -2238,6 +2238,8 @@ programs:
|
||||||
@item @samp{thread apply [@var{threadno}] [@var{all}] @var{args}},
|
@item @samp{thread apply [@var{threadno}] [@var{all}] @var{args}},
|
||||||
a command to apply a command to a list of threads
|
a command to apply a command to a list of threads
|
||||||
@item thread-specific breakpoints
|
@item thread-specific breakpoints
|
||||||
|
@item @samp{set print thread-events}, which controls printing of
|
||||||
|
messages on thread start and exit.
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
@quotation
|
@quotation
|
||||||
|
@ -2431,6 +2433,22 @@ threads that you want affected with the command argument
|
||||||
shown in the first field of the @samp{info threads} display; or it
|
shown in the first field of the @samp{info threads} display; or it
|
||||||
could be a range of thread numbers, as in @code{2-4}. To apply a
|
could be a range of thread numbers, as in @code{2-4}. To apply a
|
||||||
command to all threads, type @kbd{thread apply all @var{command}}.
|
command to all threads, type @kbd{thread apply all @var{command}}.
|
||||||
|
|
||||||
|
@kindex set print thread-events
|
||||||
|
@cindex print messages on thread start and exit
|
||||||
|
@item set print thread-events
|
||||||
|
@itemx set print thread-events on
|
||||||
|
@itemx set print thread-events off
|
||||||
|
The @code{set print thread-events} command allows you to enable or
|
||||||
|
disable printing of messages when @value{GDBN} notices that new threads have
|
||||||
|
started or that threads have exited. By default, these messages will
|
||||||
|
be printed if detection of these events is supported by the target.
|
||||||
|
Note that these messages cannot be disabled on all targets.
|
||||||
|
|
||||||
|
@kindex show print thread-events
|
||||||
|
@item show print thread-events
|
||||||
|
Show whether messages will be printed when @value{GDBN} detects that threads
|
||||||
|
have started and exited.
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
@cindex automatic thread selection
|
@cindex automatic thread selection
|
||||||
|
|
|
@ -69,11 +69,16 @@ struct thread_info
|
||||||
/* Create an empty thread list, or empty the existing one. */
|
/* Create an empty thread list, or empty the existing one. */
|
||||||
extern void init_thread_list (void);
|
extern void init_thread_list (void);
|
||||||
|
|
||||||
/* Add a thread to the thread list.
|
/* Add a thread to the thread list, print a message
|
||||||
Note that add_thread now returns the handle of the new thread,
|
that a new thread is found, and return the pointer to
|
||||||
so that the caller may initialize the private thread data. */
|
the new thread. Caller my use this pointer to
|
||||||
|
initialize the private thread data. */
|
||||||
extern struct thread_info *add_thread (ptid_t ptid);
|
extern struct thread_info *add_thread (ptid_t ptid);
|
||||||
|
|
||||||
|
/* Same as add_thread, but does not print a message
|
||||||
|
about new thread. */
|
||||||
|
extern struct thread_info *add_thread_silent (ptid_t ptid);
|
||||||
|
|
||||||
/* Delete an existing thread list entry. */
|
/* Delete an existing thread list entry. */
|
||||||
extern void delete_thread (ptid_t);
|
extern void delete_thread (ptid_t);
|
||||||
|
|
||||||
|
@ -141,4 +146,8 @@ extern void switch_to_thread (ptid_t ptid);
|
||||||
/* Commands with a prefix of `thread'. */
|
/* Commands with a prefix of `thread'. */
|
||||||
extern struct cmd_list_element *thread_cmd_list;
|
extern struct cmd_list_element *thread_cmd_list;
|
||||||
|
|
||||||
|
/* Print notices on thread events (attach, detach, etc.), set with
|
||||||
|
`set print thread-events'. */
|
||||||
|
extern int print_thread_events;
|
||||||
|
|
||||||
#endif /* GDBTHREAD_H */
|
#endif /* GDBTHREAD_H */
|
||||||
|
|
|
@ -962,7 +962,6 @@ inf_ttrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
|
||||||
sizeof (struct inf_ttrace_private_thread_info));
|
sizeof (struct inf_ttrace_private_thread_info));
|
||||||
inf_ttrace_num_lwps++;
|
inf_ttrace_num_lwps++;
|
||||||
}
|
}
|
||||||
printf_filtered (_("[New %s]\n"), target_pid_to_str (ptid));
|
|
||||||
ti = add_thread (ptid);
|
ti = add_thread (ptid);
|
||||||
ti->private =
|
ti->private =
|
||||||
xmalloc (sizeof (struct inf_ttrace_private_thread_info));
|
xmalloc (sizeof (struct inf_ttrace_private_thread_info));
|
||||||
|
|
|
@ -1331,14 +1331,8 @@ handle_inferior_event (struct execution_control_state *ecs)
|
||||||
|
|
||||||
if (ecs->ws.kind != TARGET_WAITKIND_EXITED
|
if (ecs->ws.kind != TARGET_WAITKIND_EXITED
|
||||||
&& ecs->ws.kind != TARGET_WAITKIND_SIGNALLED && ecs->new_thread_event)
|
&& ecs->ws.kind != TARGET_WAITKIND_SIGNALLED && ecs->new_thread_event)
|
||||||
{
|
|
||||||
add_thread (ecs->ptid);
|
add_thread (ecs->ptid);
|
||||||
|
|
||||||
ui_out_text (uiout, "[New ");
|
|
||||||
ui_out_text (uiout, target_pid_to_str (ecs->ptid));
|
|
||||||
ui_out_text (uiout, "]\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (ecs->ws.kind)
|
switch (ecs->ws.kind)
|
||||||
{
|
{
|
||||||
case TARGET_WAITKIND_LOADED:
|
case TARGET_WAITKIND_LOADED:
|
||||||
|
|
|
@ -871,7 +871,7 @@ exit_lwp (struct lwp_info *lp)
|
||||||
be attached. */
|
be attached. */
|
||||||
|
|
||||||
int
|
int
|
||||||
lin_lwp_attach_lwp (ptid_t ptid, int verbose)
|
lin_lwp_attach_lwp (ptid_t ptid)
|
||||||
{
|
{
|
||||||
struct lwp_info *lp;
|
struct lwp_info *lp;
|
||||||
|
|
||||||
|
@ -956,9 +956,6 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose)
|
||||||
lp->stopped = 1;
|
lp->stopped = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose)
|
|
||||||
printf_filtered (_("[New %s]\n"), target_pid_to_str (ptid));
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2090,8 +2087,6 @@ retry:
|
||||||
}
|
}
|
||||||
|
|
||||||
add_thread (lp->ptid);
|
add_thread (lp->ptid);
|
||||||
printf_unfiltered (_("[New %s]\n"),
|
|
||||||
target_pid_to_str (lp->ptid));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Save the trap's siginfo in case we need it later. */
|
/* Save the trap's siginfo in case we need it later. */
|
||||||
|
|
|
@ -95,7 +95,7 @@ void linux_proc_pending_signals (int pid, sigset_t *pending, sigset_t *blocked,
|
||||||
/* linux-nat functions for handling fork events. */
|
/* linux-nat functions for handling fork events. */
|
||||||
extern void linux_enable_event_reporting (ptid_t ptid);
|
extern void linux_enable_event_reporting (ptid_t ptid);
|
||||||
|
|
||||||
extern int lin_lwp_attach_lwp (ptid_t ptid, int verbose);
|
extern int lin_lwp_attach_lwp (ptid_t ptid);
|
||||||
|
|
||||||
/* Iterator function for lin-lwp's lwp list. */
|
/* Iterator function for lin-lwp's lwp list. */
|
||||||
struct lwp_info *iterate_over_lwps (int (*callback) (struct lwp_info *,
|
struct lwp_info *iterate_over_lwps (int (*callback) (struct lwp_info *,
|
||||||
|
|
|
@ -118,7 +118,7 @@ static CORE_ADDR td_death_bp_addr;
|
||||||
/* Prototypes for local functions. */
|
/* Prototypes for local functions. */
|
||||||
static void thread_db_find_new_threads (void);
|
static void thread_db_find_new_threads (void);
|
||||||
static void attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
|
static void attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
|
||||||
const td_thrinfo_t *ti_p, int verbose);
|
const td_thrinfo_t *ti_p);
|
||||||
static void detach_thread (ptid_t ptid, int verbose);
|
static void detach_thread (ptid_t ptid, int verbose);
|
||||||
|
|
||||||
|
|
||||||
|
@ -279,7 +279,7 @@ thread_get_info_callback (const td_thrhandle_t *thp, void *infop)
|
||||||
if (thread_info == NULL)
|
if (thread_info == NULL)
|
||||||
{
|
{
|
||||||
/* New thread. Attach to it now (why wait?). */
|
/* New thread. Attach to it now (why wait?). */
|
||||||
attach_thread (thread_ptid, thp, &ti, 1);
|
attach_thread (thread_ptid, thp, &ti);
|
||||||
thread_info = find_thread_pid (thread_ptid);
|
thread_info = find_thread_pid (thread_ptid);
|
||||||
gdb_assert (thread_info != NULL);
|
gdb_assert (thread_info != NULL);
|
||||||
}
|
}
|
||||||
|
@ -670,7 +670,7 @@ thread_db_new_objfile (struct objfile *objfile)
|
||||||
|
|
||||||
static void
|
static void
|
||||||
attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
|
attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
|
||||||
const td_thrinfo_t *ti_p, int verbose)
|
const td_thrinfo_t *ti_p)
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
struct thread_info *tp;
|
||||||
td_err_e err;
|
td_err_e err;
|
||||||
|
@ -702,7 +702,7 @@ attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
|
||||||
return; /* A zombie thread -- do not attach. */
|
return; /* A zombie thread -- do not attach. */
|
||||||
|
|
||||||
/* Under GNU/Linux, we have to attach to each and every thread. */
|
/* Under GNU/Linux, we have to attach to each and every thread. */
|
||||||
if (lin_lwp_attach_lwp (BUILD_LWP (ti_p->ti_lid, GET_PID (ptid)), 0) < 0)
|
if (lin_lwp_attach_lwp (BUILD_LWP (ti_p->ti_lid, GET_PID (ptid))) < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Add the thread to GDB's thread list. */
|
/* Add the thread to GDB's thread list. */
|
||||||
|
@ -710,9 +710,6 @@ attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
|
||||||
tp->private = xmalloc (sizeof (struct private_thread_info));
|
tp->private = xmalloc (sizeof (struct private_thread_info));
|
||||||
memset (tp->private, 0, sizeof (struct private_thread_info));
|
memset (tp->private, 0, sizeof (struct private_thread_info));
|
||||||
|
|
||||||
if (verbose)
|
|
||||||
printf_unfiltered (_("[New %s]\n"), target_pid_to_str (ptid));
|
|
||||||
|
|
||||||
/* Enable thread event reporting for this thread. */
|
/* Enable thread event reporting for this thread. */
|
||||||
err = td_thr_event_enable_p (th_p, 1);
|
err = td_thr_event_enable_p (th_p, 1);
|
||||||
if (err != TD_OK)
|
if (err != TD_OK)
|
||||||
|
@ -843,7 +840,7 @@ check_event (ptid_t ptid)
|
||||||
case TD_CREATE:
|
case TD_CREATE:
|
||||||
/* Call attach_thread whether or not we already know about a
|
/* Call attach_thread whether or not we already know about a
|
||||||
thread with this thread ID. */
|
thread with this thread ID. */
|
||||||
attach_thread (ptid, msg.th_p, &ti, 1);
|
attach_thread (ptid, msg.th_p, &ti);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -852,7 +849,7 @@ check_event (ptid_t ptid)
|
||||||
if (!in_thread_list (ptid))
|
if (!in_thread_list (ptid))
|
||||||
error (_("Spurious thread death event."));
|
error (_("Spurious thread death event."));
|
||||||
|
|
||||||
detach_thread (ptid, 1);
|
detach_thread (ptid, print_thread_events);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -976,7 +973,7 @@ find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!in_thread_list (ptid))
|
if (!in_thread_list (ptid))
|
||||||
attach_thread (ptid, th_p, &ti, 1);
|
attach_thread (ptid, th_p, &ti);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
10
gdb/procfs.c
10
gdb/procfs.c
|
@ -4119,11 +4119,8 @@ wait_again:
|
||||||
temp_ptid = MERGEPID (pi->pid, temp_tid);
|
temp_ptid = MERGEPID (pi->pid, temp_tid);
|
||||||
/* If not in GDB's thread list, add it. */
|
/* If not in GDB's thread list, add it. */
|
||||||
if (!in_thread_list (temp_ptid))
|
if (!in_thread_list (temp_ptid))
|
||||||
{
|
|
||||||
printf_filtered (_("[New %s]\n"),
|
|
||||||
target_pid_to_str (temp_ptid));
|
|
||||||
add_thread (temp_ptid);
|
add_thread (temp_ptid);
|
||||||
}
|
|
||||||
/* Return to WFI, but tell it to immediately resume. */
|
/* Return to WFI, but tell it to immediately resume. */
|
||||||
status->kind = TARGET_WAITKIND_SPURIOUS;
|
status->kind = TARGET_WAITKIND_SPURIOUS;
|
||||||
return inferior_ptid;
|
return inferior_ptid;
|
||||||
|
@ -4189,11 +4186,7 @@ wait_again:
|
||||||
/* If not in GDB's thread list, add it. */
|
/* If not in GDB's thread list, add it. */
|
||||||
temp_ptid = MERGEPID (pi->pid, temp_tid);
|
temp_ptid = MERGEPID (pi->pid, temp_tid);
|
||||||
if (!in_thread_list (temp_ptid))
|
if (!in_thread_list (temp_ptid))
|
||||||
{
|
|
||||||
printf_filtered (_("[New %s]\n"),
|
|
||||||
target_pid_to_str (temp_ptid));
|
|
||||||
add_thread (temp_ptid);
|
add_thread (temp_ptid);
|
||||||
}
|
|
||||||
|
|
||||||
status->kind = TARGET_WAITKIND_STOPPED;
|
status->kind = TARGET_WAITKIND_STOPPED;
|
||||||
status->value.sig = 0;
|
status->value.sig = 0;
|
||||||
|
@ -4280,7 +4273,6 @@ wait_again:
|
||||||
* If we don't create a procinfo, resume may be unhappy
|
* If we don't create a procinfo, resume may be unhappy
|
||||||
* later.
|
* later.
|
||||||
*/
|
*/
|
||||||
printf_filtered (_("[New %s]\n"), target_pid_to_str (retval));
|
|
||||||
add_thread (retval);
|
add_thread (retval);
|
||||||
if (find_procinfo (PIDGET (retval), TIDGET (retval)) == NULL)
|
if (find_procinfo (PIDGET (retval), TIDGET (retval)) == NULL)
|
||||||
create_procinfo (PIDGET (retval), TIDGET (retval));
|
create_procinfo (PIDGET (retval), TIDGET (retval));
|
||||||
|
|
|
@ -1049,12 +1049,7 @@ record_currthread (int currthread)
|
||||||
/* If this is a new thread, add it to GDB's thread list.
|
/* If this is a new thread, add it to GDB's thread list.
|
||||||
If we leave it up to WFI to do this, bad things will happen. */
|
If we leave it up to WFI to do this, bad things will happen. */
|
||||||
if (!in_thread_list (pid_to_ptid (currthread)))
|
if (!in_thread_list (pid_to_ptid (currthread)))
|
||||||
{
|
|
||||||
add_thread (pid_to_ptid (currthread));
|
add_thread (pid_to_ptid (currthread));
|
||||||
ui_out_text (uiout, "[New ");
|
|
||||||
ui_out_text (uiout, target_pid_to_str (pid_to_ptid (currthread)));
|
|
||||||
ui_out_text (uiout, "]\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *last_pass_packet;
|
static char *last_pass_packet;
|
||||||
|
|
|
@ -461,11 +461,8 @@ sol_thread_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
|
||||||
if (is_thread (rtnval)
|
if (is_thread (rtnval)
|
||||||
&& !ptid_equal (rtnval, save_ptid)
|
&& !ptid_equal (rtnval, save_ptid)
|
||||||
&& !in_thread_list (rtnval))
|
&& !in_thread_list (rtnval))
|
||||||
{
|
|
||||||
printf_filtered ("[New %s]\n", target_pid_to_str (rtnval));
|
|
||||||
add_thread (rtnval);
|
add_thread (rtnval);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* During process initialization, we may get here without the thread
|
/* During process initialization, we may get here without the thread
|
||||||
package being initialized, since that can only happen after we've
|
package being initialized, since that can only happen after we've
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
2008-01-23 Chris Demetriou <cgd@google.com>
|
||||||
|
|
||||||
|
* gdb.threads/thread_events.c: New testcase source file.
|
||||||
|
* gdb.threads/thread_events.exp: New testcase expect file.
|
||||||
|
|
||||||
2008-01-23 Nick Roberts <nickrob@snap.net.nz>
|
2008-01-23 Nick Roberts <nickrob@snap.net.nz>
|
||||||
|
|
||||||
* lib/gdb.exp: Add the variable octal.
|
* lib/gdb.exp: Add the variable octal.
|
||||||
|
|
55
gdb/testsuite/gdb.threads/thread_events.c
Normal file
55
gdb/testsuite/gdb.threads/thread_events.c
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/* Copyright (C) 2007 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/>.
|
||||||
|
|
||||||
|
This file was written by Chris Demetriou (cgd@google.com). */
|
||||||
|
|
||||||
|
/* Simple test to trigger thread events (thread start, thread exit). */
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
static void *
|
||||||
|
threadfunc (void *arg)
|
||||||
|
{
|
||||||
|
printf ("in threadfunc\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
after_join_func (void)
|
||||||
|
{
|
||||||
|
printf ("finished\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
pthread_t thread;
|
||||||
|
|
||||||
|
if (pthread_create (&thread, NULL, threadfunc, NULL) != 0)
|
||||||
|
{
|
||||||
|
printf ("pthread_create failed\n");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pthread_join (thread, NULL) != 0)
|
||||||
|
{
|
||||||
|
printf ("pthread_join failed\n");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
after_join_func ();
|
||||||
|
return 0;
|
||||||
|
}
|
155
gdb/testsuite/gdb.threads/thread_events.exp
Normal file
155
gdb/testsuite/gdb.threads/thread_events.exp
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
# Copyright (C) 2007 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/>.
|
||||||
|
|
||||||
|
# Please email any bugs, comments, and/or additions to this file to:
|
||||||
|
# bug-gdb@prep.ai.mit.edu
|
||||||
|
|
||||||
|
# This file was written by Chris Demetriou (cgd@google.com).
|
||||||
|
# It tests printing of thread event (start, exit) information, and
|
||||||
|
# disabling of those messages.
|
||||||
|
#
|
||||||
|
# Note: the format of thread event messages (and also whether or not
|
||||||
|
# messages are printed and can be disabled) is dependent on the target
|
||||||
|
# thread support code.
|
||||||
|
|
||||||
|
# This test has only been verified with Linux targets, and would need
|
||||||
|
# to be generalized to support other targets
|
||||||
|
if ![istarget *-*-linux*] then {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
# When using gdbserver, even on Linux, we don't get notifications
|
||||||
|
# about new threads. This is expected, so don't test for that.
|
||||||
|
if [is_remote target] then {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if $tracelevel then {
|
||||||
|
strace $tracelevel
|
||||||
|
}
|
||||||
|
|
||||||
|
set prms_id 0
|
||||||
|
set bug_id 0
|
||||||
|
|
||||||
|
set testfile "thread_events"
|
||||||
|
set srcfile ${testfile}.c
|
||||||
|
set binfile ${objdir}/${subdir}/${testfile}
|
||||||
|
|
||||||
|
if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug "incdir=${objdir}"]] != "" } {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
proc gdb_test_thread_start {messages_enabled command pattern message} {
|
||||||
|
global gdb_prompt
|
||||||
|
|
||||||
|
if { $messages_enabled } {
|
||||||
|
set events_expected 1
|
||||||
|
} else {
|
||||||
|
set events_expected 0
|
||||||
|
}
|
||||||
|
set events_seen 0
|
||||||
|
|
||||||
|
return [gdb_test_multiple $command $message {
|
||||||
|
-re "\\\[New Thread \[^\]\]*\\\]\r\n" {
|
||||||
|
incr events_seen;
|
||||||
|
exp_continue;
|
||||||
|
}
|
||||||
|
-re "\[\r\n\]*($pattern)\[\r\n\]+$gdb_prompt $" {
|
||||||
|
if { $events_seen != $events_expected } {
|
||||||
|
fail "$message (saw $events_seen, expected $events_expected)"
|
||||||
|
} else {
|
||||||
|
pass "$message"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
proc gdb_test_thread_exit {messages_enabled command pattern message} {
|
||||||
|
global gdb_prompt
|
||||||
|
|
||||||
|
if { $messages_enabled } {
|
||||||
|
set events_expected 1
|
||||||
|
} else {
|
||||||
|
set events_expected 0
|
||||||
|
}
|
||||||
|
set events_seen 0
|
||||||
|
|
||||||
|
return [gdb_test_multiple $command $message {
|
||||||
|
-re "\\\[Thread \[^\]\]* exited\\\]\r\n" {
|
||||||
|
incr events_seen
|
||||||
|
exp_continue;
|
||||||
|
}
|
||||||
|
-re "\[\r\n\]*($pattern)\[\r\n\]+$gdb_prompt $" {
|
||||||
|
if { $events_seen != $events_expected } {
|
||||||
|
fail "$message (saw $events_seen, expected $events_expected)"
|
||||||
|
} else {
|
||||||
|
pass "$message"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
proc test_thread_messages {enabled} {
|
||||||
|
global srcdir subdir binfile srcfile
|
||||||
|
|
||||||
|
if { $enabled } {
|
||||||
|
set enabled_string "with messages enabled"
|
||||||
|
} else {
|
||||||
|
set enabled_string "with messages disabled"
|
||||||
|
}
|
||||||
|
|
||||||
|
gdb_start
|
||||||
|
gdb_reinitialize_dir $srcdir/$subdir
|
||||||
|
gdb_load ${binfile}
|
||||||
|
|
||||||
|
if { $enabled } {
|
||||||
|
gdb_test "set print thread-events on"
|
||||||
|
} else {
|
||||||
|
gdb_test "set print thread-events off"
|
||||||
|
}
|
||||||
|
|
||||||
|
# The initial thread may log a 'New Thread' message, but we don't
|
||||||
|
# check for it.
|
||||||
|
if ![runto_main] then {
|
||||||
|
fail "Can't run to main $enabled_string"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
gdb_test "break threadfunc" \
|
||||||
|
"Breakpoint.*at.* file .*$srcfile, line.*" \
|
||||||
|
"breakpoint at threadfunc $enabled_string"
|
||||||
|
gdb_test "break after_join_func" \
|
||||||
|
"Breakpoint.*at.* file .*$srcfile, line.*" \
|
||||||
|
"breakpoint at after_join_func $enabled_string"
|
||||||
|
|
||||||
|
# continue to threadfunc breakpoint. A thread will start.
|
||||||
|
# Expect to see a thread start message, if messages are enabled.
|
||||||
|
gdb_test_thread_start $enabled "continue" \
|
||||||
|
".*Breakpoint .*,.*threadfunc.*at.*$srcfile:.*" \
|
||||||
|
"continue to threadfunc $enabled_string"
|
||||||
|
|
||||||
|
# continue to after_join_func breakpoint. A thread will exit.
|
||||||
|
# Expect to see a thread exit message, if messages are enabled.
|
||||||
|
gdb_test_thread_exit $enabled "continue" \
|
||||||
|
".*Breakpoint .*,.*after_join_func.*at.*$srcfile:.*" \
|
||||||
|
"continue to after_join_func $enabled_string"
|
||||||
|
|
||||||
|
delete_breakpoints
|
||||||
|
|
||||||
|
gdb_exit
|
||||||
|
}
|
||||||
|
|
||||||
|
test_thread_messages 0
|
||||||
|
test_thread_messages 1
|
35
gdb/thread.c
35
gdb/thread.c
|
@ -116,11 +116,8 @@ init_thread_list (void)
|
||||||
thread_list = NULL;
|
thread_list = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add_thread now returns a pointer to the new thread_info,
|
|
||||||
so that back_ends can initialize their private data. */
|
|
||||||
|
|
||||||
struct thread_info *
|
struct thread_info *
|
||||||
add_thread (ptid_t ptid)
|
add_thread_silent (ptid_t ptid)
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
struct thread_info *tp;
|
||||||
|
|
||||||
|
@ -133,6 +130,17 @@ add_thread (ptid_t ptid)
|
||||||
return tp;
|
return tp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct thread_info *
|
||||||
|
add_thread (ptid_t ptid)
|
||||||
|
{
|
||||||
|
struct thread_info *result = add_thread_silent (ptid);
|
||||||
|
|
||||||
|
if (print_thread_events)
|
||||||
|
printf_filtered (_("[New %s]\n"), target_pid_to_str (ptid));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
delete_thread (ptid_t ptid)
|
delete_thread (ptid_t ptid)
|
||||||
{
|
{
|
||||||
|
@ -675,6 +683,17 @@ thread_command (char *tidstr, int from_tty)
|
||||||
gdb_thread_select (uiout, tidstr, NULL);
|
gdb_thread_select (uiout, tidstr, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Print notices when new threads are attached and detached. */
|
||||||
|
int print_thread_events = 1;
|
||||||
|
static void
|
||||||
|
show_print_thread_events (struct ui_file *file, int from_tty,
|
||||||
|
struct cmd_list_element *c, const char *value)
|
||||||
|
{
|
||||||
|
fprintf_filtered (file, _("\
|
||||||
|
Printing of thread events is %s.\n"),
|
||||||
|
value);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
do_captured_thread_select (struct ui_out *uiout, void *tidstr)
|
do_captured_thread_select (struct ui_out *uiout, void *tidstr)
|
||||||
{
|
{
|
||||||
|
@ -737,4 +756,12 @@ The new thread ID must be currently known."),
|
||||||
|
|
||||||
if (!xdb_commands)
|
if (!xdb_commands)
|
||||||
add_com_alias ("t", "thread", class_run, 1);
|
add_com_alias ("t", "thread", class_run, 1);
|
||||||
|
|
||||||
|
add_setshow_boolean_cmd ("thread-events", no_class,
|
||||||
|
&print_thread_events, _("\
|
||||||
|
Set printing of thread events (e.g., thread start and exit)."), _("\
|
||||||
|
Show printing of thread events (e.g., thread start and exit)."), NULL,
|
||||||
|
NULL,
|
||||||
|
show_print_thread_events,
|
||||||
|
&setprintlist, &showprintlist);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1311,10 +1311,6 @@ get_win32_debug_event (int pid, struct target_waitstatus *ourstatus)
|
||||||
/* Record the existence of this thread */
|
/* Record the existence of this thread */
|
||||||
th = win32_add_thread (current_event.dwThreadId,
|
th = win32_add_thread (current_event.dwThreadId,
|
||||||
current_event.u.CreateThread.hThread);
|
current_event.u.CreateThread.hThread);
|
||||||
if (info_verbose)
|
|
||||||
printf_unfiltered ("[New %s]\n",
|
|
||||||
target_pid_to_str (
|
|
||||||
pid_to_ptid (current_event.dwThreadId)));
|
|
||||||
retval = current_event.dwThreadId;
|
retval = current_event.dwThreadId;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -1311,10 +1311,6 @@ get_win32_debug_event (int pid, struct target_waitstatus *ourstatus)
|
||||||
/* Record the existence of this thread */
|
/* Record the existence of this thread */
|
||||||
th = win32_add_thread (current_event.dwThreadId,
|
th = win32_add_thread (current_event.dwThreadId,
|
||||||
current_event.u.CreateThread.hThread);
|
current_event.u.CreateThread.hThread);
|
||||||
if (info_verbose)
|
|
||||||
printf_unfiltered ("[New %s]\n",
|
|
||||||
target_pid_to_str (
|
|
||||||
pid_to_ptid (current_event.dwThreadId)));
|
|
||||||
retval = current_event.dwThreadId;
|
retval = current_event.dwThreadId;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue