<div dir="ltr">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.<div><br></div><div>Thanks!</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Oct 27, 2014 at 9:23 PM, Greg Clayton <span dir="ltr"><<a href="mailto:gclayton@apple.com" target="_blank">gclayton@apple.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class=""><br>
> On Oct 27, 2014, at 12:42 PM, Mario Zechner <<a href="mailto:badlogicgames@gmail.com">badlogicgames@gmail.com</a>> wrote:<br>
><br>
> 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.<br>
<br>
</span>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.<br>
<span class="">><br>
> 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.<br>
<br>
</span>This what "sync" mode is for:<br>
<br>
debugger.SetAsync(false)<br>
<br>
When in this mode, any process events that resume the process will wait until the process stops before returning:<br>
<br>
process.Continue()<br>
<br>
This continue won't return until the process actually stops. It will consume all running/stopped events.<br>
<br>
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<br>
<span class=""><br>
><br>
> 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.<br>
><br>
> As always, really appreciate that you take the time to read and answer my walls of text.<br>
<br>
</span>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.<br>
<br>
Something like:<br>
<br>
SBBroadcaster g_broadcaster("JDWP");<br>
<br>
enum JDWPEvents {<br>
eEventThreadCommand = 1u << 0,<br>
eJDWPThreadResponse = 1u << 1<br>
};<br>
<br>
int event_thread(...)<br>
{<br>
SBDebugger debugger = lldb::SBDebugger::Create();<br>
debugger.SetAsync (true);<br>
SBError error;<br>
uint32_t event_timeout_seconds = UINT32_MAX; // Infinite wait<br>
SBTarget target = debugger.CreateTarget (...)<br>
if (target.IsValid())<br>
{<br>
SBListener listener("event_thread.listener");<br>
<br>
SBProcess process = target.Launch (listener,<br>
NULL, // char const **argv,<br>
NULL, // char const **envp,<br>
NULL, // const char *stdin_path,<br>
NULL, // const char *stdout_path,<br>
NULL, // const char *stderr_path,<br>
NULL, // const char *working_directory,<br>
0, // uint32_t launch_flags<br>
false, // bool stop_at_entry,<br>
error);<br>
<br>
listener.StartListeningForEvents (g_broadcaster, eEventThreadCommand);<br>
<br>
if (error.Success() &&<br>
process.IsValid() &&<br>
process.GetProcessID() != LLDB_INVALID_PROCESS_ID)<br>
{<br>
SBEvent event;<br>
<br>
if (listener.WaitForEvent (event_timeout_seconds, event))<br>
{<br>
if (event.BroadcasterMatchesRef(g_broadcaster))<br>
{<br>
// eEventThreadCommand<br>
// Do the work needed by the JDWP thread, and then send a response to let it know it is done...<br>
g_broadcaster.BroadcastEventByType(eJDWPThreadResponse);<br>
}<br>
else<br>
{<br>
// Process event...<br>
}<br>
}<br>
}<br>
}<br>
}<br>
<br>
int jdwp_thread(...)<br>
{<br>
SBListener listener("jdwp_thread.listener");<br>
listener.StartListeningForEvents (g_broadcaster, eEventThreadCommand);<br>
if (listener.WaitForEvent (event_timeout_seconds, event))<br>
{<br>
}<br>
}<br>
<br>
<br>
One thing we need to add to:<br>
<br>
SBProcess<br>
SBTarget::Launch (SBLaunchInfo &launch_info, SBError& error);<br>
<br>
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.<br>
<span class="HOEnZb"><font color="#888888"><br>
Greg<br>
<br>
<br>
<br>
</font></span></blockquote></div><br></div>