From: Pedro Alves Date: Wed, 19 Feb 2025 14:37:39 +0000 (+0000) Subject: thread_info::executing+resumed -> thread_info::internal_state X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3a0b79bae0bfc6755b80ff31bb5bd5b4fbf6df06;p=thirdparty%2Fbinutils-gdb.git thread_info::executing+resumed -> thread_info::internal_state While working on Windows non-stop support, I ran into a very-hard-to-track-down bug. The problem turned out to be that infrun.c:proceed_resume_thread_checked resumed an already-executing thread because the thread was marked as "executing=true, resumed=false", and that function only skips resuming threads that are marked resumed=true. The consequence was that GDB corrupted the registers of the Windows DLL loader threads, eventually leading to a GDB+inferior deadlock. Originally, the "resumed" flag was only ever set when infrun decided is was ready to process a thread's pending wait status. infrun has since evolved to set the resumed flag when we set a thread's executing flag too. We are not always consistent throughout in guaranteeing that a thread is marked resumed=true whenever it is marked executing=true, though. For instance, no target code that supports non-stop mode (linux-nat, remote, and windows-nat with this series) is making sure that new threads are marked resumed=true when they are added to the thread list. They are only marked as {state=running, executing=true}, the "resumed" flag is not touched. Making proceed_resume_thread_checked check thr->executing() in addition to thr->resumed(), feels like papering over a combination of states that shouldn't happen nowadays. OTOH, having to have the target backends mark new threads as resumed=true just feels like too many different states (three) to set: add_thread (...); set_running (...); set_executing (...); set_resumed (...); Yuck. I think we can do better. We really have too many "state tracking" flags in a thread. Basically: - whether a thread is "running/stopped/exited" (from the user's perspective). This is the thread_info::state field. - whether a thread is "executing" (infrun asked the target to set the thread executing). This is thread_info::executing(). - whether a thread is "resumed" (infrun wants the thread to be resumed, but maybe can't yet because the thread has a pending wait status). This is thread_info::resumed() "running", "executing", and "resumed" are almost synonyms, so this can be highly confusing English-wise too. For "running" vs "executing", in comments, we tipically need to explain that "running/stopped/exited" is for the user/frontend perspective, while "executing true/false" is for gdb's internal run control. (Also, "executing or not" can also mean something else in GDB's codebase -- "target has execution" does not mean that threads are actually running right now -- it's a test for whether we have a live process vs a core dump!) One simplification we can do that avoids this running vs executing ambiguity is to replace the "executing" field with an "internal_state" field, similar to the thread_info::state field, and make that new internal_state field reuse the same enum thread_state type that is used by thread_info::state. Like: struct thread_info { ... /* Frontend/public/external/user view of the thread state. */ enum thread_state m_state = THREAD_STOPPED; /* The thread's internal state. When the thread is stopped internally while handling an internal event, like a software single-step breakpoint, the internal state will be THREAD_STOPPED, but the external state will still be THREAD_RUNNING. */ enum thread_state m_internal_state = THREAD_STOPPED; }; (Assume we'd add state() and internal_state() getters.) With that, every check for thr->executing() is replaced with a 'thr->internal_state() == THREAD_RUNNING' check, and the code is clearer by design. There is no confusion between "running" vs "executing" any more, because they now mean the exact same thing. Instead, we say e.g., 'thread has (user) state "running", and internal state "stopped"'. Or simpler, 'thread is running (from the user's perspective), but internally stopped'. That is after all what we would way in comments today already. That still leaves the 'resumed' flag, though. That's the least obvious one. Turns out we can get rid of it, and make it a new state tracked by thread_info::internal_state. That is, we make internal_state have its own enumeration type (decoupled from thread_info::state's type), and convert the resumed true/false flag to a new enumerator of this new enumeration. Like so: enum thread_int_state { THREAD_INT_STOPPED, THREAD_INT_RUNNING, + THREAD_INT_RESUMED_PENDING_STATUS, THREAD_INT_EXITED, }; That is what this patch does. So in summary, we go from: thread_info::state {THREAD_STOPPED, THREAD_RUNNING, THREAD_EXITED} thread_info::executing {false, true} thread_info::resumed {false, true} to: thread_info::state {THREAD_STOPPED, THREAD_RUNNING, THREAD_EXITED} thread_info::internal_state {THREAD_INT_STOPPED, THREAD_INT_RUNNING, THREAD_INT_RESUMED_PENDING_STATUS, THREAD_INT_EXITED} The patch adds getters/setters for both (user) state and internal_state, and adds assertions around state transitions, ensuring that internal_state doesn't get out of sync with thread::have_pending_wait_status(). It also adds an assertion to clear_proceed_status_thread, making sure that we don't try to proceed a thread that is already running. Turns out that catches attach_command calling init_wait_for_inferior too late, after attaching has already created already-running threads. The code that adds/removes threads from the proc_target's resumed_with_pending_wait_status list is all centralized within thread_info::set_internal_state, when we switch to/from the resumed-pending-status state. With the assertions in place, it should be impossible to end up with a THREAD_INT_RUNNING thread with a pending status. The thread.c:set_running, thread.c:set_executing, thread.c:set_resumed global functions are all gone, replaced with new thread.c:set_state and thread.c:set_internal_state functions. Tested on x86_64-linux-gnu, native and gdbserver. Change-Id: I4f5097d68f4694d44e1ae23fea3e9bce45fb078c --- diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c index 8d54e59f332..8e1908452c5 100644 --- a/gdb/aarch64-tdep.c +++ b/gdb/aarch64-tdep.c @@ -4265,7 +4265,7 @@ aarch64_remove_non_address_bits (struct gdbarch *gdbarch, CORE_ADDR pointer) /* If the thread is running, we will not be able to fetch the mask registers. */ - if (thread != nullptr && thread->state != THREAD_RUNNING) + if (thread != nullptr && thread->state () != THREAD_RUNNING) { /* Otherwise, fetch the register cache and the masks. */ struct regcache *regs diff --git a/gdb/amd-dbgapi-target.c b/gdb/amd-dbgapi-target.c index 819b373da32..b976cb75d06 100644 --- a/gdb/amd-dbgapi-target.c +++ b/gdb/amd-dbgapi-target.c @@ -907,7 +907,7 @@ amd_dbgapi_target::stop (ptid_t ptid) /* Use the threads_safe iterator since stop_one_thread may delete the thread if it has exited. */ for (auto *thread : inf->threads_safe ()) - if (thread->state != THREAD_EXITED && thread->ptid.matches (ptid) + if (thread->state () != THREAD_EXITED && thread->ptid.matches (ptid) && ptid_is_gpu (thread->ptid)) stop_one_thread (thread); } @@ -1130,8 +1130,8 @@ add_gpu_thread (inferior *inf, ptid_t wave_ptid) /* Create new GPU threads silently to avoid spamming the terminal with thousands of "[New Thread ...]" messages. */ thread_info *thread = add_thread_silent (proc_target, wave_ptid); - set_running (proc_target, wave_ptid, true); - set_executing (proc_target, wave_ptid, true); + set_state (proc_target, wave_ptid, THREAD_RUNNING); + set_internal_state (proc_target, wave_ptid, THREAD_INT_RUNNING); return thread; } @@ -1872,7 +1872,7 @@ amd_dbgapi_target::update_thread_list () which does not have a corresponding wave_id represents a wave which is gone at this point and should be deleted. */ for (thread_info *tp : inf->threads_safe ()) - if (ptid_is_gpu (tp->ptid) && tp->state != THREAD_EXITED) + if (ptid_is_gpu (tp->ptid) && tp->state () != THREAD_EXITED) { auto it = threads.find (tp->ptid.tid ()); diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index dab52f1fae7..a86be54e81a 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -624,9 +624,9 @@ breakpoints_should_be_inserted_now (void) return 1; /* Don't remove breakpoints yet if, even though all threads are - stopped, we still have events to process. */ + stopped, some still have pending events to process. */ for (thread_info *tp : all_non_exited_threads ()) - if (tp->resumed () && tp->has_pending_waitstatus ()) + if (tp->internal_state () == THREAD_INT_RESUMED_PENDING_STATUS) return 1; } return 0; @@ -2049,7 +2049,7 @@ watchpoint_in_thread_scope (struct watchpoint *b) return (b->pspace == current_program_space && (b->watchpoint_thread == null_ptid || (inferior_ptid == b->watchpoint_thread - && !inferior_thread ()->executing ()))); + && inferior_thread ()->internal_state () != THREAD_INT_RUNNING))); } /* Set watchpoint B to disp_del_at_next_stop, even including its possible @@ -4990,7 +4990,8 @@ get_bpstat_thread () return NULL; thread_info *tp = inferior_thread (); - if (tp->state == THREAD_EXITED || tp->executing ()) + if (tp->internal_state () == THREAD_INT_EXITED + || tp->internal_state () == THREAD_INT_RUNNING) return NULL; return tp; } diff --git a/gdb/bsd-uthread.c b/gdb/bsd-uthread.c index a493b0c6ae4..6ca7acb03e0 100644 --- a/gdb/bsd-uthread.c +++ b/gdb/bsd-uthread.c @@ -416,7 +416,7 @@ bsd_uthread_target::wait (ptid_t ptid, struct target_waitstatus *status, /* Don't let the core see a ptid without a corresponding thread. */ thread_info *thread = beneath->find_thread (ptid); - if (thread == NULL || thread->state == THREAD_EXITED) + if (thread == NULL || thread->state () == THREAD_EXITED) add_thread (beneath, ptid); return ptid; @@ -467,7 +467,7 @@ bsd_uthread_target::update_thread_list () process_stratum_target *proc_target = as_process_stratum_target (this->beneath ()); thread_info *thread = proc_target->find_thread (ptid); - if (thread == nullptr || thread->state == THREAD_EXITED) + if (thread == nullptr || thread->state () == THREAD_EXITED) { /* If INFERIOR_PTID doesn't have a tid member yet, then ptid is still the initial thread of the process. Notify GDB diff --git a/gdb/fork-child.c b/gdb/fork-child.c index 8abfbda2b78..0913435fb80 100644 --- a/gdb/fork-child.c +++ b/gdb/fork-child.c @@ -130,8 +130,8 @@ gdb_startup_inferior (pid_t pid, int num_traps) ptid_t ptid = startup_inferior (proc_target, pid, num_traps, NULL, NULL); - /* Mark all threads non-executing. */ - set_executing (proc_target, ptid, false); + /* Mark all threads internally stopped. */ + set_internal_state (proc_target, ptid, THREAD_INT_STOPPED); return ptid; } diff --git a/gdb/frame.c b/gdb/frame.c index fe5336f2401..59e72ec37d8 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -1873,11 +1873,11 @@ has_stack_frames () thread_info *tp = inferior_thread (); /* Don't try to read from a dead thread. */ - if (tp->state == THREAD_EXITED) + if (tp->internal_state () == THREAD_INT_EXITED) return false; /* ... or from a spinning thread. */ - if (tp->executing ()) + if (tp->internal_state () == THREAD_INT_RUNNING) return false; } diff --git a/gdb/gcore.c b/gdb/gcore.c index fa15d06796b..b9ed7991efb 100644 --- a/gdb/gcore.c +++ b/gdb/gcore.c @@ -846,7 +846,7 @@ thread_info * gcore_find_signalled_thread () { thread_info *curr_thr = inferior_thread (); - if (curr_thr->state != THREAD_EXITED + if (curr_thr->state () != THREAD_EXITED && curr_thr->stop_signal () != GDB_SIGNAL_0) return curr_thr; @@ -855,7 +855,7 @@ gcore_find_signalled_thread () return thr; /* Default to the current thread, unless it has exited. */ - if (curr_thr->state != THREAD_EXITED) + if (curr_thr->state () != THREAD_EXITED) return curr_thr; return nullptr; diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h index a8fd967c702..344c808e9cb 100644 --- a/gdb/gdbthread.h +++ b/gdb/gdbthread.h @@ -51,8 +51,8 @@ extern bool debug_threads; #define threads_debug_printf(fmt, ...) \ debug_prefixed_printf_cond (debug_threads, "threads", fmt, ##__VA_ARGS__) -/* Frontend view of the thread state. Possible extensions: stepping, - finishing, until(ling),... +/* User/frontend view of the thread state. Possible extensions: + stepping, finishing, until(ling),... NOTE: Since the thread state is not a boolean, most times, you do not want to check it with negation. If you really want to check if @@ -81,6 +81,34 @@ enum thread_state THREAD_EXITED, }; +/* Internal view of the thread's running state. When a thread is + running from the user's perspective, it will still occasionally + stop, due to breakpoint hits, single-stepping, etc. Often those + stops are not meant to be user-visible. In such situations, the + user state will be THREAD_RUNNING, while the internal state + transitions between stopped, running, etc. */ + +enum thread_int_state +{ + /* The thread is stopped. If the thread has a pending wait status, + we should not process it until we try to let the thread run, in + which case we switch the thread to + THREAD_INT_RESUMED_PENDING_STATUS state. */ + THREAD_INT_STOPPED, + + /* The thread is running. */ + THREAD_INT_RUNNING, + + /* infrun wants the thread to be resumed, but didn't set it running + yet, because the thread has a pending wait status to process. We + shouldn't let the thread really run until that wait status has + been processed. */ + THREAD_INT_RESUMED_PENDING_STATUS, + + /* The thread is listed, but known to have exited. */ + THREAD_INT_EXITED, +}; + /* STEP_OVER_ALL means step over all subroutine calls. STEP_OVER_UNDEBUGGABLE means step over calls to undebuggable functions. STEP_OVER_NONE means don't step over any subroutine calls. */ @@ -218,10 +246,10 @@ struct thread_suspend_state last stopped, a pending breakpoint waitstatus is discarded. - If the thread is running, then this field has its value removed by - calling stop_pc.reset() (see thread_info::set_executing()). + calling stop_pc.reset() (see thread_info::set_internal_state()). Attempting to read a std::optional with no value is undefined behavior and will trigger an assertion error when _GLIBCXX_DEBUG is - defined, which should make error easier to track down. */ + defined, which should make errors easier to track down. */ std::optional stop_pc; }; @@ -263,8 +291,23 @@ public: bool deletable () const; - /* Mark this thread as running and notify observers. */ - void set_running (bool running); + /* Get the thread's (user-visible) state. */ + thread_state state () const { return m_state; } + + /* Set this thread's (user-visible) state. If the thread is set + running, notify observers. */ + void set_state (thread_state state) { set_state (state, false); } + + /* Get the thread's internal state. */ + thread_int_state internal_state () const { return m_internal_state; } + + /* Set the thread's internal state from STATE. If the state + switches to THREAD_INT_RUNNING, also clears the thread's stop_pc. + The thread may also be added to (when switching to + THREAD_INT_RESUMED_PENDING_STATUS), or removed from (when + switching from THREAD_INT_RESUMED_PENDING_STATUS), the list of + threads with a pending wait status. */ + void set_internal_state (thread_int_state state); ptid_t ptid; /* "Actual process id"; In fact, this may be overloaded with @@ -326,28 +369,6 @@ public: m_name = std::move (name); } - bool executing () const - { return m_executing; } - - /* Set the thread's 'm_executing' field from EXECUTING, and if EXECUTING - is true also clears the thread's stop_pc. */ - void set_executing (bool executing); - - bool resumed () const - { return m_resumed; } - - /* Set the thread's 'm_resumed' field from RESUMED. The thread may also - be added to (when RESUMED is true), or removed from (when RESUMED is - false), the list of threads with a pending wait status. */ - void set_resumed (bool resumed); - - /* 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 = THREAD_STOPPED; - /* State of GDB control of inferior thread execution. See `struct thread_control_state'. */ thread_control_state control; @@ -573,20 +594,22 @@ public: displaced_step_thread_state displaced_step_state; private: - /* True if this thread is resumed from infrun's perspective. - Note that a thread can be marked both as not-executing and - resumed at the same time. This happens if we try to resume a - thread that has a wait status pending. We shouldn't let the - 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. */ - bool m_resumed = false; - - /* True 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. */ - bool m_executing = false; + /* Set this thread's (user-visible) state. If the thread is set + running, notify observers, unless SUPPRESS_NOTIFICATION is true. + Returns the thread's previous state. */ + thread_state set_state (thread_state state, bool suppress_notification); + friend void set_state (process_stratum_target *targ, + ptid_t ptid, + thread_state state); + friend void finish_thread_state (process_stratum_target *targ, + ptid_t ptid); + + /* User view of the thread's stopped/running/exited state. */ + enum thread_state m_state = THREAD_STOPPED; + + /* The thread's internal state. See definition of + thread_int_state. */ + enum thread_int_state m_internal_state = THREAD_INT_STOPPED; /* State of inferior thread to restore after GDB is done with an inferior call. See `struct thread_suspend_state'. */ @@ -815,17 +838,15 @@ extern void switch_to_no_thread (); /* Switch from one thread to another. Does not read registers. */ extern void switch_to_thread_no_regs (struct thread_info *thread); -/* Marks or clears thread(s) PTID of TARG as resumed. If PTID is - MINUS_ONE_PTID, applies to all threads of TARG. If - ptid_is_pid(PTID) is true, applies to all threads of the process - pointed at by {TARG,PTID}. */ -extern void set_resumed (process_stratum_target *targ, - ptid_t ptid, bool resumed); +/* Marks thread PTID of TARG with user state STATE. If PTID is + minus_one_ptid, marks all threads of TARG. */ +extern void set_state (process_stratum_target *targ, + ptid_t ptid, thread_state state); -/* Marks thread PTID of TARG as running, or as stopped. If PTID is +/* Marks thread PTID of TARG with internal state STATE. If PTID is minus_one_ptid, marks all threads of TARG. */ -extern void set_running (process_stratum_target *targ, - ptid_t ptid, bool running); +extern void set_internal_state (process_stratum_target *targ, + ptid_t ptid, thread_int_state state); /* Marks or clears thread(s) PTID of TARG as having been requested to stop. If PTID is MINUS_ONE_PTID, applies to all threads of TARG. @@ -835,25 +856,19 @@ extern void set_running (process_stratum_target *targ, extern void set_stop_requested (process_stratum_target *targ, ptid_t ptid, bool stop); -/* Marks thread PTID of TARG as executing, or not. If PTID is - minus_one_ptid, marks all threads of TARG. - - Note that this is different from the running state. See the - description of state and executing fields of struct - thread_info. */ -extern void set_executing (process_stratum_target *targ, - ptid_t ptid, bool executing); - /* True if any (known or unknown) thread of TARG is or may be executing. */ extern bool threads_are_executing (process_stratum_target *targ); -/* Merge the executing property of thread PTID of TARG over to its - thread state property (frontend running/stopped view). +/* Propagate the internal thread state of thread PTID of TARG over to + its (user) thread state. - "not executing" -> "stopped" - "executing" -> "running" - "exited" -> "exited" + user <- internal + ------- ------------------------ + stopped <- stopped + running <- running + running <- continued-pending-status + exited <- exited If PTID is minus_one_ptid, go over all threads of TARG. @@ -1074,5 +1089,6 @@ extern void thread_try_catch_cmd (thread_info *thr, /* Return a string representation of STATE. */ extern const char *thread_state_string (enum thread_state state); +extern const char *thread_int_state_string (enum thread_int_state state); #endif /* GDB_GDBTHREAD_H */ diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c index 23788b44e92..a37eb132f47 100644 --- a/gdb/i386-tdep.c +++ b/gdb/i386-tdep.c @@ -4811,8 +4811,8 @@ i386_record_vex (struct i386_record_s *ir, uint8_t vex_w, uint8_t vex_r, /* Since we are reading pseudo registers, we need to tell GDB that it is safe to do so, by saying we aren't _really_ running the inferior right now. */ - SCOPE_EXIT { inferior_thread ()->set_executing (true); }; - inferior_thread () -> set_executing (false); + SCOPE_EXIT { inferior_thread ()->set_internal_state (THREAD_INT_RUNNING); }; + inferior_thread ()->set_internal_state (THREAD_INT_STOPPED); switch (opcode) { diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c index efa269cbe23..d39f2e5b015 100644 --- a/gdb/inf-ptrace.c +++ b/gdb/inf-ptrace.c @@ -175,7 +175,7 @@ inf_ptrace_target::attach (const char *args, int from_tty) /* Don't consider the thread stopped until we've processed its initial SIGSTOP stop. */ - set_executing (this, thr->ptid, true); + set_internal_state (this, thr->ptid, THREAD_INT_RUNNING); unpusher.release (); } diff --git a/gdb/infcall.c b/gdb/infcall.c index 098072dfd2a..697bbbacc5a 100644 --- a/gdb/infcall.c +++ b/gdb/infcall.c @@ -797,7 +797,7 @@ run_inferior_call (std::unique_ptr sm, struct gdb_exception caught_error; ptid_t call_thread_ptid = call_thread->ptid; - int was_running = call_thread->state == THREAD_RUNNING; + int was_running = call_thread->state () == THREAD_RUNNING; *timed_out_p = false; infcall_debug_printf ("call function at %s in thread %s, was_running = %d", @@ -928,7 +928,7 @@ run_inferior_call (std::unique_ptr sm, of error out of resume()), then we wouldn't need this. */ if (caught_error.reason < 0) { - if (call_thread->state != THREAD_EXITED) + if (call_thread->state () != THREAD_EXITED) breakpoint_auto_delete (call_thread->control.stop_bpstat); } @@ -1565,7 +1565,7 @@ call_function_by_hand_dummy (struct value *function, infcall_debug_printf ("after inferior call, exception (%d): %s", e.reason, e.what ()); infcall_debug_printf ("after inferior call, thread state is: %s", - thread_state_string (call_thread->state)); + thread_state_string (call_thread->state ())); gdb::observers::inferior_call_post.notify (call_thread_ptid, funaddr); @@ -1576,7 +1576,7 @@ call_function_by_hand_dummy (struct value *function, threads appear after GDB has reported a stop. */ update_thread_list (); - if (call_thread->state != THREAD_EXITED) + if (call_thread->state () != THREAD_EXITED) { /* The FSM should still be the same. */ gdb_assert (call_thread->thread_fsm () == sm); diff --git a/gdb/infcmd.c b/gdb/infcmd.c index e9b58ce5521..6c07e07619c 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -537,12 +537,12 @@ proceed_thread_callback (struct thread_info *thread) into a single target `resume_all' request, because some threads may be stopped in internal breakpoints/events, or stopped waiting for its turn in the displaced stepping queue (that is, they are - running && !executing). The target side has no idea about why - the thread is stopped, so a `resume_all' command would resume too - much. If/when GDB gains a way to tell the target `hold this - thread stopped until I say otherwise', then we can optimize - this. */ - if (thread->state != THREAD_STOPPED) + running from the user's perspective but internally stopped). The + target side has no idea about why the thread is stopped, so a + `resume_all' command would resume too much. If/when GDB gains a + way to tell the target `hold this thread stopped until I say + otherwise', then we can optimize this. */ + if (thread->state () != THREAD_STOPPED) return false; if (!thread->inf->has_execution ()) @@ -558,7 +558,7 @@ static void ensure_valid_thread (void) { if (inferior_ptid == null_ptid - || inferior_thread ()->state == THREAD_EXITED) + || inferior_thread ()->state () == THREAD_EXITED) error (_("Cannot execute this command without a live selected thread.")); } @@ -587,7 +587,7 @@ error_is_running (void) static void ensure_not_running (void) { - if (inferior_thread ()->state == THREAD_RUNNING) + if (inferior_thread ()->state () == THREAD_RUNNING) error_is_running (); } @@ -945,7 +945,8 @@ prepare_one_step (thread_info *tp, struct step_command_fsm *sm) /* Pretend that we've ran. */ resume_ptid = user_visible_resume_ptid (1); - set_running (tp->inf->process_target (), resume_ptid, true); + set_state (tp->inf->process_target (), resume_ptid, + THREAD_RUNNING); step_into_inline_frame (tp); @@ -1921,12 +1922,12 @@ info_program_command (const char *args, int from_tty) print_thread_id (tp), target_pid_to_str (tp->ptid).c_str ()); - if (tp->state == THREAD_EXITED) + if (tp->state () == THREAD_EXITED) { gdb_printf (_("Selected thread has exited.\n")); return; } - else if (tp->state == THREAD_RUNNING) + else if (tp->state () == THREAD_RUNNING) { gdb_printf (_("Selected thread is running.\n")); return; @@ -1948,13 +1949,13 @@ info_program_command (const char *args, int from_tty) print_thread_id (tp), target_pid_to_str (tp->ptid).c_str ()); - if (tp->state == THREAD_EXITED) + if (tp->state () == THREAD_EXITED) { gdb_printf (_("Thread has since exited.\n")); return; } - if (tp->state == THREAD_RUNNING) + if (tp->state () == THREAD_RUNNING) { gdb_printf (_("Thread is now running.\n")); return; @@ -2473,7 +2474,7 @@ proceed_after_attach (inferior *inf) scoped_restore_current_thread restore_thread; for (thread_info *thread : inf->non_exited_threads ()) - if (!thread->executing () + if (thread->internal_state () != THREAD_INT_RUNNING && !thread->stop_requested && thread->stop_signal () == GDB_SIGNAL_0) { @@ -2628,6 +2629,10 @@ attach_command (const char *args, int from_tty) this function should probably be moved into target_pre_inferior. */ target_pre_inferior (); + /* Set up execution context to know that we should return from + wait_for_inferior as soon as the target reports a stop. */ + init_wait_for_inferior (); + gdb::unique_xmalloc_ptr stripped = strip_bg_char (args, &async_exec); args = stripped.get (); @@ -2670,10 +2675,6 @@ attach_command (const char *args, int from_tty) finished. */ target_terminal::inferior (); - /* Set up execution context to know that we should return from - wait_for_inferior as soon as the target reports a stop. */ - init_wait_for_inferior (); - inferior->needs_setup = true; if (target_is_non_stop_p ()) @@ -2753,7 +2754,7 @@ notice_new_inferior (thread_info *thr, bool leave_running, int from_tty) /* When we "notice" a new inferior we need to do all the things we would normally do if we had just attached to it. */ - if (thr->executing ()) + if (thr->internal_state () == THREAD_INT_RUNNING) { struct inferior *inferior = current_inferior (); diff --git a/gdb/inferior.h b/gdb/inferior.h index 54f5229b420..301a78f9ebb 100644 --- a/gdb/inferior.h +++ b/gdb/inferior.h @@ -201,8 +201,8 @@ extern void child_interrupt (struct target_ops *self); /* From fork-child.c */ /* Helper function to call STARTUP_INFERIOR with PID and NUM_TRAPS. - This function already calls set_executing. Return the ptid_t from - STARTUP_INFERIOR. */ + This function already sets the threads' internal state to + THREAD_STOPPED. Return the ptid_t from STARTUP_INFERIOR. */ extern ptid_t gdb_startup_inferior (pid_t pid, int num_traps); /* From infcmd.c */ diff --git a/gdb/inflow.c b/gdb/inflow.c index f5ae6cd982f..aef3c8c7081 100644 --- a/gdb/inflow.c +++ b/gdb/inflow.c @@ -525,7 +525,7 @@ child_interrupt (struct target_ops *self) thread_info *resumed = NULL; for (thread_info *thr : all_non_exited_threads ()) { - if (thr->executing ()) + if (thr->internal_state () == THREAD_INT_RUNNING) { resumed = thr; break; diff --git a/gdb/infrun.c b/gdb/infrun.c index 70a799a8269..52e526361e4 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -990,14 +990,14 @@ follow_inferior_reset_breakpoints (void) insert_breakpoints (); } -/* The child has exited or execed: resume THREAD, a thread of the parent, - if it was meant to be executing. */ +/* The child has exited or execed: resume THREAD, a thread of the + parent, if it was meant to be running. */ static void proceed_after_vfork_done (thread_info *thread) { - if (thread->state == THREAD_RUNNING - && !thread->executing () + if (thread->state () == THREAD_RUNNING + && thread->internal_state () != THREAD_INT_RUNNING && !thread->stop_requested && thread->stop_signal () == GDB_SIGNAL_0) { @@ -2226,15 +2226,14 @@ start_step_over (void) } if (tp->control.trap_expected - || tp->resumed () - || tp->executing ()) + || tp->internal_state () == THREAD_INT_RESUMED_PENDING_STATUS + || tp->internal_state () == THREAD_INT_RUNNING) { internal_error ("[%s] has inconsistent state: " - "trap_expected=%d, resumed=%d, executing=%d\n", + "trap_expected=%d, internal_state=%s\n", tp->ptid.to_string ().c_str (), tp->control.trap_expected, - tp->resumed (), - tp->executing ()); + thread_int_state_string (tp->internal_state ())); } infrun_debug_printf ("resuming [%s] for step-over", @@ -2258,7 +2257,7 @@ start_step_over (void) /* If the thread's step over could not be initiated because no buffers were available, it was re-added to the global step over chain. */ - if (tp->resumed ()) + if (tp->internal_state () != THREAD_INT_STOPPED) { infrun_debug_printf ("[%s] was resumed.", tp->ptid.to_string ().c_str ()); @@ -2658,7 +2657,7 @@ resume_1 (enum gdb_signal sig) tp->control.currently_stepping); tp->inf->process_target ()->threads_executing = true; - tp->set_resumed (true); + tp->set_internal_state (THREAD_INT_RESUMED_PENDING_STATUS); /* FIXME: What should we do if we are supposed to resume this thread with a signal? Maybe we should maintain a queue of @@ -2783,7 +2782,6 @@ resume_1 (enum gdb_signal sig) resume_ptid = internal_resume_ptid (user_step); do_target_resume (resume_ptid, false, GDB_SIGNAL_0); - tp->set_resumed (true); return; } } @@ -2975,7 +2973,6 @@ resume_1 (enum gdb_signal sig) } do_target_resume (resume_ptid, step, sig); - tp->set_resumed (true); } /* Resume the inferior. SIG is the signal to give the inferior @@ -3039,6 +3036,7 @@ static void clear_proceed_status_thread (struct thread_info *tp) { infrun_debug_printf ("%s", tp->ptid.to_string ().c_str ()); + gdb_assert (tp->internal_state () != THREAD_INT_RUNNING); /* If we're starting a new sequence, then the previous finished single-step is no longer relevant. */ @@ -3050,6 +3048,7 @@ clear_proceed_status_thread (struct thread_info *tp) "Discarding.", tp->ptid.to_string ().c_str ()); + tp->set_internal_state (THREAD_INT_STOPPED); tp->clear_pending_waitstatus (); tp->set_stop_reason (TARGET_STOPPED_BY_NO_REASON); } @@ -3124,7 +3123,8 @@ clear_proceed_status (int step) /* In all-stop mode, delete the per-thread status of all threads we're about to resume, implicitly and explicitly. */ for (thread_info *tp : all_non_exited_threads (resume_target, resume_ptid)) - clear_proceed_status_thread (tp); + if (tp->internal_state () != THREAD_INT_RUNNING) + clear_proceed_status_thread (tp); } if (inferior_ptid != null_ptid) @@ -3484,6 +3484,8 @@ check_multi_target_resumption (process_stratum_target *resume_target) static void proceed_resume_thread_checked (thread_info *tp) { + gdb_assert (tp->internal_state () != THREAD_INT_EXITED); + if (!tp->inf->has_execution ()) { infrun_debug_printf ("[%s] target has no execution", @@ -3491,11 +3493,10 @@ proceed_resume_thread_checked (thread_info *tp) return; } - if (tp->resumed ()) + if (tp->internal_state () != THREAD_INT_STOPPED) { infrun_debug_printf ("[%s] resumed", tp->ptid.to_string ().c_str ()); - gdb_assert (tp->executing () || tp->has_pending_waitstatus ()); return; } @@ -3671,7 +3672,7 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal) inferior function, as in that case we pretend the inferior doesn't run at all. */ if (!cur_thr->control.in_infcall) - set_running (resume_target, resume_ptid, true); + set_state (resume_target, resume_ptid, THREAD_RUNNING); infrun_debug_printf ("addr=%s, signal=%s, resume_ptid=%s", paddress (gdbarch, addr), @@ -3872,9 +3873,9 @@ infrun_thread_stop_requested (ptid_t ptid) for reporting the stop now. */ for (thread_info *tp : all_threads (curr_target, ptid)) { - if (tp->state != THREAD_RUNNING) + if (tp->state () != THREAD_RUNNING) continue; - if (tp->executing ()) + if (tp->internal_state () == THREAD_INT_RUNNING) continue; /* Remove matching threads from the step-over queue, so @@ -3905,10 +3906,10 @@ infrun_thread_stop_requested (ptid_t ptid) if (step_over_info_valid_p ()) continue; - /* Otherwise we can process the (new) pending event now. Set - it so this pending event is considered by + /* Otherwise we can process the (new) pending event now. Switch + state so this pending event is considered by do_target_wait. */ - tp->set_resumed (true); + tp->set_internal_state (THREAD_INT_RESUMED_PENDING_STATUS); } } @@ -4014,7 +4015,7 @@ random_pending_event_thread (inferior *inf, ptid_t waiton_ptid) } infrun_debug_printf ("Found %s.", thread->ptid.to_string ().c_str ()); - gdb_assert (thread->resumed ()); + gdb_assert (thread->internal_state () == THREAD_INT_RESUMED_PENDING_STATUS); gdb_assert (thread->has_pending_waitstatus ()); return thread; @@ -4127,6 +4128,7 @@ do_target_wait_1 (inferior *inf, ptid_t ptid, tp->set_stop_reason (TARGET_STOPPED_BY_NO_REASON); *status = tp->pending_waitstatus (); + tp->set_internal_state (THREAD_INT_STOPPED); tp->clear_pending_waitstatus (); /* Wake up the event loop again, until all pending events are @@ -4325,7 +4327,7 @@ prepare_for_detach (void) { if (thr->displaced_step_state.in_progress ()) { - if (thr->executing ()) + if (thr->internal_state () == THREAD_INT_RUNNING) { if (!thr->stop_requested) { @@ -4333,8 +4335,6 @@ prepare_for_detach (void) thr->stop_requested = true; } } - else - thr->set_resumed (false); } } @@ -4473,7 +4473,7 @@ clean_up_just_stopped_threads_fsms (struct execution_control_state *ecs) for (thread_info *thr : all_threads_safe ()) { - if (thr->state == THREAD_EXITED) + if (thr->state () == THREAD_EXITED) continue; if (thr == ecs->event_thread) @@ -4809,7 +4809,7 @@ fetch_inferior_event () if (cmd_done && exec_done_display_p && (inferior_ptid == null_ptid - || inferior_thread ()->state != THREAD_RUNNING)) + || inferior_thread ()->state () != THREAD_RUNNING)) gdb_printf (_("completed.\n")); } @@ -5372,14 +5372,14 @@ save_waitstatus (struct thread_info *tp, const target_waitstatus &ws) } } -/* Mark the non-executing threads accordingly. In all-stop, all +/* Mark the internally stopped threads accordingly. In all-stop, all threads of all processes are stopped when we get any event reported. In non-stop mode, only the event thread stops. */ static void -mark_non_executing_threads (process_stratum_target *target, - ptid_t event_ptid, - const target_waitstatus &ws) +mark_internally_stopped_threads (process_stratum_target *target, + ptid_t event_ptid, + const target_waitstatus &ws) { ptid_t mark_ptid; @@ -5399,18 +5399,15 @@ mark_non_executing_threads (process_stratum_target *target, target_mourn_inferior, by associating the same inferior/thread to another fork. We haven't mourned yet at this point, but we must mark any threads left in the - process as not-executing so that finish_thread_state marks - them stopped (in the user's perspective) if/when we present + process as internally stopped so that finish_thread_state marks + them stopped in the user's perspective if/when we present the stop to the user. */ mark_ptid = ptid_t (event_ptid.pid ()); } else mark_ptid = event_ptid; - set_executing (target, mark_ptid, false); - - /* Likewise the resumed flag. */ - set_resumed (target, mark_ptid, false); + set_internal_state (target, mark_ptid, THREAD_INT_STOPPED); } /* Handle one event after stopping threads. If the eventing thread @@ -5476,11 +5473,11 @@ handle_one (const wait_one_event &event) if (t != nullptr) { - /* Set the threads as non-executing to avoid - another stop attempt on them. */ + /* Set the threads as internally stopped to avoid another + stop attempt on them. */ switch_to_thread_no_regs (t); - mark_non_executing_threads (event.target, event.ptid, - event.ws); + mark_internally_stopped_threads (event.target, event.ptid, + event.ws); save_waitstatus (t, event.ws); t->stop_requested = false; @@ -5502,8 +5499,7 @@ handle_one (const wait_one_event &event) t = add_thread (event.target, event.ptid); t->stop_requested = false; - t->set_executing (false); - t->set_resumed (false); + t->set_internal_state (THREAD_INT_STOPPED); t->control.may_range_step = 0; /* This may be the first time we see the inferior report @@ -5732,7 +5728,7 @@ stop_all_threads (const char *reason, inferior *inf) if (!target_is_non_stop_p ()) continue; - if (t->executing ()) + if (t->internal_state () == THREAD_INT_RUNNING) { /* If already stopping, don't request a stop again. We just haven't seen the notification yet. */ @@ -5759,7 +5755,7 @@ stop_all_threads (const char *reason, inferior *inf) /* The thread may be not executing, but still be resumed with a pending status to process. */ - t->set_resumed (false); + t->set_internal_state (THREAD_INT_STOPPED); } } @@ -5875,7 +5871,7 @@ handle_no_resumed (struct execution_control_state *ecs) for (thread_info *thread : all_non_exited_threads ()) { - if (swap_terminal && thread->executing ()) + if (swap_terminal && thread->internal_state () == THREAD_INT_RUNNING) { if (thread->inf != curr_inf) { @@ -5887,7 +5883,7 @@ handle_no_resumed (struct execution_control_state *ecs) swap_terminal = false; } - if (!ignore_event && thread->resumed ()) + if (!ignore_event && thread->internal_state () != THREAD_INT_STOPPED) { /* Either there were no unwaited-for children left in the target at some point, but there are now, or some target @@ -6159,7 +6155,7 @@ handle_inferior_event (struct execution_control_state *ecs) } } - mark_non_executing_threads (ecs->target, ecs->ptid, ecs->ws); + mark_internally_stopped_threads (ecs->target, ecs->ptid, ecs->ws); switch (ecs->ws.kind ()) { @@ -6423,7 +6419,7 @@ handle_inferior_event (struct execution_control_state *ecs) /* If not resuming the parent, mark it stopped. */ if (ecs->ws.kind () != TARGET_WAITKIND_THREAD_CLONED && follow_child && !detach_fork && !non_stop && !sched_multi) - parent->set_running (false); + parent->set_state (THREAD_STOPPED); /* If resuming the child, mark it running. */ if ((ecs->ws.kind () == TARGET_WAITKIND_THREAD_CLONED @@ -6431,7 +6427,7 @@ handle_inferior_event (struct execution_control_state *ecs) || (ecs->ws.kind () != TARGET_WAITKIND_THREAD_CLONED && (follow_child || (!detach_fork && (non_stop || sched_multi))))) - child->set_running (true); + child->set_state (THREAD_RUNNING); /* In non-stop mode, also resume the other branch. */ if ((ecs->ws.kind () == TARGET_WAITKIND_THREAD_CLONED @@ -6623,18 +6619,17 @@ restart_threads (struct thread_info *event_thread, inferior *inf) continue; } - if (!(tp->state == THREAD_RUNNING || tp->control.in_infcall)) + if (!(tp->state () == THREAD_RUNNING || tp->control.in_infcall)) { infrun_debug_printf ("restart threads: [%s] not meant to be running", tp->ptid.to_string ().c_str ()); continue; } - if (tp->resumed ()) + if (tp->internal_state () != THREAD_INT_STOPPED) { - infrun_debug_printf ("restart threads: [%s] resumed", + infrun_debug_printf ("restart threads: [%s] already resumed", tp->ptid.to_string ().c_str ()); - gdb_assert (tp->executing () || tp->has_pending_waitstatus ()); continue; } @@ -6642,7 +6637,6 @@ restart_threads (struct thread_info *event_thread, inferior *inf) { infrun_debug_printf ("restart threads: [%s] needs step-over", tp->ptid.to_string ().c_str ()); - gdb_assert (!tp->resumed ()); continue; } @@ -6651,7 +6645,7 @@ restart_threads (struct thread_info *event_thread, inferior *inf) { infrun_debug_printf ("restart threads: [%s] has pending status", tp->ptid.to_string ().c_str ()); - tp->set_resumed (true); + tp->set_internal_state (THREAD_INT_RESUMED_PENDING_STATUS); continue; } @@ -6690,7 +6684,7 @@ restart_threads (struct thread_info *event_thread, inferior *inf) static bool resumed_thread_with_pending_status (struct thread_info *tp) { - return tp->resumed () && tp->has_pending_waitstatus (); + return tp->internal_state () == THREAD_INT_RESUMED_PENDING_STATUS; } /* Called when we get an event that may finish an in-line or @@ -6779,12 +6773,12 @@ finish_step_over (struct execution_control_state *ecs) /* Record the event thread's event for later. */ save_waitstatus (tp, ecs->ws); - /* This was cleared early, by handle_inferior_event. Set it + /* The internal state was reset to stopped early, by + handle_inferior_event. Switch to resumed-pending-status so this pending event is considered by do_target_wait. */ - tp->set_resumed (true); - - gdb_assert (!tp->executing ()); + gdb_assert (tp->internal_state () == THREAD_INT_STOPPED); + tp->set_internal_state (THREAD_INT_RESUMED_PENDING_STATUS); regcache = get_thread_regcache (tp); tp->set_stop_pc (regcache_read_pc (regcache)); @@ -8436,7 +8430,7 @@ restart_stepped_thread (process_stratum_target *resume_target, for (thread_info *tp : all_threads_safe ()) { - if (tp->state == THREAD_EXITED) + if (tp->state () == THREAD_EXITED) continue; if (tp->has_pending_waitstatus ()) @@ -8460,7 +8454,7 @@ restart_stepped_thread (process_stratum_target *resume_target, for (thread_info *tp : all_threads_safe ()) { - if (tp->state == THREAD_EXITED) + if (tp->state () == THREAD_EXITED) continue; if (tp->has_pending_waitstatus ()) @@ -8495,26 +8489,27 @@ restart_after_all_stop_detach (process_stratum_target *proc_target) current inferior may no longer have a process_stratum target pushed, as we just detached. */ - /* See if we have a THREAD_RUNNING thread that need to be - re-resumed. If we have any thread that is already executing, - then we don't need to resume the target -- it is already been - resumed. With the remote target (in all-stop), it's even - impossible to issue another resumption if the target is already - resumed, until the target reports a stop. */ + /* See if we have a thread that is running from the user's + perspective that need to be re-resumed. If we have any thread + that is already executing, then we don't need to resume the + target -- it is already been resumed. With the remote target (in + all-stop), it's even impossible to issue another resumption if + the target is already resumed, until the target reports a + stop. */ for (thread_info *thr : all_threads (proc_target)) { - if (thr->state != THREAD_RUNNING) + if (thr->state () != THREAD_RUNNING) continue; /* If we have any thread that is already executing, then we don't need to resume the target -- it is already been resumed. */ - if (thr->executing ()) + if (thr->internal_state () == THREAD_INT_RUNNING) return; - /* If we have a pending event to process, skip resuming the + /* If we have a pending status to process, skip resuming the target and go straight to processing it. */ - if (thr->resumed () && thr->has_pending_waitstatus ()) + if (thr->internal_state () == THREAD_INT_RESUMED_PENDING_STATUS) return; } @@ -8527,7 +8522,7 @@ restart_after_all_stop_detach (process_stratum_target *proc_target) it. */ for (thread_info *thr : all_threads (proc_target)) { - if (thr->state != THREAD_RUNNING) + if (thr->state () != THREAD_RUNNING) continue; execution_control_state ecs (thr); @@ -8564,7 +8559,7 @@ keep_going_stepped_thread (struct thread_info *tp) stepping thread is still alive. For that reason, we need to synchronously query the target now. */ - if (tp->state == THREAD_EXITED || !target_thread_alive (tp->ptid)) + if (tp->state () == THREAD_EXITED || !target_thread_alive (tp->ptid)) { infrun_debug_printf ("not resuming previously stepped thread, it has " "vanished"); @@ -8617,7 +8612,6 @@ keep_going_stepped_thread (struct thread_info *tp) get_frame_address_space (frame), tp->stop_pc ()); - tp->set_resumed (true); resume_ptid = internal_resume_ptid (tp->control.stepping_command); do_target_resume (resume_ptid, false, GDB_SIGNAL_0); } @@ -9026,7 +9020,7 @@ static void keep_going_pass_signal (struct execution_control_state *ecs) { gdb_assert (ecs->event_thread->ptid == inferior_ptid); - gdb_assert (!ecs->event_thread->resumed ()); + gdb_assert (ecs->event_thread->internal_state () == THREAD_INT_STOPPED); /* Save the pc before execution, to compare with pc after stop. */ ecs->event_thread->prev_pc @@ -9494,7 +9488,7 @@ stop_context::changed () const return true; if (inf_num != current_inferior ()->num) return true; - if (thread != nullptr && thread->state != THREAD_STOPPED) + if (thread != nullptr && thread->state () != THREAD_STOPPED) return true; if (get_stop_id () != stop_id) return true; diff --git a/gdb/infrun.h b/gdb/infrun.h index b9b64aca45a..b09e7c1df8a 100644 --- a/gdb/infrun.h +++ b/gdb/infrun.h @@ -66,12 +66,11 @@ infrun_debug_show_threads (const char *title, ThreadRange threads) infrun_debug_printf ("%s:", title); for (thread_info *thread : threads) - infrun_debug_printf (" thread %s, executing = %d, resumed = %d, " + infrun_debug_printf (" thread %s, internal_state = %s, " "state = %s", thread->ptid.to_string ().c_str (), - thread->executing (), - thread->resumed (), - thread_state_string (thread->state)); + thread_int_state_string (thread->internal_state ()), + thread_state_string (thread->state ())); } } diff --git a/gdb/linux-fork.c b/gdb/linux-fork.c index 338ba032a0e..377c68ae6b9 100644 --- a/gdb/linux-fork.c +++ b/gdb/linux-fork.c @@ -363,8 +363,7 @@ fork_load_infrun_state (struct fork_info *fp) inferior_thread ()->set_stop_pc (regcache_read_pc (get_thread_regcache (inferior_thread ()))); - inferior_thread ()->set_executing (false); - inferior_thread ()->set_resumed (false); + inferior_thread ()->set_internal_state (THREAD_INT_STOPPED); nullify_last_target_wait_ptid (); /* Now restore the file positions of open file descriptors. */ @@ -726,7 +725,7 @@ delete_checkpoint_command (const char *args, int from_tty) ptid. */ thread_info *parent = linux_target->find_thread (pptid); if ((parent == NULL && find_fork_ptid (pptid).first != nullptr) - || (parent != NULL && parent->state == THREAD_STOPPED)) + || (parent != NULL && parent->state () == THREAD_STOPPED)) { if (inferior_call_waitpid (pptid, ptid.pid ())) warning (_("Unable to wait pid %s"), @@ -866,7 +865,7 @@ print_checkpoints (struct ui_out *uiout, inferior *req_inf, fork_info *req_fi) uiout->field_string ("target-id", target_pid_to_str (proc_ptid (fi.ptid)).c_str ()); - if (t->state == THREAD_RUNNING && is_current) + if (t->state () == THREAD_RUNNING && is_current) uiout->text ("(running)"); else { @@ -1108,7 +1107,7 @@ restart_command (const char *args, int from_tty) /* Don't allow switching from a thread/fork that's running. */ inferior *curinf = current_inferior (); if (curinf->pid != 0 - && any_thread_of_inferior (curinf)->state == THREAD_RUNNING) + && any_thread_of_inferior (curinf)->state () == THREAD_RUNNING) error (_("Cannot execute this command while " "the selected thread is running.")); diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index 2f98060506b..4de4cc83cfa 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -1246,8 +1246,8 @@ linux_nat_target::attach (const char *args, int from_tty) if (lwp->ptid.pid () != lwp->ptid.lwp ()) { add_thread (linux_target, lwp->ptid); - set_running (linux_target, lwp->ptid, true); - set_executing (linux_target, lwp->ptid, true); + set_state (linux_target, lwp->ptid, THREAD_RUNNING); + set_internal_state (linux_target, lwp->ptid, THREAD_INT_RUNNING); } return 0; }); @@ -1331,7 +1331,8 @@ get_detach_signal (struct lwp_info *lp) { thread_info *tp = linux_target->find_thread (lp->ptid); - if (target_is_non_stop_p () && !tp->executing ()) + if (target_is_non_stop_p () + && tp->internal_state () != THREAD_INT_RUNNING) { if (tp->has_pending_waitstatus ()) { diff --git a/gdb/linux-thread-db.c b/gdb/linux-thread-db.c index f60116afb2c..7f8f9eeaa53 100644 --- a/gdb/linux-thread-db.c +++ b/gdb/linux-thread-db.c @@ -1361,7 +1361,7 @@ record_thread (struct thread_db_info *info, /* Add the thread to GDB's thread list. If we already know about a thread with this PTID, but it's marked exited, then the kernel reused the tid of an old thread. */ - if (tp == NULL || tp->state == THREAD_EXITED) + if (tp == NULL || tp->state () == THREAD_EXITED) tp = add_thread_with_info (info->process_target, ptid, private_thread_info_up (priv)); else @@ -1625,7 +1625,7 @@ thread_db_target::update_thread_list () continue; thread_info *thread = any_live_thread_of_inferior (inf); - if (thread == NULL || thread->executing ()) + if (thread == NULL || thread->internal_state () == THREAD_INT_RUNNING) continue; /* It's best to avoid td_ta_thr_iter if possible. That walks diff --git a/gdb/mi/mi-cmd-var.c b/gdb/mi/mi-cmd-var.c index 9cbb85722b3..79c8b9979e2 100644 --- a/gdb/mi/mi-cmd-var.c +++ b/gdb/mi/mi-cmd-var.c @@ -608,14 +608,14 @@ mi_cmd_var_update_iter (struct varobj *var, bool only_floating, if (thread_id == -1) { thread_stopped = (inferior_ptid == null_ptid - || inferior_thread ()->state == THREAD_STOPPED); + || inferior_thread ()->state () == THREAD_STOPPED); } else { thread_info *tp = find_thread_global_id (thread_id); thread_stopped = (tp == NULL - || tp->state == THREAD_STOPPED); + || tp->state () == THREAD_STOPPED); } if (thread_stopped diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c index 1c905347007..de8173676b1 100644 --- a/gdb/mi/mi-interp.c +++ b/gdb/mi/mi-interp.c @@ -868,7 +868,7 @@ mi_interp::on_user_selected_context_changed (user_selected_what selection) gdb_printf (this->event_channel, "thread-selected,id=\"%d\"", tp->global_num); - if (tp->state != THREAD_RUNNING) + if (tp->state () != THREAD_RUNNING) { if (has_stack_frames ()) print_stack_frame_to_uiout (mi_uiout, get_selected_frame (NULL), diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c index cda72ca4f5b..cfb6fcf0772 100644 --- a/gdb/mi/mi-main.c +++ b/gdb/mi/mi-main.c @@ -239,7 +239,7 @@ mi_cmd_exec_jump (const char *args, const char *const *argv, int argc) static void proceed_thread (struct thread_info *thread, int pid) { - if (thread->state != THREAD_STOPPED) + if (thread->state () != THREAD_STOPPED) return; if (pid != 0 && thread->ptid.pid () != pid) @@ -367,7 +367,7 @@ mi_cmd_exec_interrupt (const char *command, const char *const *argv, int argc) iterate_over_threads ([&] (struct thread_info *thread) { - if (thread->state != THREAD_RUNNING) + if (thread->state () != THREAD_RUNNING) return false; if (thread->ptid.pid () != inf->pid) @@ -508,7 +508,7 @@ mi_cmd_target_detach (const char *command, const char *const *argv, int argc) target_detach detaches from the parent of inferior_ptid. */ tp = iterate_over_threads ([&] (struct thread_info *ti) { - return ti->ptid.pid () == pid && ti->state != THREAD_EXITED; + return ti->ptid.pid () == pid && ti->state () != THREAD_EXITED; }); if (!tp) error (_("Thread group is empty")); @@ -2059,7 +2059,7 @@ mi_cmd_execute (struct mi_parse *parse) if (tp == NULL) error (_("Invalid thread id: %d"), parse->thread); - if (tp->state == THREAD_EXITED) + if (tp->state () == THREAD_EXITED) error (_("Thread id: %d has terminated"), parse->thread); if (parse->cmd->preserve_user_selected_context ()) diff --git a/gdb/process-stratum-target.c b/gdb/process-stratum-target.c index 329589dc34b..039dac4c0fe 100644 --- a/gdb/process-stratum-target.c +++ b/gdb/process-stratum-target.c @@ -114,8 +114,9 @@ process_stratum_target::maybe_add_resumed_with_pending_wait_status { gdb_assert (!thread->resumed_with_pending_wait_status_node.is_linked ()); - if (thread->resumed () && thread->has_pending_waitstatus ()) + if (thread->internal_state () == THREAD_INT_RESUMED_PENDING_STATUS) { + gdb_assert (thread->has_pending_waitstatus ()); infrun_debug_printf ("adding to resumed threads with event list: %s", thread->ptid.to_string ().c_str ()); m_resumed_with_pending_wait_status.push_back (*thread); @@ -128,8 +129,9 @@ void process_stratum_target::maybe_remove_resumed_with_pending_wait_status (thread_info *thread) { - if (thread->resumed () && thread->has_pending_waitstatus ()) + if (thread->internal_state () == THREAD_INT_RESUMED_PENDING_STATUS) { + gdb_assert (thread->has_pending_waitstatus ()); infrun_debug_printf ("removing from resumed threads with event list: %s", thread->ptid.to_string ().c_str ()); gdb_assert (thread->resumed_with_pending_wait_status_node.is_linked ()); diff --git a/gdb/python/py-infthread.c b/gdb/python/py-infthread.c index 4f1f8d47e32..0a392616d48 100644 --- a/gdb/python/py-infthread.c +++ b/gdb/python/py-infthread.c @@ -261,7 +261,7 @@ thpy_is_stopped (PyObject *self, PyObject *args) THPY_REQUIRE_VALID (thread_obj); - if (thread_obj->thread->state == THREAD_STOPPED) + if (thread_obj->thread->state () == THREAD_STOPPED) Py_RETURN_TRUE; Py_RETURN_FALSE; @@ -277,7 +277,7 @@ thpy_is_running (PyObject *self, PyObject *args) THPY_REQUIRE_VALID (thread_obj); - if (thread_obj->thread->state == THREAD_RUNNING) + if (thread_obj->thread->state () == THREAD_RUNNING) Py_RETURN_TRUE; Py_RETURN_FALSE; @@ -293,7 +293,7 @@ thpy_is_exited (PyObject *self, PyObject *args) THPY_REQUIRE_VALID (thread_obj); - if (thread_obj->thread->state == THREAD_EXITED) + if (thread_obj->thread->state () == THREAD_EXITED) Py_RETURN_TRUE; Py_RETURN_FALSE; diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c index 5dd3f1e1ddd..6dbf26a2190 100644 --- a/gdb/record-btrace.c +++ b/gdb/record-btrace.c @@ -2039,18 +2039,18 @@ get_thread_current_frame_id (struct thread_info *tp) process_stratum_target *proc_target = tp->inf->process_target (); - /* Clear the executing flag to allow changes to the current frame. - We are not actually running, yet. We just started a reverse execution - command or a record goto command. - For the latter, EXECUTING is false and this has no effect. - For the former, EXECUTING is true and we're in wait, about to - move the thread. Since we need to recompute the stack, we temporarily - set EXECUTING to false. */ - bool executing = tp->executing (); - set_executing (proc_target, inferior_ptid, false); + /* Temporarily set the thread to internally stopped to allow changes + to the current frame. We are not actually running, yet. We just + started a reverse execution command or a record goto command. + For the latter, the thread is stopped and this has no effect. + For the former, the thread is running and we're in wait, about to + move the thread. Since we need to recompute the stack, we + temporarily set the thread to internally stopped. */ + thread_int_state prev_int_state = tp->internal_state (); + set_internal_state (proc_target, inferior_ptid, THREAD_INT_STOPPED); SCOPE_EXIT { - set_executing (proc_target, inferior_ptid, executing); + set_internal_state (proc_target, inferior_ptid, prev_int_state); }; return get_frame_id (get_current_frame ()); } diff --git a/gdb/record-full.c b/gdb/record-full.c index b52fb062d80..cf162f451fc 100644 --- a/gdb/record-full.c +++ b/gdb/record-full.c @@ -1270,10 +1270,12 @@ record_full_wait_1 (struct target_ops *ops, { /* Try to insert the software single step breakpoint. If insert success, set step to 0. */ - set_executing (proc_target, inferior_ptid, false); + set_internal_state (proc_target, inferior_ptid, + THREAD_INT_STOPPED); SCOPE_EXIT { - set_executing (proc_target, inferior_ptid, true); + set_internal_state (proc_target, inferior_ptid, + THREAD_INT_RUNNING); }; reinit_frame_cache (); diff --git a/gdb/regcache.c b/gdb/regcache.c index e3d435f90d5..cd6e65f9dc9 100644 --- a/gdb/regcache.c +++ b/gdb/regcache.c @@ -429,7 +429,7 @@ get_thread_regcache (process_stratum_target *target, ptid_t ptid) struct regcache * get_thread_regcache (thread_info *thread) { - gdb_assert (thread->state != THREAD_EXITED); + gdb_assert (thread->state () != THREAD_EXITED); return get_thread_regcache (thread->inf->process_target (), thread->ptid); diff --git a/gdb/remote.c b/gdb/remote.c index 1c49cdf0fc0..413425ab8e7 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -1220,12 +1220,15 @@ public: /* Remote specific methods. */ ptid_t select_thread_for_ambiguous_stop_reply (const struct target_waitstatus &status); - void remote_notice_new_inferior (ptid_t currthread, bool executing); + void remote_notice_new_inferior (ptid_t currthread, + thread_int_state internal_state); void print_one_stopped_thread (thread_info *thread); void process_initial_stop_replies (int from_tty); - thread_info *remote_add_thread (ptid_t ptid, bool running, bool executing, + thread_info *remote_add_thread (ptid_t ptid, + thread_state state, + thread_int_state internal_state, bool silent_p); void btrace_sync_conf (const btrace_config *conf); @@ -2924,13 +2927,16 @@ static remote_thread_info *get_remote_thread_info (thread_info *thread); static remote_thread_info *get_remote_thread_info (remote_target *target, ptid_t ptid); -/* Add thread PTID to GDB's thread list. Tag it as executing/running - according to EXECUTING and RUNNING respectively. If SILENT_P (or the - remote_state::starting_up flag) is true then the new thread is added - silently, otherwise the new thread will be announced to the user. */ +/* Add thread PTID to GDB's thread list. Tag its user and internal + states according to STATE and INTERNAL_STATE respectively. If + SILENT_P (or the remote_state::starting_up flag) is true then the + new thread is added silently, otherwise the new thread will be + announced to the user. */ thread_info * -remote_target::remote_add_thread (ptid_t ptid, bool running, bool executing, +remote_target::remote_add_thread (ptid_t ptid, + thread_state state, + thread_int_state internal_state, bool silent_p) { struct remote_state *rs = get_remote_state (); @@ -2947,10 +2953,10 @@ remote_target::remote_add_thread (ptid_t ptid, bool running, bool executing, else thread = add_thread (this, ptid); - if (executing) + if (internal_state == THREAD_INT_RUNNING) get_remote_thread_info (thread)->set_resumed (); - set_executing (this, ptid, executing); - set_running (this, ptid, running); + set_internal_state (this, ptid, internal_state); + set_state (this, ptid, state); return thread; } @@ -2959,26 +2965,29 @@ remote_target::remote_add_thread (ptid_t ptid, bool running, bool executing, It may be the first time we hear about such thread, so take the opportunity to add it to GDB's thread list. In case this is the first time we're noticing its corresponding inferior, add it to - GDB's inferior list as well. EXECUTING indicates whether the - thread is (internally) executing or stopped. */ + GDB's inferior list as well. INTERNAL_STATE indicates whether the + thread is internally running or stopped. */ void -remote_target::remote_notice_new_inferior (ptid_t currthread, bool executing) +remote_target::remote_notice_new_inferior (ptid_t currthread, + thread_int_state internal_state) { /* In non-stop mode, we assume new found threads are (externally) running until proven otherwise with a stop reply. In all-stop, we can only get here if all threads are stopped. */ - bool running = target_is_non_stop_p (); + thread_state state = (target_is_non_stop_p () + ? THREAD_RUNNING + : THREAD_STOPPED); /* 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. */ thread_info *tp = this->find_thread (currthread); - if (tp != NULL && tp->state == THREAD_EXITED) + if (tp != NULL && tp->state () == THREAD_EXITED) { /* We're seeing an event on a thread id we knew had exited. This has to be a new thread reusing the old id. Add it. */ - remote_add_thread (currthread, running, executing, false); + remote_add_thread (currthread, state, internal_state, false); return; } @@ -3000,7 +3009,7 @@ remote_target::remote_notice_new_inferior (ptid_t currthread, bool executing) else { thread_info *thr - = remote_add_thread (currthread, running, executing, false); + = remote_add_thread (currthread, state, internal_state, false); switch_to_thread (thr); } return; @@ -3031,7 +3040,7 @@ remote_target::remote_notice_new_inferior (ptid_t currthread, bool executing) /* This is really a new thread. Add it. */ thread_info *new_thr - = remote_add_thread (currthread, running, executing, false); + = remote_add_thread (currthread, state, internal_state, false); /* If we found a new inferior, let the common code do whatever it needs to with it (e.g., read shared libraries, insert @@ -3042,7 +3051,7 @@ remote_target::remote_notice_new_inferior (ptid_t currthread, bool executing) struct remote_state *rs = get_remote_state (); if (!rs->starting_up) - notice_new_inferior (new_thr, executing, 0); + notice_new_inferior (new_thr, internal_state, 0); } } } @@ -4363,12 +4372,14 @@ remote_target::update_thread_list () if (item.ptid != null_ptid) { /* In non-stop mode, we assume new found threads are - executing until proven otherwise with a stop reply. - In all-stop, we can only get here if all threads are + running until proven otherwise with a stop reply. In + all-stop, we can only get here if all threads are stopped. */ - bool executing = target_is_non_stop_p (); + thread_int_state internal_state = (target_is_non_stop_p () + ? THREAD_INT_RUNNING + : THREAD_INT_STOPPED); - remote_notice_new_inferior (item.ptid, executing); + remote_notice_new_inferior (item.ptid, internal_state); thread_info *tp = this->find_thread (item.ptid); remote_thread_info *info = get_remote_thread_info (tp); @@ -4982,8 +4993,8 @@ remote_target::process_initial_stop_replies (int from_tty) || ws.sig () != GDB_SIGNAL_0) evthread->set_pending_waitstatus (ws); - set_executing (this, event_ptid, false); - set_running (this, event_ptid, false); + set_internal_state (this, event_ptid, THREAD_INT_STOPPED); + set_state (this, event_ptid, THREAD_STOPPED); get_remote_thread_info (evthread)->set_not_resumed (); } @@ -4996,7 +5007,7 @@ remote_target::process_initial_stop_replies (int from_tty) if (non_stop) { thread_info *thread = any_live_thread_of_inferior (inf); - notice_new_inferior (thread, thread->state == THREAD_RUNNING, + notice_new_inferior (thread, thread->state () == THREAD_RUNNING, from_tty); } } @@ -5038,8 +5049,8 @@ remote_target::process_initial_stop_replies (int from_tty) first = thread; if (!non_stop) - thread->set_running (false); - else if (thread->state != THREAD_STOPPED) + thread->set_state (THREAD_STOPPED); + else if (thread->state () != THREAD_STOPPED) continue; if (selected == nullptr && thread->has_pending_waitstatus ()) @@ -6585,7 +6596,7 @@ remote_target::follow_fork (inferior *child_inf, ptid_t child_ptid, void remote_target::follow_clone (ptid_t child_ptid) { - remote_add_thread (child_ptid, false, false, false); + remote_add_thread (child_ptid, THREAD_STOPPED, THREAD_INT_STOPPED, false); } /* Target follow-exec function for remote targets. Save EXECD_PATHNAME @@ -6693,7 +6704,8 @@ extended_remote_target::attach (const char *args, int from_tty) /* Add the main thread to the thread list. We add the thread silently in this case (the final true parameter). */ - thread_info *thr = remote_add_thread (curr_ptid, true, true, true); + thread_info *thr = remote_add_thread (curr_ptid, THREAD_RUNNING, + THREAD_INT_RUNNING, true); switch_to_thread (thr); } @@ -8571,7 +8583,7 @@ remote_target::process_stop_reply (stop_reply_up stop_reply, && status->kind () != TARGET_WAITKIND_SIGNALLED && status->kind () != TARGET_WAITKIND_NO_RESUMED) { - remote_notice_new_inferior (ptid, false); + remote_notice_new_inferior (ptid, THREAD_INT_STOPPED); /* Expedited registers. */ if (!stop_reply->regcache.empty ()) @@ -8677,7 +8689,7 @@ static ptid_t first_remote_resumed_thread (remote_target *target) { for (thread_info *tp : all_non_exited_threads (target, minus_one_ptid)) - if (tp->resumed ()) + if (tp->internal_state () != THREAD_INT_STOPPED) return tp->ptid; return null_ptid; } diff --git a/gdb/sol-thread.c b/gdb/sol-thread.c index ae1e5c07457..3c7f0d3d353 100644 --- a/gdb/sol-thread.c +++ b/gdb/sol-thread.c @@ -451,7 +451,7 @@ sol_thread_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus, if (rtnval.tid_p ()) { thread_info *thr = current_inferior ()->find_thread (rtnval); - if (thr == NULL || thr->state == THREAD_EXITED) + if (thr == NULL || thr->state () == THREAD_EXITED) { process_stratum_target *proc_target = current_inferior ()->process_target (); @@ -997,7 +997,7 @@ sol_update_thread_list_callback (const td_thrhandle_t *th, void *ignored) ptid_t ptid = ptid_t (current_inferior ()->pid, 0, ti.ti_tid); thread_info *thr = current_inferior ()->find_thread (ptid); - if (thr == NULL || thr->state == THREAD_EXITED) + if (thr == NULL || thr->state () == THREAD_EXITED) { process_stratum_target *proc_target = current_inferior ()->process_target (); diff --git a/gdb/target.c b/gdb/target.c index 522bed8e939..c55c0878c6b 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -2653,10 +2653,10 @@ target_resume (ptid_t scope_ptid, int step, enum gdb_signal signal) current_inferior ()->top_target ()->resume (scope_ptid, step, signal); registers_changed_ptid (curr_target, scope_ptid); - /* We only set the internal executing state here. The user/frontend - running state is set at a higher level. This also clears the - thread's stop_pc as side effect. */ - set_executing (curr_target, scope_ptid, true); + /* We only set the internal state here. The user/frontend state is + set at a higher level. This also clears the thread's stop_pc as + side effect. */ + set_internal_state (curr_target, scope_ptid, THREAD_INT_RUNNING); clear_inline_frame_state (curr_target, scope_ptid); if (target_can_async_p ()) @@ -3805,9 +3805,10 @@ target_pass_ctrlc (void) for (thread_info *thr : inf->non_exited_threads ()) { - /* A thread can be THREAD_STOPPED and executing, while - running an infcall. */ - if (thr->state == THREAD_RUNNING || thr->executing ()) + /* A thread can be externally THREAD_STOPPED and internally + THREAD_INT_RUNNING, while running an infcall. */ + if (thr->state () == THREAD_RUNNING + || thr->internal_state () == THREAD_INT_RUNNING) { /* We can get here quite deep in target layers. Avoid switching thread context or anything that would diff --git a/gdb/thread-iter.h b/gdb/thread-iter.h index abd7daff1f8..4463aaf37a6 100644 --- a/gdb/thread-iter.h +++ b/gdb/thread-iter.h @@ -151,7 +151,7 @@ struct non_exited_thread_filter { bool operator() (struct thread_info *thr) const { - return thr->state != THREAD_EXITED; + return thr->state () != THREAD_EXITED; } }; diff --git a/gdb/thread.c b/gdb/thread.c index 0228027fb92..da45c263c92 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -223,23 +223,13 @@ set_thread_exited (thread_info *tp, std::optional exit_code, if (thread_is_in_step_over_chain (tp)) global_thread_step_over_chain_remove (tp); - if (tp->state != THREAD_EXITED) + if (tp->state () != THREAD_EXITED) { - process_stratum_target *proc_target = tp->inf->process_target (); - - /* Some targets unpush themselves from the inferior's target stack before - clearing the inferior's thread list (which marks all threads as exited, - and therefore leads to this function). In this case, the inferior's - process target will be nullptr when we arrive here. - - See also the comment in inferior::unpush_target. */ - if (proc_target != nullptr) - proc_target->maybe_remove_resumed_with_pending_wait_status (tp); - notify_thread_exited (tp, exit_code, silent); /* Tag it as exited. */ - tp->state = THREAD_EXITED; + tp->set_state (THREAD_EXITED); + tp->set_internal_state (THREAD_INT_EXITED); /* Clear breakpoints, etc. associated with this thread. */ clear_thread_inferior_resources (tp); @@ -373,34 +363,50 @@ thread_info::deletable () const /* See gdbthread.h. */ void -thread_info::set_executing (bool executing) -{ - m_executing = executing; - if (executing) - this->clear_stop_pc (); -} - -/* See gdbthread.h. */ - -void -thread_info::set_resumed (bool resumed) +thread_info::set_internal_state (thread_int_state state) { - if (resumed == m_resumed) + if (m_internal_state == state) return; - process_stratum_target *proc_target = this->inf->process_target (); - - /* If we transition from resumed to not resumed, we might need to remove - the thread from the resumed threads with pending statuses list. */ - if (!resumed) - proc_target->maybe_remove_resumed_with_pending_wait_status (this); + if (state == THREAD_INT_RUNNING) + this->clear_stop_pc (); - m_resumed = resumed; + if (state == THREAD_INT_RESUMED_PENDING_STATUS) + gdb_assert (this->has_pending_waitstatus ()); + else if (state == THREAD_INT_RUNNING) + gdb_assert (!this->has_pending_waitstatus ()); - /* If we transition from not resumed to resumed, we might need to add + /* If we transition from resumed-pending-status to another state, we + might need to remove the thread from the resumed threads with + pending statuses list. Conversely, if we transition to + resumed-pending-status from another state, we might need to add the thread to the resumed threads with pending statuses list. */ - if (resumed) - proc_target->maybe_add_resumed_with_pending_wait_status (this); + if (state == THREAD_INT_RESUMED_PENDING_STATUS + || m_internal_state == THREAD_INT_RESUMED_PENDING_STATUS) + { + process_stratum_target *proc_target = this->inf->process_target (); + + /* We need the proc_target NULL checks below, because some + targets unpush themselves from the inferior's target stack + before clearing the inferior's thread list (which marks all + threads as exited, and therefore leads to this function). In + this case, the inferior's process target will be nullptr when + we arrive here. See also the comment in + inferior::unpush_target. */ + + if (state != THREAD_INT_RESUMED_PENDING_STATUS && proc_target != nullptr) + proc_target->maybe_remove_resumed_with_pending_wait_status (this); + + /* Note maybe_remove_resumed_with_pending_wait_status internally + reads this state. Thus it must be updated after the call + above, and before the call below. */ + m_internal_state = state; + + if (state == THREAD_INT_RESUMED_PENDING_STATUS && proc_target != nullptr) + proc_target->maybe_add_resumed_with_pending_wait_status (this); + } + else + m_internal_state = state; } /* See gdbthread.h. */ @@ -409,12 +415,13 @@ void thread_info::set_pending_waitstatus (const target_waitstatus &ws) { gdb_assert (!this->has_pending_waitstatus ()); + /* Doesn't make sense to set a pending status on an exited or + running thread. */ + gdb_assert (this->internal_state () == THREAD_INT_STOPPED + || this->internal_state () == THREAD_INT_RESUMED_PENDING_STATUS); m_suspend.waitstatus = ws; m_suspend.waitstatus_pending_p = 1; - - process_stratum_target *proc_target = this->inf->process_target (); - proc_target->maybe_add_resumed_with_pending_wait_status (this); } /* See gdbthread.h. */ @@ -424,9 +431,6 @@ thread_info::clear_pending_waitstatus () { gdb_assert (this->has_pending_waitstatus ()); - process_stratum_target *proc_target = this->inf->process_target (); - proc_target->maybe_remove_resumed_with_pending_wait_status (this); - m_suspend.waitstatus_pending_p = 0; } @@ -435,8 +439,8 @@ thread_info::clear_pending_waitstatus () void thread_info::set_thread_options (gdb_thread_options thread_options) { - gdb_assert (this->state != THREAD_EXITED); - gdb_assert (!this->executing ()); + gdb_assert (this->state () != THREAD_EXITED); + gdb_assert (this->internal_state () == THREAD_INT_STOPPED); if (m_thread_options == thread_options) return; @@ -682,30 +686,30 @@ any_thread_of_inferior (inferior *inf) thread_info * any_live_thread_of_inferior (inferior *inf) { - struct thread_info *curr_tp = NULL; - struct thread_info *tp_executing = NULL; + thread_info *curr_tp = NULL; + thread_info *tp_running = NULL; gdb_assert (inf != NULL && inf->pid != 0); - /* Prefer the current thread if it's not executing. */ + /* Prefer the current thread if it's stopped. */ if (inferior_ptid != null_ptid && current_inferior () == inf) { - /* If the current thread is dead, forget it. If it's not - executing, use it. Otherwise, still choose it (below), but - only if no other non-executing thread is found. */ + /* If the current thread is dead, forget it. If it's stopped, + use it. Otherwise, still choose it (below), but only if no + other running thread is found. */ curr_tp = inferior_thread (); - if (curr_tp->state == THREAD_EXITED) + if (curr_tp->internal_state () == THREAD_INT_EXITED) curr_tp = NULL; - else if (!curr_tp->executing ()) + else if (curr_tp->internal_state () != THREAD_INT_RUNNING) return curr_tp; } for (thread_info *tp : inf->non_exited_threads ()) { - if (!tp->executing ()) + if (tp->internal_state () != THREAD_INT_RUNNING) return tp; - tp_executing = tp; + tp_running = tp; } /* If both the current thread and all live threads are executing, @@ -713,15 +717,15 @@ any_live_thread_of_inferior (inferior *inf) if (curr_tp != NULL) return curr_tp; - /* Otherwise, just return an executing thread, if any. */ - return tp_executing; + /* Otherwise, just return a running thread, if any. */ + return tp_running; } /* Return true if TP is an active thread. */ static bool thread_alive (thread_info *tp) { - if (tp->state == THREAD_EXITED) + if (tp->state () == THREAD_EXITED) return false; /* Ensure we're looking at the right target stack. */ @@ -773,7 +777,7 @@ void delete_exited_threads (void) { for (thread_info *tp : all_threads_safe ()) - if (tp->state == THREAD_EXITED) + if (tp->state () == THREAD_EXITED) delete_thread (tp); } @@ -852,43 +856,6 @@ thread_change_ptid (process_stratum_target *targ, gdb::observers::thread_ptid_changed.notify (targ, old_ptid, new_ptid); } -/* See gdbthread.h. */ - -void -set_resumed (process_stratum_target *targ, ptid_t ptid, bool resumed) -{ - for (thread_info *tp : all_non_exited_threads (targ, ptid)) - tp->set_resumed (resumed); -} - -/* Helper for set_running, that marks one thread either running or - stopped. */ - -static bool -set_running_thread (struct thread_info *tp, bool running) -{ - bool started = false; - - if (running && tp->state == THREAD_STOPPED) - started = true; - tp->state = running ? THREAD_RUNNING : THREAD_STOPPED; - - threads_debug_printf ("thread: %s, running? %d%s", - tp->ptid.to_string ().c_str (), running, - (started ? " (started)" : "")); - - if (!running) - { - /* If the thread is now marked stopped, remove it from - the step-over queue, so that we don't try to resume - it until the user wants it to. */ - if (thread_is_in_step_over_chain (tp)) - global_thread_step_over_chain_remove (tp); - } - - return started; -} - /* Notify interpreters and observers that the target was resumed. */ static void @@ -905,41 +872,73 @@ notify_target_resumed (ptid_t ptid) /* See gdbthread.h. */ -void -thread_info::set_running (bool running) +thread_state +thread_info::set_state (thread_state state, + bool suppress_notification) { - if (set_running_thread (this, running)) - notify_target_resumed (this->ptid); + thread_state prev_state = m_state; + + if (prev_state == state) + return prev_state; + + threads_debug_printf ("thread: %s, %s -> %s", + this->ptid.to_string ().c_str (), + thread_state_string (m_state), + thread_state_string (state)); + + m_state = state; + + switch (m_state) + { + case THREAD_EXITED: + break; + + case THREAD_STOPPED: + /* If the thread is now marked stopped, remove it from + the step-over queue, so that we don't try to resume + it until the user wants it to. */ + if (thread_is_in_step_over_chain (this)) + global_thread_step_over_chain_remove (this); + break; + + case THREAD_RUNNING: + if (!suppress_notification) + notify_target_resumed (this->ptid); + break; + } + + return prev_state; } void -set_running (process_stratum_target *targ, ptid_t ptid, bool running) +set_state (process_stratum_target *targ, ptid_t ptid, thread_state state) { /* We try not to notify the observer if no thread has actually - changed the running state -- merely to reduce the number of + changed its public state -- merely to reduce the number of messages to the MI frontend. A frontend is supposed to handle multiple *running notifications just fine. */ - bool any_started = false; + bool any_changed = false; for (thread_info *tp : all_non_exited_threads (targ, ptid)) - if (set_running_thread (tp, running)) - any_started = true; + if (tp->set_state (state, true) != state) + any_changed = true; - if (any_started) + if (any_changed && state == THREAD_RUNNING) notify_target_resumed (ptid); } void -set_executing (process_stratum_target *targ, ptid_t ptid, bool executing) +set_internal_state (process_stratum_target *targ, ptid_t ptid, + thread_int_state state) { for (thread_info *tp : all_non_exited_threads (targ, ptid)) - tp->set_executing (executing); + tp->set_internal_state (state); /* It only takes one running thread to spawn more threads. */ - if (executing) + if (state == THREAD_INT_RUNNING) targ->threads_executing = true; /* Only clear the flag if the caller is telling us everything is - stopped. */ + stopped or dead. */ else if (minus_one_ptid == ptid) targ->threads_executing = false; } @@ -964,14 +963,41 @@ set_stop_requested (process_stratum_target *targ, ptid_t ptid, bool stop) gdb::observers::thread_stop_requested.notify (ptid); } +/* Map INT_STATE to a user state. */ + +static thread_state +state_from_int_state (thread_int_state int_state) +{ + switch (int_state) + { + case THREAD_INT_RUNNING: + case THREAD_INT_RESUMED_PENDING_STATUS: + return THREAD_RUNNING; + case THREAD_INT_STOPPED: + return THREAD_STOPPED; + case THREAD_INT_EXITED: + return THREAD_EXITED; + } + + gdb_assert_not_reached ("unknown thread_int_state: %d", int_state); +} + +/* See gdbthread.h. Note this is a friend of thread_info so that it + can access the thread_info::set_state overload that lets us + suppress the target_resumed notification. */ + void finish_thread_state (process_stratum_target *targ, ptid_t ptid) { bool any_started = false; for (thread_info *tp : all_non_exited_threads (targ, ptid)) - if (set_running_thread (tp, tp->executing ())) - any_started = true; + { + thread_state new_state = state_from_int_state (tp->internal_state ()); + thread_state prev_state = tp->set_state (new_state, true); + if (prev_state != new_state && new_state == THREAD_RUNNING) + any_started = true; + } if (any_started) notify_target_resumed (ptid); @@ -989,7 +1015,7 @@ validate_registers_access (void) thread_info *tp = inferior_thread (); /* Don't try to read from a dead thread. */ - if (tp->state == THREAD_EXITED) + if (tp->state () == THREAD_EXITED) error (_("The current thread has terminated")); /* ... or from a spinning thread. FIXME: This isn't actually fully @@ -997,7 +1023,7 @@ validate_registers_access (void) at the prompt) when a thread is not executing for some internal reason, but is marked running from the user's perspective. E.g., the thread is waiting for its turn in the step-over queue. */ - if (tp->executing ()) + if (tp->internal_state () == THREAD_INT_RUNNING) { /* If we are replaying with the record-full subsystem, even though the thread is executing, it is always safe to read from it since @@ -1017,11 +1043,11 @@ can_access_registers_thread (thread_info *thread) return false; /* Don't try to read from a dead thread. */ - if (thread->state == THREAD_EXITED) + if (thread->state () == THREAD_EXITED) return false; /* ... or from a spinning thread. FIXME: see validate_registers_access. */ - if (thread->executing ()) + if (thread->internal_state () == THREAD_INT_RUNNING) { /* See validate_registers_access. */ if (!record_full_is_replaying ()) @@ -1105,14 +1131,14 @@ should_print_thread (const char *requested_threads, return false; } - if (thr->state == THREAD_EXITED) + if (thr->state () == THREAD_EXITED) return false; - bool is_stopped = (thr->state == THREAD_STOPPED); + bool is_stopped = (thr->state () == THREAD_STOPPED); if (opts.show_stopped_threads && is_stopped) return true; - bool is_running = (thr->state == THREAD_RUNNING); + bool is_running = (thr->state () == THREAD_RUNNING); if (opts.show_running_threads && is_running) return true; @@ -1203,7 +1229,7 @@ do_print_thread (ui_out *uiout, const char *requested_threads, uiout->field_string ("target-id", thread_target_id_str (tp)); } - if (tp->state == THREAD_RUNNING) + if (tp->state () == THREAD_RUNNING) uiout->text ("(running)\n"); else { @@ -1219,7 +1245,7 @@ do_print_thread (ui_out *uiout, const char *requested_threads, { const char *state = "stopped"; - if (tp->state == THREAD_RUNNING) + if (tp->state () == THREAD_RUNNING) state = "running"; uiout->field_string ("state", state); } @@ -1330,7 +1356,7 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, for (inferior *inf : all_inferiors ()) for (thread_info *tp : inf->threads ()) { - if (tp == current_thread && tp->state == THREAD_EXITED) + if (tp == current_thread && tp->state () == THREAD_EXITED) current_exited = true; print_thread (uiout, requested_threads, opts, global_ids, pid, @@ -1495,7 +1521,7 @@ scoped_restore_current_thread::restore () changed, so we have to recheck it here. */ if (inferior_ptid != null_ptid && m_was_stopped - && m_thread->state == THREAD_STOPPED + && m_thread->state () == THREAD_STOPPED && target_has_registers () && target_has_stack () && target_has_memory ()) @@ -1518,7 +1544,7 @@ scoped_restore_current_thread::scoped_restore_current_thread () { m_thread = thread_info_ref::new_reference (inferior_thread ()); - m_was_stopped = m_thread->state == THREAD_STOPPED; + m_was_stopped = m_thread->state () == THREAD_STOPPED; save_selected_frame (&m_selected_frame_id, &m_selected_frame_level); } } @@ -1964,7 +1990,7 @@ thread_command (const char *tidstr, int from_tty) { struct thread_info *tp = inferior_thread (); - if (tp->state == THREAD_EXITED) + if (tp->state () == THREAD_EXITED) gdb_printf (_("[Current thread is %s (%s) (exited)]\n"), print_thread_id (tp), target_pid_to_str (inferior_ptid).c_str ()); @@ -2122,7 +2148,7 @@ print_selected_thread_frame (struct ui_out *uiout, } } - if (tp->state == THREAD_RUNNING) + if (tp->state () == THREAD_RUNNING) { if (selection & USER_SELECTED_THREAD) uiout->text ("(running)\n"); @@ -2167,7 +2193,7 @@ update_threads_executing (void) for (thread_info *tp : inf->non_exited_threads ()) { - if (tp->executing ()) + if (tp->internal_state () == THREAD_INT_RUNNING) { targ->threads_executing = true; return; @@ -2221,6 +2247,29 @@ thread_state_string (enum thread_state state) gdb_assert_not_reached ("unknown thread state"); } +/* See gdbthread.h. */ + +const char * +thread_int_state_string (thread_int_state state) +{ + switch (state) + { + case THREAD_INT_STOPPED: + return "INT_STOPPED"; + + case THREAD_INT_RUNNING: + return "INT_RUNNING"; + + case THREAD_INT_RESUMED_PENDING_STATUS: + return "INT_RESUMED_PENDING_STATUS"; + + case THREAD_INT_EXITED: + return "INT_EXITED"; + } + + gdb_assert_not_reached ("unknown thread internal state"); +} + /* Return a new value for the selected thread's id. Return a value of 0 if no thread is selected. If GLOBAL is true, return the thread's global number. Otherwise return the per-inferior number. */ diff --git a/gdb/top.c b/gdb/top.c index 25a2afe09c8..469313db22f 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -586,7 +586,7 @@ execute_command (const char *p, int from_tty) we just finished executing did not resume the inferior's execution. If it did resume the inferior, we will do that check after the inferior stopped. */ - if (has_stack_frames () && inferior_thread ()->state != THREAD_RUNNING) + if (has_stack_frames () && inferior_thread ()->state () != THREAD_RUNNING) check_frame_language_change (); cleanup_if_error.release ();