Re: [non-stop] 10/10 split user/internal threads

Daniel Jacobowitz
2008-07-01T00:51:52Z

On Mon, Jun 30, 2008 at 01:08:48AM +0100, Pedro Alves wrote:
> - In non-stop mode, the current thread may exit while the
> user has it selected. Switching current thread, and restoring
> it with a cleanup is problematic in non-stop mode.

The target interface is async, the inferior program is running - but
GDB retains a single thread of control. So unless the inferior runs
while the cleanup is live, there's no problem here. I suppose it
could be trouble if you enter the expression evaluator, though?

> Now this example:
>
> - User has thread 1 selected.
> - thread 2 has an event
> - GDB switches to thread 2 to handle it
> - It was a breakpoint, and has breakpoint commands attached to it.
> - The breakpoint has several commands attached actually:
> thread 3
> print value1
> up
> print value2
> up
> print value3
> end
>
> - GDB has finished handling the event, so should restore to the
> user selected thread and frame. But, which is it now?
> thread 1, or thread 3? In all-stop mode? In non-stop mode?

IMO it's thread 3 in all-stop and thread 1 in non-stop. This is a
weird user-visible artifact, though.

> Now another example. Imagine in non-stop mode, this case:
>
> (gdb) b foo.c:100
> Breakpoint 1 ...
> (gdb) commands
> >thread 3
> >c&
> >end
> (gdb) interrupt -a
> (all threads stopped)
> (gdb) thread 2
> (gdb) c&
> (thread 2 resumes)
> (gdb) thread 1
> (gdb) print foo_c
> (gdb) print foo_b
> (gdb) pri
> (thread 2 hits breakpoint 1, and runs its commands,
> which included switching to thread 3)
> nt foo_a</enter>
>
> (note that the breakpoint was hit while the user was
> inspecting thread 1, typing a print command)
>
> To which thread should the last "print foo_a" apply to?
> My opinion is that is should apply to thread 1. Does
> anyone disagree?

Yes, in non-stop the weird behavior of scoping the "thread" command to
a commands list seems to be the only plausible choice.

> With all the above in mind, I thought of:
>
> - calling the { selected thread and frame } thing a "context".
> - having a context stack
> (The top level context being what the user/frontend
> considers current.)
>
> Instead of temporarilly switching to another thread and frame;
> execute commands in it, and restoring the selected thread and
> frame, we do:
>
> - push a new context on the context stack
> - switch the selected thread and frame in this
> new now top level context
> - execute command(s)
> which can switch thread and frame at will
> - pop context
>
> - Whenever a thread exit is detected, we go through all
> contexts and if it was the selected thread in it, invalidate
> it.

Isn't this exactly the same as using cleanups, except that there is a
way to invalidate saved cleanups?

If so, then it seems to me there is a simpler and less intrusive
solution. Put a reference count in the thread structure and increment
it when you push a cleanup. I think Vladimir added a hook that will
let us drop the reference even if the cleanup is discarded.

I don't want to proliferate cleanup-like mechanisms if we can avoid
it, the ones we have are confusing enough already :-)

> > > +/* Only safe to use this cleanup on a stopped thread, and
> > > + inferior_ptid isn't ran before running the cleanup. */
> > > +
> > > struct current_thread_cleanup
> >
> > Not sure what you mean by this comment.
> >
>
> I've changed the comment to this:
>
> /* It is only safe to use this cleanup iff inferior_ptid is alive and
> stopped, and, by if by the time it is ran, inferior_ptid represents
> the same thread, it is alive and it is stopped. */
>
> Does it make it clearer?

Does it in "by the time it is" refer to the cleanup? And then the
"it"s on the last line to "the same thread"? Pronouns are so
confusing.

I didn't look at the incremental patch, sorry - let's finish talking
about the problem first.

--
Daniel Jacobowitz
CodeSourcery