[lldb-dev] Stop/Resume process, interrupting I/O
Mario Zechner
badlogicgames at gmail.com
Mon Oct 27 13:43:20 PDT 2014
Yes, that all makes sense to me. It will somewhat complicate the JDWP
thread logic, but i guess it will ultimately safe me quite a bit of pain.
Thanks!
On Mon, Oct 27, 2014 at 9:23 PM, Greg Clayton <gclayton at apple.com> wrote:
>
> > On Oct 27, 2014, at 12:42 PM, Mario Zechner <badlogicgames at gmail.com>
> wrote:
> >
> > 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.
>
> I would venture to say that trying to handle events on different threads
> and doing a handoff is a bad idea (race conditions, etc) and you should
> handle process events on one thread.
> >
> > 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.
>
> This what "sync" mode is for:
>
> debugger.SetAsync(false)
>
> When in this mode, any process events that resume the process will wait
> until the process stops before returning:
>
> process.Continue()
>
> This continue won't return until the process actually stops. It will
> consume all running/stopped events.
>
> But as you already have a thread that is handling events, I still say
> this is a bad idea. What we do in Xcode is have a thread that is waiting
> not only for process events, but also for other events like common things
> to do like backtraces, get frame variables, etc). So you
>
> >
> > 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.
> >
> > As always, really appreciate that you take the time to read and answer
> my walls of text.
>
> So I would say the safest thing to do is to make your event handling
> thread always handle all events. If you need the JDWP thread to do
> something, it sends a event over to the event thread and has it be handled.
> You can make your own broadcaster and then listen to it as well on the
> thread that is listening for process events. This way you don't mix and
> match. The event thread can also use that same broadcaster to send and
> event back to the JDWP thread.
>
> Something like:
>
> SBBroadcaster g_broadcaster("JDWP");
>
> enum JDWPEvents {
> eEventThreadCommand = 1u << 0,
> eJDWPThreadResponse = 1u << 1
> };
>
> int event_thread(...)
> {
> SBDebugger debugger = lldb::SBDebugger::Create();
> debugger.SetAsync (true);
> SBError error;
> uint32_t event_timeout_seconds = UINT32_MAX; // Infinite wait
> SBTarget target = debugger.CreateTarget (...)
> if (target.IsValid())
> {
> SBListener listener("event_thread.listener");
>
> SBProcess process = target.Launch (listener,
> NULL, // char const **argv,
> NULL, // char const **envp,
> NULL, // const char
> *stdin_path,
> NULL, // const char
> *stdout_path,
> NULL, // const char
> *stderr_path,
> NULL, // const char
> *working_directory,
> 0, // uint32_t
> launch_flags
> false, // bool stop_at_entry,
> error);
>
> listener.StartListeningForEvents (g_broadcaster,
> eEventThreadCommand);
>
> if (error.Success() &&
> process.IsValid() &&
> process.GetProcessID() != LLDB_INVALID_PROCESS_ID)
> {
> SBEvent event;
>
> if (listener.WaitForEvent (event_timeout_seconds, event))
> {
> if (event.BroadcasterMatchesRef(g_broadcaster))
> {
> // eEventThreadCommand
> // Do the work needed by the JDWP thread, and then
> send a response to let it know it is done...
>
> g_broadcaster.BroadcastEventByType(eJDWPThreadResponse);
> }
> else
> {
> // Process event...
> }
> }
> }
> }
> }
>
> int jdwp_thread(...)
> {
> SBListener listener("jdwp_thread.listener");
> listener.StartListeningForEvents (g_broadcaster, eEventThreadCommand);
> if (listener.WaitForEvent (event_timeout_seconds, event))
> {
> }
> }
>
>
> One thing we need to add to:
>
> SBProcess
> SBTarget::Launch (SBLaunchInfo &launch_info, SBError& error);
>
> Is the ability to set the SBListener in the SBLaunchInfo so we can specify
> an alternate listener. Do you get where I am going with this? The key is to
> listen for events and do all process control from one thread to ensure
> there are no races.
>
> Greg
>
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/lldb-dev/attachments/20141027/936e5794/attachment.html>
More information about the lldb-dev
mailing list