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

jingham at apple.com jingham at apple.com
Mon Oct 27 11:31:45 PDT 2014


> On Oct 27, 2014, at 11:02 AM, 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?

No, I don't think this is right.  The thread that stopped at a breakpoint should not have its stop reason changed.  That would be really confusing.  I think it is better to mark the event with Interrupted, since that is really a process wide event, and the point is you don't really even know which action on which thread caused the eventual interruption.  Indeed, there may be no thread specific action at all.  For instance on Mac OS X we could decide to use the Mach "task_suspend" to interrupt processes instead of going through the signal mechanism at all.  We don't do that because it leaves the process in a pretty shady state, whereas sending it a signal causes it to rendezvous in user space in a more consistent state.  But we could do that and in that case you would  interrupt the process but NO thread would have any specific reason.  So again, this really needs to be an attribute on the stop event itself, not the stop reasons of individual threads.

We could also introduce another stop event - an interrupted event - but right now the stop event handling is pretty simple, there's mostly just stopped, running, and exited, and any other information like restarted or interrupted are side-bits on the event that you can ask about if you need to know.  Not sure I see any great advantage to changing that.

I don't mind at some point going back and trying to cover over the Stop Reason for the thread that eventually stops.  So if we knew we sent a SIGSTOP, and saw the thread with the SIGSTOP, might be okay to change this to a StopReason of interrupted.  But of course you could have sent a SIGSTOP just as the program was getting a job control SIGSTOP, so you could still get this wrong...

Jim


>> 
>> 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
> 
> 
> _______________________________________________
> lldb-dev mailing list
> lldb-dev at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev





More information about the lldb-dev mailing list