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

Add API to pause target and wait for debugger to be suspended #339

Merged
merged 8 commits into from
Nov 14, 2024

Conversation

Luke-zhang-mchp
Copy link
Contributor

Closes #295.

Code to suspend/continue the debug session when setting breakpoints are moved to a reusable function pause and continue methods. The pause method awaits a promise which gets resolves when the target is actually suspended.

This pause method is also used in GDBTargetDebugSession::disconnectRequest.

@Luke-zhang-mchp Luke-zhang-mchp changed the title Wait for pause Add API to pause target and wait for debugger to be suspended Nov 7, 2024
@Luke-zhang-mchp
Copy link
Contributor Author

Hey @jonahgraham, this is what I assume the issue was alluding to, and it works fine on our IDE. Let me know how the changes look.

* Sends a pause command to GDBBackend, and resolves when the debugger is
* actually paused
*/
protected async pause(): Promise<void> {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think this name is questionable, since there's also pauseRequest and continueRequest, but I'm not sure what a good name would be. Something like pauseAndWait?

Copy link
Contributor

@jonahgraham jonahgraham left a comment

Choose a reason for hiding this comment

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

This looks quite close to what I was talking about - but I was hoping the logic for "waitPauseNeeded" could be in the new method.

i.e. have a single call that is "pauseIfNeeded" that can be awaited, and then at the end of the block "resumeIfNeeded" that is perhaps passed a token pauseIfNeeded returned (or elsewhere stored in the state).


sort of related topic brain dump:

This is a place I really like Python's with statement, because in Python I would write something like:

    with this.targetPaused():
        // do some operations on a paused target

which will pause if needed at the beginning and resume automatically when leaving the block.

@Luke-zhang-mchp
Copy link
Contributor Author

Luke-zhang-mchp commented Nov 8, 2024

Yeah that with statement would be really nice. What about method decorators? It's not really the same cause it would be the beginning and end of the function. Also probably not worth the trouble, but it would be something like:

const paused = <T extends []>(
    target: GDBDebugSessionBase,
    propertyKey: string,
    descriptor: TypedPropertyDescriptor<(...args: T[]) => void>
) => {
    const originalMethod = descriptor.value; // Original function

    descriptor.value = function (...args: T[]) {
        target.pause();
        originalMethod?.apply(this, args);
        target.continue();
    };
};

export abstract class GDBDebugSessionBase extends LoggingDebugSession {
    @paused
    protected async setBreakPointsRequest(
        response: DebugProtocol.SetBreakpointsResponse,
        args: DebugProtocol.SetBreakpointsArguments
    ): Promise<void> {}
}

unfortunately it can only cover the entire function.

Signed-off-by: Luke Zhang <luke.zhang@microchip.com>
This solution is similar to eclipse-cdt-cloud#287, except the pause method is not based
on an arbitrary timeout, but an emitted event from GDB that indicates
the target is actually suspended.

Signed-off-by: Luke Zhang <luke.zhang@microchip.com>
continue is a reserved keyword

Signed-off-by: Luke Zhang <luke.zhang@microchip.com>
Signed-off-by: Luke Zhang <luke.zhang@microchip.com>
Signed-off-by: Luke Zhang <luke.zhang@microchip.com>
@Luke-zhang-mchp Luke-zhang-mchp marked this pull request as ready for review November 8, 2024 20:56
@jonahgraham
Copy link
Contributor

What about method decorators?

My lack of experience with typescript means I don't know if this is a good idea or not in this case.

Also probably not worth the trouble

That is my instinct for now.

Copy link
Contributor

@jonahgraham jonahgraham left a comment

Choose a reason for hiding this comment

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

This change looks correct - but it also looks like it exposes some issues in the tests when async is off.

For example I can see in logpoints/remote gdb-async-off/hits a logpoint.log that at the moment that the SIGINT is sent to gdb, inferior happens to be paused, leading to this output:

[21:00:09.996 UTC] GDB signal: SIGINT to pid 13380
[21:00:09.996 UTC] GDB notify async: breakpoint-modified,bkpt={number="1",type="breakpoint",disp="keep",enabled="y",addr="0x000055555555513f",func="main",file="count.c",fullname="/home/runner/work/cdt-gdb-adapter/cdt-gdb-adapter/src/integration-tests/test-programs/count.c",line="4",thread-groups=["i1"],times="2",original-location="-source /home/runner/work/cdt-gdb-adapter/cdt-gdb-adapter/src/integration-tests/test-programs/count.c -line 4"}
[21:00:09.996 UTC] To client: {"seq":0,"type":"event","event":"output","body":{"category":"log","output":"Quit\n"}}

What this means is that the adapter thought the inferior was running, so sent a SIGINT, but in the time between the test and SIGINT being delivered, the inferior hit a breakpoint, so the SIGINT was interpreted as Quit instead of pause.

This is a fundamental problem with async mode because this race condition can not be detected or avoided. What I don't know is if/why this change exposes this problem more, or if it was just bad luck. I have restarted the tests in the first instance.

With async on by default for the last couple of years I don't think this matters too much. But we do need to have a clean run. If the above isn't enough information to resolve the issue, let me know and I can try to fix up these problematic test cases.

Signed-off-by: Luke-zhang-04 <Luke_zhang_04@protonmail.com>
Unreliable behaviour due to race conditions is a known issue in sync mode.
See eclipse-cdt-cloud#339 for
more details.
@jonahgraham jonahgraham merged commit 6ba0de8 into eclipse-cdt-cloud:main Nov 14, 2024
4 checks passed
jonahgraham added a commit to jonahgraham/cdt-gdb-vscode that referenced this pull request Dec 4, 2024
Includes:

- Refactor code to allow web extension
  - eclipse-cdt-cloud/cdt-gdb-adapter#328
- Improved handling of ContinuedEvent
  - eclipse-cdt-cloud/cdt-gdb-adapter#335
- Ensure 'interrupt' and 'disconnect' signals are sent before '-gdb-exit'
  - eclipse-cdt-cloud/cdt-gdb-adapter#338
- Add API to pause target and wait for debugger to be suspended
  - eclipse-cdt-cloud/cdt-gdb-adapter#339
jonahgraham added a commit to jonahgraham/cdt-gdb-vscode that referenced this pull request Dec 4, 2024
Includes:

- Refactor code to allow web extension
  - eclipse-cdt-cloud/cdt-gdb-adapter#328
- Improved handling of ContinuedEvent
  - eclipse-cdt-cloud/cdt-gdb-adapter#335
- Ensure 'interrupt' and 'disconnect' signals are sent before '-gdb-exit'
  - eclipse-cdt-cloud/cdt-gdb-adapter#338
- Add API to pause target and wait for debugger to be suspended
  - eclipse-cdt-cloud/cdt-gdb-adapter#339
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add API to easily pause target and wait for it to be ready
3 participants