Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement well defined window for breakpoint configuration. #313

Merged

Conversation

brownts
Copy link
Collaborator

@brownts brownts commented Mar 2, 2022

Fixes #307.

The previous implementation worked under the assumption that
breakpoint requests would be received from the client prior to the
debugger having completed it's initialization. However, if the
debugger completed initialization prior to having received breakpoint
requests from the client, those breakpoints requests would be
ignored (i.e., there was a race condition). Additionally, the
previous implementation "buffered" the receipt of the breakpoint
requests and would only process them after the debugger initialization
had completed (i.e., "debug-ready").

This change delays the sending of the "initialized" event back to the
client (until the debugger truly has completed its initialization).
As a result, there is no longer a need to buffer the breakpoint
requests. Breakpoints requests are now forced to be received after
the debugger has been initialized. Furthermore, a previous change
prevented running the application until after the "configurationDone"
request is received. Therefore, with this change, there is now a well
defined window (between sending the "initialized" event and receiving
the "configurationDone" request), for breakpoint configuration to
occur.

@GitMensch
Copy link
Collaborator

Thank you for this contribution, that looks nice and the defined window is much better than the manual event check.

It looks like you've tested that already on GDB and LLDB, correct?
I currently don't have the second running at all and while I assume "works on one = works on both" this assumption was beaten before...

@brownts
Copy link
Collaborator Author

brownts commented Mar 2, 2022

Thank you for this contribution, that looks nice and the defined window is much better than the manual event check.

It looks like you've tested that already on GDB and LLDB, correct? I currently don't have the second running at all and while I assume "works on one = works on both" this assumption was beaten before...

Yes, that is correct. I ran launch and attach scenarios on both GDB and LLDB, and both seem to operate as expected.

@GitMensch
Copy link
Collaborator

Could you do me a favor and try something that takes long to attach?

I'd highly suggest attaching to a process with lots of loaded shared objects (maybe your browser, or something else) and/or attach via SSH to a gdbserver.
Can you add an entry to the Changelog file yourself, please? Otherwise I'd need to do it after the merge.

Copy link
Owner

@WebFreak001 WebFreak001 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

otherwise I like this change

src/mibase.ts Outdated Show resolved Hide resolved
@WebFreak001
Copy link
Owner

actually after reviewing where the event is sent, this seems like it should never work like this?

Flowchart

If the initialized-event is sent on debug-ready, that should never actually start, as debug-ready is emitted when load/ssh/attach has been run (which in this picture corresponds to the launch request)

@brownts
Copy link
Collaborator Author

brownts commented Mar 2, 2022

Hi @WebFreak001, my interpretation of that UML sequence diagram is that the configuration happens asynchronously (per the dashed arrow on the "initialized event") from the primary focus of control in that lifeline. Therefore, I don't believe there is an implied order between the "launch request" and the breakpoint configuration shown above it. I think the diagram likely could have been constructed with the "launch request" shown above the breakpoint configuration.

@brownts
Copy link
Collaborator Author

brownts commented Mar 2, 2022

That was my interpretation that there was no ordering dependency there. That was further emphasized by the wording in the overview which reinforced this understanding:

Since the development tool does not know when is the correct moment for passing the configuration information to the adapter, the debug adapter is expected to send an initialized event to the development tool to announce that it is ready to accept configuration requests. With this approach a debug adapter does not have to implement a buffering strategy for configuration information.

@WebFreak001
Copy link
Owner

before that however:

[...] This configuration information must be passed to the debug adapter before program execution starts. Some debuggers are able to deal with this information very early, even before the debuggee is known; other debuggers accept this information only when the debuggee is about to start running.

@brownts
Copy link
Collaborator Author

brownts commented Mar 2, 2022

before that however:

[...] This configuration information must be passed to the debug adapter before program execution starts. Some debuggers are able to deal with this information very early, even before the debuggee is known; other debuggers accept this information only when the debuggee is about to start running.

Yes, that is correct. This is accomplished by having the continue/run commands, which are sent to the debugger, gated by having received the configurationDone request (per here) which guarantees that all breakpoint configuration has occurred prior to program execution starting.

@WebFreak001
Copy link
Owner

WebFreak001 commented Mar 2, 2022

ok I'd be fine with merging then if you remove the bind(this) and change it to once as per review

@brownts
Copy link
Collaborator Author

brownts commented Mar 3, 2022

ok I'd be fine with merging then if you remove the bind(this) and change it to once as per review

Sounds good, thanks for taking a look at this. I'll make your suggested changes and push a new update.

The previous implementation worked under the assumption that
breakpoint requests would be received from the client prior to the
debugger having completed it's initialization.  However, if the
debugger completed initialization prior to having received breakpoint
requests from the client, those breakpoints requests would be
ignored (i.e., there was a race condition).  Additionally, the
previous implementation "buffered" the receipt of the breakpoint
requests and would only process them after the debugger initialization
had completed (i.e., "debug-ready").

This change delays the sending of the "initialized" event back to the
client (until the debugger truly has completed its initialization).
As a result, there is no longer a need to buffer the breakpoint
requests.  Breakpoints requests are now forced to be received after
the debugger has been initialized.  Furthermore, a previous change
prevented running the application until after the "configurationDone"
request is received.  Therefore, with this change, there is now a well
defined window (between sending the "initialized" event and receiving
the "configurationDone" request), for breakpoint configuration to
occur.
@brownts brownts force-pushed the bugfix/breakpoint_race_condition branch from 27829e8 to 12f9a7a Compare March 3, 2022 03:39
@GitMensch GitMensch merged commit e2831d9 into WebFreak001:master Mar 3, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants