[lldb-dev] Stop/Resume process, interrupting I/O

Mario Zechner badlogicgames at gmail.com
Mon Oct 27 13:09:33 PDT 2014


And one more reply that didn't go to the list. Really sorry :/. Original
message, plus an edit:

The piggy backing of events is fine from my point of view as long as i can
check the interrupted flag (for which i'll try to compose a patch). My
issues stem more from the fact that i have to concurrently operate on the
process (event loop thread, JDWP thread). The "hook" breakpoints are
actually handled on the event loop thread, including the auto-resume, which
is a requirement for our JDWP implementation to work correctly. The JDWP
client shouldn't know that the process hit a "hook" breakpoint.

My problem is really this: the JDWP thread stops the event loop thread.
Next it stops the process via SBProcess::Stop (which calls Process::Halt).
Sadly, Process::Halt doesn't set the state on the process. I have to poll
events on the JDWP thread for that to happen, on the JDWP thread, until i
get a stopped (or exited/crashed/...) event. I then have to re-broadcast
those events so the event loop thread can later process them once i resume
it. I'm very worried about re-broadcasting events as i don't know what
havoc that will wreck in the LLDB internal state.

Ideally, Process::Halt (and hence SBProcess::Stop()) would set things up in
a way where i don't have to poll events on the JDWP thread. It should also
set the process state accordingly. I also noticed strange timing bugs when
calling SBProcess::Stop() while a previous SBProcess::Continue() is still
being propagated to the inferior. That's actually what causes the
eStopReasonInvalid events i talked about in another thread.

I just played around with the Python API. Turns out i've been using
SBListener::WaitForEvent incorrectly. I supplied 0 for timeout, assuming it
would return immediately. This actually throws an assertion when called via
the Python API. Our JNI wrapper of LLDB doesn't throw an assert. I guess
SBListener::PeekAtNextEvent is what i should use instead for non-blocking
event processing?

As always, really appreciate that you take the time to read and answer my
walls of text.

On Mon, Oct 27, 2014 at 7:02 PM, Greg Clayton <gclayton at apple.com> wrote:

>
> > On Oct 26, 2014, at 5:23 AM, Mario Zechner <badlogicgames at gmail.com>
> wrote:
> >
> > Sorry for the mail bomb. After some more investigation, it's the
> inferior's responsibility to deal with SIGSTOP itself, e.g. interpret and
> act upon errno == EINTR. Lucky, our runtime library already seems to take
> care of EINTR properly and supports "restartable" I/O. So i guess i
> answered question 2 myself. Progress :)
> >
> Glad you figured this out, I was about to mention EINTR and handling those
> correctly.
>
> > For question 1, i'd like to elaborate on the scenario:
> >
> > - We have one event loop thread constantly polling events from the
> process via SBListener::WaitForEvent
> > - We setup a few breakpoints in our runtime to get to know about things
> like thread creation/death and so on. When such a "hook" breakpoint is hit,
> we read whatever information we need from the inferior and then
> automatically resume the process via SBProcess:Continue. All this happens
> on the event loop thread, in response to breakpoint stop events with the
> appropriate location.
> > - We have a second thread, let's call it JDWP thread, that listens for
> JDWP commands. When a command arrives, we need to stop the inferior,
> perform the command, and resume the inferior. For this we temporarily
> disable the event loop thread (no more calls to WaitForEvent, hence no
> "Hook" breakpoint processing, hence no calls to SBProcess::Continue on the
> event loop thread), call SBProcess::Stop(), perform our command, call
> SBProcess::Continue and then reenable the event loop thread.
> >
> > This setup has one issue, which relates to my first question
> (stop/breakpoint event taken over by SBProcess::Halt and marked as
> interrupted). When we stop the event loop thread and then call
> SBProcess::Stop(), one of three things can happen:
> >
> > 1) the process was already stopped -> Process::Halt returns immediately,
> no additional events are generated
> > 2) the process wasn't stopped yet, so Process::Halt sends SIGSTOP and an
> event with stop reason eStopReasonSignal will eventually be generated and
> broadcast to the SBListener in the event loop thread
> > 3) the process wasn't stopped yet, while Process::Halt does its thing a
> stop event arrives (e.g. breakpoint) and is consumed by Process::Halt.
> Process::Halt takes over that event, marks it as interrupted then
> rebroadcasts it.
> >
> > In case 3 (breakpoint event is taken over and marked) we don't want to
> automatically resume the process. That's why we need to be able to decipher
> if the event was marked as interrupted, so we can decide whether the JDWP
> thread should actually resume the process once its done responding to the
> JDWP request.
>
> An easy way to deal with this is to take the race out by having your event
> thread do the resume and don't have your breakpoint do the auto resume.
> More generically, we do need LLDB to be able stop the auto-resume stuff
> from happening. To clarify your case #3 above: you are still getting a stop
> event, just not a eStopReasonSignal? No stop reason?
>
> If a plug-in sends a "SIGSTOP" in order to stop a process, we really
> should be not showing that to the user as the reason for the stop like we
> are now, we should be covering it up and giving a new
> eStopReasonInterrupted for a thread instead IMHO. If we did this, would
> this clear up your issues?
> >
> > Sorry for the wall of text. I feel my adventure notes here may serve
> others to navigate LLDB for similar use cases :)
> >
> > Thanks,
> > Mario
> >
> > On Sun, Oct 26, 2014 at 11:59 AM, Mario Zechner <badlogicgames at gmail.com>
> wrote:
> > Just to clarify my use of "interrupted". Of course all threads should be
> stopped upon SBProcess::Stop(). However, upon SBProcess:Resume() I/O
> operations shouldn't just return due to the SIGSTOP but continue doing what
> they did before receiving the signal.
> >
> > Thanks,
> > Mario
> >
> > On Sun, Oct 26, 2014 at 11:56 AM, Mario Zechner <badlogicgames at gmail.com>
> wrote:
> > Hi,
> >
> > i'm currently trying to understand how LLDB interrupts/resumes
> processes. To my understanding, the Process implementation sends a SIGSTOP
> to the inferior, which will stop the process. Alternatively, the process
> may be stopped (e.g. breakpoint) while Process::DoHalt is executing, in
> which case the event is marked as interrupted. I have a few questions
> regarding this:
> >
> > 1) How can i check wether an event was marked as interrupted via the
> API? SBProcess has a couple of static methods like GetStateFromEvent, but
> none of these allow me to check if the event was marked as interrupted
> > 2) SIGSTOP seems to interrupt any I/O call, e.g. getchar, listen, and so
> on. Upon a resume, these functions will simply return (e.g. returning EOF)
> instead of continuing waiting for input. Is there any way to have this not
> happen?
> >
> > Our problem is, that we need to stop/resume the process to implement
> parts of JDWP (Java debugging wire protocol). Some JDWP commands require us
> to stop the process, read some memory regions and resume the process again,
> letting the inferior think that nothing has happened. All of this should
> not interfere with normal program execution, e.g. a file read shouldn't be
> interrupted because we stopped the inferior via SBProcess:Stop().
> >
> > As always, thanks for all your help!
> >
> > ciao,
> > Mario
> >
> >
> > _______________________________________________
> > lldb-dev mailing list
> > lldb-dev at cs.uiuc.edu
> > http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/lldb-dev/attachments/20141027/3d95812e/attachment.html>


More information about the lldb-dev mailing list