#include "common/vec.h"
#include "target/waitstatus.h"
#include "cli/cli-utils.h"
+#include "common/refcounted-object.h"
+#include "common-gdbthread.h"
/* Frontend view of the thread state. Possible extensions: stepping,
finishing, until(ling),... */
DEF_VEC_P (value_ptr);
typedef VEC (value_ptr) value_vec;
-struct thread_info
+/* Threads are intrusively refcounted objects. Being the
+ user-selected thread is normally considered an implicit strong
+ reference and is thus not accounted in the refcount, unlike
+ inferior objects. This is necessary, because there's no "current
+ thread" pointer. Instead the current thread is inferred from the
+ inferior_ptid global. However, when GDB needs to remember the
+ selected thread to later restore it, GDB bumps the thread object's
+ refcount, to prevent something deleting the thread object before
+ reverting back (e.g., due to a "kill" command). If the thread
+ meanwhile exits before being re-selected, then the thread object is
+ left listed in the thread list, but marked with state
+ THREAD_EXITED. (See make_cleanup_restore_current_thread and
+ delete_thread). All other thread references are considered weak
+ references. Placing a thread in the thread list is an implicit
+ strong reference, and is thus not accounted for in the thread's
+ refcount. */
+
+class thread_info : public refcounted_object
{
- struct thread_info *next;
+public:
+ explicit thread_info (inferior *inf, ptid_t ptid);
+ ~thread_info ();
+
+ bool deletable () const
+ {
+ /* If this is the current thread, or there's code out there that
+ relies on it existing (refcount > 0) we can't delete yet. */
+ return (refcount () == 0 && !ptid_equal (ptid, inferior_ptid));
+ }
+
+ struct thread_info *next = NULL;
ptid_t ptid; /* "Actual process id";
In fact, this may be overloaded with
kernel thread id, etc. */
/* The name of the thread, as specified by the user. This is NULL
if the thread does not have a user-given name. */
- char *name;
+ char *name = NULL;
/* Non-zero means the thread is executing. Note: this is different
from saying that there is an active target and we are stopped at
a breakpoint, for instance. This is a real indicator whether the
thread is off and running. */
- int executing;
+ int executing = 0;
/* Non-zero if this thread is resumed from infrun's perspective.
Note that a thread can be marked both as not-executing and
thread really run until that wait status has been processed, but
we should not process that wait status if we didn't try to let
the thread run. */
- int resumed;
+ int resumed = 0;
/* Frontend view of the thread state. Note that the THREAD_RUNNING/
THREAD_STOPPED states are different from EXECUTING. When the
thread is stopped internally while handling an internal event,
like a software single-step breakpoint, EXECUTING will be false,
but STATE will still be THREAD_RUNNING. */
- enum thread_state state;
-
- /* If this is > 0, then it means there's code out there that relies
- on this thread being listed. Don't delete it from the lists even
- if we detect it exiting. */
- int refcount;
+ enum thread_state state = THREAD_STOPPED;
/* State of GDB control of inferior thread execution.
See `struct thread_control_state'. */
- struct thread_control_state control;
+ thread_control_state control {};
/* State of inferior thread to restore after GDB is done with an inferior
call. See `struct thread_suspend_state'. */
- struct thread_suspend_state suspend;
+ thread_suspend_state suspend {};
- int current_line;
- struct symtab *current_symtab;
+ int current_line = 0;
+ struct symtab *current_symtab = NULL;
/* Internal stepping state. */
by proceed and keep_going, and among other things, it's used in
adjust_pc_after_break to distinguish a hardware single-step
SIGTRAP from a breakpoint SIGTRAP. */
- CORE_ADDR prev_pc;
+ CORE_ADDR prev_pc = 0;
/* Did we set the thread stepping a breakpoint instruction? This is
used in conjunction with PREV_PC to decide whether to adjust the
PC. */
- int stepped_breakpoint;
+ int stepped_breakpoint = 0;
/* Should we step over breakpoint next time keep_going is called? */
- int stepping_over_breakpoint;
+ int stepping_over_breakpoint = 0;
/* Should we step over a watchpoint next time keep_going is called?
This is needed on targets with non-continuable, non-steppable
watchpoints. */
- int stepping_over_watchpoint;
+ int stepping_over_watchpoint = 0;
/* Set to TRUE if we should finish single-stepping over a breakpoint
after hitting the current step-resume breakpoint. The context here
step_after_step_resume_breakpoint is set to TRUE at this moment in
order to keep GDB in mind that there is still a breakpoint to step over
when GDB gets back SIGTRAP from step_resume_breakpoint. */
- int step_after_step_resume_breakpoint;
+ int step_after_step_resume_breakpoint = 0;
/* Pointer to the state machine manager object that handles what is
left to do for the thread's execution command after the target
stops. Several execution commands use it. */
- struct thread_fsm *thread_fsm;
+ struct thread_fsm *thread_fsm = NULL;
/* This is used to remember when a fork or vfork event was caught by
a catchpoint, and thus the event is to be followed at the next
struct target_waitstatus pending_follow;
/* True if this thread has been explicitly requested to stop. */
- int stop_requested;
+ int stop_requested = 0;
/* The initiating frame of a nexting operation, used for deciding
which exceptions to intercept. If it is null_frame_id no
bp_longjmp or bp_exception but longjmp has been caught just for
bp_longjmp_call_dummy. */
- struct frame_id initiating_frame;
+ struct frame_id initiating_frame = null_frame_id;
/* Private data used by the target vector implementation. */
- struct private_thread_info *priv;
+ struct private_thread_info *priv = NULL;
/* Function that is called to free PRIVATE. If this is NULL, then
xfree will be called on PRIVATE. */
- void (*private_dtor) (struct private_thread_info *);
+ void (*private_dtor) (struct private_thread_info *) = NULL;
/* Branch trace information for this thread. */
- struct btrace_thread_info btrace;
+ struct btrace_thread_info btrace {};
/* Flag which indicates that the stack temporaries should be stored while
evaluating expressions. */
- int stack_temporaries_enabled;
+ int stack_temporaries_enabled = 0;
/* Values that are stored as temporaries on stack while evaluating
expressions. */
- value_vec *stack_temporaries;
+ value_vec *stack_temporaries = NULL;
/* Step-over chain. A thread is in the step-over queue if these are
non-NULL. If only a single thread is in the chain, then these
fields point to self. */
- struct thread_info *step_over_prev;
- struct thread_info *step_over_next;
+ struct thread_info *step_over_prev = NULL;
+ struct thread_info *step_over_next = NULL;
};
/* Create an empty thread list, or empty the existing one. */
/* Check whether the thread has software single stepping breakpoints
set at PC. */
extern int thread_has_single_step_breakpoint_here (struct thread_info *tp,
- struct address_space *aspace,
+ const address_space *aspace,
CORE_ADDR addr);
/* Translate the global integer thread id (GDB's homegrown id, not the
/* Find thread by GDB global thread ID. */
struct thread_info *find_thread_global_id (int global_id);
+/* Find thread by thread library specific handle in inferior INF. */
+struct thread_info *find_thread_by_handle (struct value *thread_handle,
+ struct inferior *inf);
+
/* Finds the first thread of the inferior given by PID. If PID is -1,
returns the first thread in the list. */
struct thread_info *first_thread_of_process (int pid);
extern int thread_count (void);
-/* Switch from one thread to another. Also sets the STOP_PC
- global. */
-extern void switch_to_thread (ptid_t ptid);
-
/* Switch from one thread to another. Does not read registers and
sets STOP_PC to -1. */
extern void switch_to_thread_no_regs (struct thread_info *thread);
/* Commands with a prefix of `thread'. */
extern struct cmd_list_element *thread_cmd_list;
-extern void thread_command (char *tidstr, int from_tty);
+extern void thread_command (const char *tidstr, int from_tty);
/* Print notices on thread events (attach, detach, etc.), set with
`set print thread-events'. */
extern void print_thread_info (struct ui_out *uiout, char *requested_threads,
int pid);
-extern struct cleanup *make_cleanup_restore_current_thread (void);
+/* Save/restore current inferior/thread/frame. */
+
+class scoped_restore_current_thread
+{
+public:
+ scoped_restore_current_thread ();
+ ~scoped_restore_current_thread ();
+
+ DISABLE_COPY_AND_ASSIGN (scoped_restore_current_thread);
+
+private:
+ thread_info *m_thread;
+ inferior *m_inf;
+ frame_id m_selected_frame_id;
+ int m_selected_frame_level;
+ bool m_was_stopped;
+};
/* Returns a pointer into the thread_info corresponding to
INFERIOR_PTID. INFERIOR_PTID *must* be in the thread list. */
extern void print_selected_thread_frame (struct ui_out *uiout,
user_selected_what selection);
+/* Helper for the CLI's "thread" command and for MI's -thread-select.
+ Selects thread THR. TIDSTR is the original string the thread ID
+ was parsed from. This is used in the error message if THR is not
+ alive anymore. */
+extern void thread_select (const char *tidstr, thread_info *thr);
+
extern struct thread_info *thread_list;
#endif /* GDBTHREAD_H */