mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-03 04:12:10 +08:00
e8032dde10
When GDB wants to sync the thread list with the target's (e.g., due to "info threads"), it calls update_thread_list: update_thread_list (void) { prune_threads (); target_find_new_threads (); update_threads_executing (); } And then prune_threads does: prune_threads (void) { struct thread_info *tp, *next; for (tp = thread_list; tp; tp = next) { next = tp->next; if (!thread_alive (tp)) delete_thread (tp->ptid); } } Calling thread_live on each thread one by one is expensive. E.g., on Linux, it ends up doing kill(SIG0) once for each thread. Not a big deal, but still a bunch of syscalls... With the remote target, it's cumbersome. That thread_alive call ends up generating one T packet per thread: Sending packet: $Tp2141.2150#82...Packet received: OK Sending packet: $Tp2141.214f#b7...Packet received: OK Sending packet: $Tp2141.2141#82...Packet received: OK Sending packet: $qXfer:threads:read::0,fff#03...Packet received: l<threads>\n<thread id="p2141.2141" core="2"/>\n<thread id="p2141.214f" core="1"/>\n<thread id="p2141.2150" core="2"/>\n</threads>\n That seems a bit silly when target_find_new_threads method implementations will always fetch the whole current set of target threads, and then add those that are not in GDB's thread list, to GDB's thread list. This patch thus pushes down the responsibility of pruning dead threads to the target_find_new_threads method instead, so a target may implement pruning dead threads however it wants. Once we do that, target_find_new_threads becomes a misnomer, so the patch renames it to target_update_thread_list. The patch doesn't attempt to do any optimization to any target yet. It simply exports prune_threads, and makes all implementations of target_update_thread_list call that. It's meant to be a no-op. gdb/ 2014-10-15 Pedro Alves <palves@redhat.com> * ada-tasks.c (print_ada_task_info, task_command_1): Adjust. * bsd-uthread.c (bsd_uthread_find_new_threads): Rename to ... (bsd_uthread_update_thread_list): ... this. Call prune_threads. (bsd_uthread_target): Adjust. * corelow.c (core_open): Adjust. * dec-thread.c (dec_thread_find_new_threads): Update comment. (dec_thread_update_thread_list): New function. (init_dec_thread_ops): Adjust. * gdbthread.h (prune_threads): New declaration. * linux-thread-db.c (thread_db_find_new_threads): Rename to ... (thread_db_update_thread_list): ... this. Call prune_threads. (init_thread_db_ops): Adjust. * nto-procfs.c (procfs_find_new_threads): Rename to ... (procfs_update_thread_list): ... this. Call prune_threads. (procfs_attach, procfs_create_inferior, init_procfs_targets): Adjust. * obsd-nat.c (obsd_find_new_threads): Rename to ... (obsd_update_thread_list): ... this. Call prune_threads. (obsd_add_target): Adjust. * procfs.c (procfs_target): Adjust. (procfs_notice_thread): Update comment. (procfs_find_new_threads): Rename to ... (procfs_update_thread_list): ... this. Call prune_threads. * ravenscar-thread.c (ravenscar_update_inferior_ptid): Update comment. (ravenscar_wait): Adjust. (ravenscar_find_new_threads): Rename to ... (ravenscar_update_thread_list): ... this. Call prune_threads. (init_ravenscar_thread_ops): Adjust. * record-btrace.c (record_btrace_find_new_threads): Rename to ... (record_btrace_update_thread_list): ... this. Adjust comment. (init_record_btrace_ops): Adjust. * remote.c (remote_threads_info): Rename to ... (remote_update_thread_list): ... this. Call prune_threads. (remote_start_remote, extended_remote_attach_1, init_remote_ops): Adjust. * sol-thread.c (check_for_thread_db): Adjust. (sol_find_new_threads_callback): Rename to ... (sol_update_thread_list_callback): ... this. (sol_find_new_threads): Rename to ... (sol_update_thread_list): ... this. Call prune_threads. Adjust. (sol_get_ada_task_ptid, init_sol_thread_ops): Adjust. * target-delegates.c: Regenerate. * target.c (target_find_new_threads): Rename to ... (target_update_thread_list): ... this. * target.h (struct target_ops): Rename to_find_new_threads field to to_update_thread_list. (target_find_new_threads): Rename to ... (target_update_thread_list): ... this. * thread.c (prune_threads): Make extern. (update_thread_list): Adjust.
187 lines
4.4 KiB
C
187 lines
4.4 KiB
C
/* Native-dependent code for OpenBSD.
|
|
|
|
Copyright (C) 2012-2014 Free Software Foundation, Inc.
|
|
|
|
This file is part of GDB.
|
|
|
|
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 "defs.h"
|
|
#include "gdbthread.h"
|
|
#include "inferior.h"
|
|
#include "target.h"
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/ptrace.h>
|
|
#include "gdb_wait.h"
|
|
|
|
#include "inf-child.h"
|
|
#include "obsd-nat.h"
|
|
|
|
/* OpenBSD 5.2 and later include rthreads which uses a thread model
|
|
that maps userland threads directly onto kernel threads in a 1:1
|
|
fashion. */
|
|
|
|
#ifdef PT_GET_THREAD_FIRST
|
|
|
|
static char *
|
|
obsd_pid_to_str (struct target_ops *ops, ptid_t ptid)
|
|
{
|
|
if (ptid_get_lwp (ptid) != 0)
|
|
{
|
|
static char buf[64];
|
|
|
|
xsnprintf (buf, sizeof buf, "thread %ld", ptid_get_lwp (ptid));
|
|
return buf;
|
|
}
|
|
|
|
return normal_pid_to_str (ptid);
|
|
}
|
|
|
|
static void
|
|
obsd_update_thread_list (struct target_ops *ops)
|
|
{
|
|
pid_t pid = ptid_get_pid (inferior_ptid);
|
|
struct ptrace_thread_state pts;
|
|
|
|
prune_threads ();
|
|
|
|
if (ptrace (PT_GET_THREAD_FIRST, pid, (caddr_t)&pts, sizeof pts) == -1)
|
|
perror_with_name (("ptrace"));
|
|
|
|
while (pts.pts_tid != -1)
|
|
{
|
|
ptid_t ptid = ptid_build (pid, pts.pts_tid, 0);
|
|
|
|
if (!in_thread_list (ptid))
|
|
{
|
|
if (ptid_get_lwp (inferior_ptid) == 0)
|
|
thread_change_ptid (inferior_ptid, ptid);
|
|
else
|
|
add_thread (ptid);
|
|
}
|
|
|
|
if (ptrace (PT_GET_THREAD_NEXT, pid, (caddr_t)&pts, sizeof pts) == -1)
|
|
perror_with_name (("ptrace"));
|
|
}
|
|
}
|
|
|
|
static ptid_t
|
|
obsd_wait (struct target_ops *ops,
|
|
ptid_t ptid, struct target_waitstatus *ourstatus, int options)
|
|
{
|
|
pid_t pid;
|
|
int status, save_errno;
|
|
|
|
do
|
|
{
|
|
set_sigint_trap ();
|
|
|
|
do
|
|
{
|
|
pid = waitpid (ptid_get_pid (ptid), &status, 0);
|
|
save_errno = errno;
|
|
}
|
|
while (pid == -1 && errno == EINTR);
|
|
|
|
clear_sigint_trap ();
|
|
|
|
if (pid == -1)
|
|
{
|
|
fprintf_unfiltered (gdb_stderr,
|
|
_("Child process unexpectedly missing: %s.\n"),
|
|
safe_strerror (save_errno));
|
|
|
|
/* Claim it exited with unknown signal. */
|
|
ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
|
|
ourstatus->value.sig = GDB_SIGNAL_UNKNOWN;
|
|
return inferior_ptid;
|
|
}
|
|
|
|
/* Ignore terminated detached child processes. */
|
|
if (!WIFSTOPPED (status) && pid != ptid_get_pid (inferior_ptid))
|
|
pid = -1;
|
|
}
|
|
while (pid == -1);
|
|
|
|
ptid = pid_to_ptid (pid);
|
|
|
|
if (WIFSTOPPED (status))
|
|
{
|
|
ptrace_state_t pe;
|
|
pid_t fpid;
|
|
|
|
if (ptrace (PT_GET_PROCESS_STATE, pid, (caddr_t)&pe, sizeof pe) == -1)
|
|
perror_with_name (("ptrace"));
|
|
|
|
switch (pe.pe_report_event)
|
|
{
|
|
case PTRACE_FORK:
|
|
ourstatus->kind = TARGET_WAITKIND_FORKED;
|
|
ourstatus->value.related_pid = pid_to_ptid (pe.pe_other_pid);
|
|
|
|
/* Make sure the other end of the fork is stopped too. */
|
|
fpid = waitpid (pe.pe_other_pid, &status, 0);
|
|
if (fpid == -1)
|
|
perror_with_name (("waitpid"));
|
|
|
|
if (ptrace (PT_GET_PROCESS_STATE, fpid,
|
|
(caddr_t)&pe, sizeof pe) == -1)
|
|
perror_with_name (("ptrace"));
|
|
|
|
gdb_assert (pe.pe_report_event == PTRACE_FORK);
|
|
gdb_assert (pe.pe_other_pid == pid);
|
|
if (fpid == ptid_get_pid (inferior_ptid))
|
|
{
|
|
ourstatus->value.related_pid = pid_to_ptid (pe.pe_other_pid);
|
|
return pid_to_ptid (fpid);
|
|
}
|
|
|
|
return pid_to_ptid (pid);
|
|
}
|
|
|
|
ptid = ptid_build (pid, pe.pe_tid, 0);
|
|
if (!in_thread_list (ptid))
|
|
{
|
|
if (ptid_get_lwp (inferior_ptid) == 0)
|
|
thread_change_ptid (inferior_ptid, ptid);
|
|
else
|
|
add_thread (ptid);
|
|
}
|
|
}
|
|
|
|
store_waitstatus (ourstatus, status);
|
|
return ptid;
|
|
}
|
|
|
|
void
|
|
obsd_add_target (struct target_ops *t)
|
|
{
|
|
/* Override some methods to support threads. */
|
|
t->to_pid_to_str = obsd_pid_to_str;
|
|
t->to_update_thread_list = obsd_update_thread_list;
|
|
t->to_wait = obsd_wait;
|
|
add_target (t);
|
|
}
|
|
|
|
#else
|
|
|
|
void
|
|
obsd_add_target (struct target_ops *t)
|
|
{
|
|
add_target (t);
|
|
}
|
|
|
|
#endif /* PT_GET_THREAD_FIRST */
|