From: Andrew Burgess <andrew.burgess@embecosm.com>
To: Simon Marchi <simon.marchi@polymtl.ca>
Cc: gdb-patches@sourceware.org
Subject: Re: [PATCH 3/3] gdb: make thread_info executing and resumed state more consistent
Date: Wed, 29 Sep 2021 09:09:58 +0100 [thread overview]
Message-ID: <20210929080958.GJ1900093@embecosm.com> (raw)
In-Reply-To: <36212932-3978-3caa-30aa-b426a1e20bc8@polymtl.ca>
* Simon Marchi <simon.marchi@polymtl.ca> [2021-09-23 13:14:33 -0400]:
> > I did think about this, but I guess I'm not quite sure how this ends
> > up being any simpler than the two booleans with rules.
> >
> > My assumption is that we'd want to keep the API as
> > executing/set_executing and resumed/set_resumed as this represents the
> > questions we want to ask.
> >
> > As such something like set_executing would become:
> >
> > void
> > thread_info::set_executing (bool e)
> > {
> > if (m_state == RESUMED_AND_TARGET_RESUMED)
> > return;
> >
> > gdb_assert (m_state == RESUMED_BUT_NOT_TARGET_RESUMED);
> >
> > m_state = RESUMED_AND_TARGET_RESUMED;
> > }
> >
> > Which doesn't feel any less complex to me.
> >
> > Of course, we could change the API so the user sets the state
> > directly, like:
> >
> > void
> > thread_info_::set_executing_resumed_state (enum state_type s)
> > {
> > /* ... */
> > }
> >
> > But then we'd _still_ end up having to assert the correct state
> > transitions.
>
> The later is what I was thinking.
>
> What do you mean "assert the correct state transitions"? With the enum
> all possible transitions are valid. I'm not sure if
> RESUMED_AND_TARGET_RESUMED -> RESUMED_BUT_NOT_TARGET_RESUMED is actually
> used, but it's not something prevented by your patch either.
The RESUMED_AND_TARGET_RESUMED -> RESUMED_BUT_NOT_TARGET_RESUMED
transition is definitely used, and is, I believe required with my
patch.
I don't know if there are many places in GDB that we actually sit in
the RESUMED_BUT_NOT_TARGET_RESUMED state for long (that would
currently be resumed=true,executing=false, right?) but my intention is
that we have to go back through that state, i.e. we can't set resumed
to false while executing is true.
From you original proposed states:
enum class thread_resumption_state
{
NOT_RESUMED, /* 1 */
RESUMED_BUT_NOT_TARGET_RESUMED, /* 2 */
RESUMED_AND_TARGET_RESUMED, /* 3 */
};
Under the current scheme the transition order should always be:
1 -> 2 -> 3 -> 2 -> 1
Anything else should trigger an assertion.
Ideally, if I transitioned to the new scheme I'd (at least initially)
want to keep assertions that force that transition scheme, so no
transitions 1->3 or 3->1.
However, there are places where set_resumed and set_executing are
right next to each other.
So maybe they would be merged into a single set_state call, which
means the 1->3 or 3->1 transitions would be legal. So, then we remove
the asserts and allow any state transitions.
But then, if we have a bug which GDB skips the logic that used to be
responsible for "set_resumed" we'd never know, right? When we hit the
old set_executing call, this will now just set the state as if the
resumed had happened...
...this seems less good to me.
I guess given you've said you're not against what I have then for now
I'd prefer to stick with the separate resumed/executing. We can
always change later - I think it would be best done in a separate
patch anyway - I just want to try and explain my thinking.
Thanks for all your other feedback. I'll go through and try and
address all your points and post a new version of the patch.
Thanks,
Andrew
>
> Note that I'm still ok with how you are doing things, I'm just
> discussing this to know whether we would want this as follow-up work or
> not (if somebody is interested in implementing it).
>
> > - The add_thread* calls now take a flag, and threads can be started
> > as resumed or non-resumed.
> >
> > - Some of the state changes, like in ::follow_exec, are now pushed
> > back to where the thread is created, as a result, some places where
> > in V1 I was changing the state, I'm now asserting the state.
> >
> > - Added some asserts to clear_stop_pc
> >
> > One big consequence of this patch is that we now expect that threads
> > are created in the "correct" resumed/non-resumed state. A place where
> > this is definitely now wrong is during the initial creation of a
> > process to debug - threads are created in the default resumed state,
> > which is not correct.
> >
> > I've fixed this for the native Linux and remote targets, but for all
> > other targets this will likely be incorrect.
> >
> > As I'm not able to test these targets I made the choice to, instead of
> > asserting that GDB has the correct state, fix the state. This can be
> > seen in gdb_startup_inferior (fork-child.c) and one in run_command_1
> > (infcmd.c), where I've added comments about this.
> >
> > I don't really see a way around this. If I make the default thread
> > state be non-resumed then the inferior creation code would work, but
> > any target specific code to handle creating new threads would
> > potentially be wrong (as threads would be created non-resumed when
> > they should be resumed).
>
> I'm not a fan of the default parameter values in add_thread and friends.
> I'd prefer having to pass an explicit value at each call site (there
> aren't that many), that would force thinking about what to pass at each
> call site.
>
> For targets you can't build and test... I'd say do a best effort to
> update them (update calls to add_thread* functions) and then use
> assertions. I much prefer a clear and consistent set of
> preconditions/postconditions to the target interface than a state where
> some targets do one thing and other targets do something else. That's
> easier to work with in the long run. And ideally, these would be
> documented in the target interface. For example, the documentation for
> target_ops::attach should say "threads created by the target during
> attach should be marked as (resumed|non-resumed)". If somebody hits one
> of your assertions, because a target is not respecting this
> postcondition, it will be quite obvious.
>
>
> > @@ -1172,6 +1179,11 @@ follow_exec (ptid_t ptid, const char *exec_file_target)
> > gdb_assert (current_inferior () == inf);
> > gdb_assert (current_program_space == inf->pspace);
> >
> > + /* The inferior (and so thread) might have changed depending on which
> > + path we took through the above code. However, the currently selected
> > + thread should not be in a resumed state. */
> > + gdb_assert (!inferior_thread ()->resumed ());
>
> Here, I suggested using a loop over all of current inferior's threads.
> It sounds a bit silly, but I'm thinking that some weird platform some
> day might have processes with two threads when coming out of an exec.
> Alternatively, we could assert that the current inferior contains
> exactly one thread.
>
> > +
> > /* Attempt to open the exec file. SYMFILE_DEFER_BP_RESET is used
> > because the proper displacement for a PIE (Position Independent
> > Executable) main symbol file will only be computed by
> > @@ -2100,6 +2112,52 @@ internal_resume_ptid (int user_step)
> > return user_visible_resume_ptid (user_step);
> > }
> >
> > +/* Before calling into target code to set inferior threads executing we
> > + must mark all threads as resumed. If an exception is thrown while
> > + trying to set the threads executing then we should mark the threads as
> > + non-resumed.
> > +
> > + Create an instance of this struct before */
>
> Seems like this comment was not finished.
>
> > +struct scoped_mark_thread_resumed
> > +{
> > + /* Constructor. All threads matching PTID will be marked as resumed. */
> > + scoped_mark_thread_resumed (process_stratum_target *targ, ptid_t ptid)
> > + : m_target (targ), m_ptid (ptid)
> > + {
> > + gdb_assert (m_target != nullptr);
> > + set_resumed (m_target, m_ptid, true);
> > + }
> > +
> > + /* Destructor. If M_TARGET is not nullptr then mark all threads matching
> > + M_PTID as no longer being resumed. The expectation is that on the
> > + exception path this will be called with M_TARGET still set to a valid
> > + target. If however, the threads were successfully set executing then
> > + this->commit() will have been called, and M_TARGET will now be
> > + nullptr. */
>
> I'd say "If the object was not committed" instead of "If M_TARGET is not
> nullptr". M_TARGET being nullptr to represent the commit is an internal
> detail, and this comment is supposed to describe the interface.
>
> > + ~scoped_mark_thread_resumed ()
> > + {
> > + if (m_target != nullptr)
> > + set_resumed (m_target, m_ptid, false);
> > + }
> > +
> > + /* Called once all of the threads have successfully be set executing (by
> > + calling into the target code). Clears M_TARGET as an indication that,
> > + when this object is destructed, we should leave all matching threads
> > + as being marked resumed. */
>
> Same idea here. You could put the "Clear M_TARGET..." part inside the
> method body (to describe the implementation), while the comment above
> the method can describe the interface (e.g. "Calling commit makes it so
> threads are left as resumed on destruction.").
>
> Simon
next prev parent reply other threads:[~2021-09-29 8:10 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-08-30 20:03 [PATCH 0/3] Changes to thread state tracking Andrew Burgess
2021-08-30 20:03 ` [PATCH 1/3] gdb: make thread_info::executing private Andrew Burgess
2021-09-01 13:53 ` Simon Marchi via Gdb-patches
2021-09-07 11:46 ` Andrew Burgess
2021-08-30 20:03 ` [PATCH 2/3] gdb: make thread_suspend_state::stop_pc optional Andrew Burgess
2021-09-01 14:23 ` Simon Marchi via Gdb-patches
2021-09-07 13:21 ` Andrew Burgess
2021-09-07 14:10 ` Simon Marchi via Gdb-patches
2021-09-08 9:50 ` Andrew Burgess
2021-08-30 20:03 ` [PATCH 3/3] gdb: make thread_info executing and resumed state more consistent Andrew Burgess
2021-09-01 15:09 ` Simon Marchi via Gdb-patches
2021-09-22 11:21 ` Andrew Burgess
2021-09-23 17:14 ` Simon Marchi via Gdb-patches
2021-09-29 8:09 ` Andrew Burgess [this message]
2021-10-08 19:33 ` Simon Marchi via Gdb-patches
2022-01-13 18:34 ` [PATCHv3] " Andrew Burgess via Gdb-patches
2022-01-14 17:10 ` Simon Marchi via Gdb-patches
2022-02-24 15:52 ` Andrew Burgess via Gdb-patches
2022-03-03 19:42 ` Simon Marchi via Gdb-patches
2022-03-07 7:39 ` Aktemur, Tankut Baris via Gdb-patches
2022-03-30 9:19 ` Andrew Burgess via Gdb-patches
2022-04-21 16:45 ` [PATCHv4 0/2] Make " Andrew Burgess via Gdb-patches
2022-04-21 16:45 ` [PATCHv4 1/2] gdb: add some additional thread status debug output Andrew Burgess via Gdb-patches
2022-04-21 20:35 ` Lancelot SIX via Gdb-patches
2022-04-22 17:50 ` Andrew Burgess via Gdb-patches
2022-05-03 14:04 ` Andrew Burgess via Gdb-patches
2022-04-21 16:45 ` [PATCHv4 2/2] gdb: make thread_info executing and resumed state more consistent Andrew Burgess via Gdb-patches
2022-04-26 13:28 ` Nidal Faour via Gdb-patches
2022-08-08 11:04 ` [PATCHv4 0/2] Make " Craig Blackmore
2022-08-08 12:01 ` Andrew Burgess via Gdb-patches
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210929080958.GJ1900093@embecosm.com \
--to=andrew.burgess@embecosm.com \
--cc=gdb-patches@sourceware.org \
--cc=simon.marchi@polymtl.ca \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox