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

Breakpoints are randomly not set by the extension #307

Closed
4 of 8 tasks
JanHildenbrandBosch opened this issue Dec 23, 2021 · 9 comments · Fixed by #313
Closed
4 of 8 tasks

Breakpoints are randomly not set by the extension #307

JanHildenbrandBosch opened this issue Dec 23, 2021 · 9 comments · Fixed by #313

Comments

@JanHildenbrandBosch
Copy link

JanHildenbrandBosch commented Dec 23, 2021

Edit: Could be related to #276 (comment) and #268

Although a breakpoint is set in Visual Studio Code before the debugging task is executed, only sometimes the extension will instruct gdb to insert a breakpoint.

Running VSCode Version 1.55.2, gdb (Ubuntu 10.2-0ubuntu1~ 20.04 ~ 1) and extension version 0.25.1 from the VSCode extension marketplace.

  • If you are using gdb
    • gdb --version >= 7.7.1
    • it works on the command line with gdb
    • cwd and target are properly set
  • If you are using lldb
    • lldb --version >= 3.7.1
    • it works on the command line with lldb-mi
    • cwd and target are properly set

Configuration:

            "name": "x86",
            "request": "launch",
            "target": "${command:cmake.launchTargetPath}",
            "type": "gdb",
            "printCalls": true,
            "showDevDebugOutput": true,

and "debug.allowBreakpointsEverywhere": true,

Output:

1-gdb-set target-async on
2-environment-directory "/workspace"
3-file-exec-and-symbols "/workspace/build/executable"
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"thread-group-added","output":[["id","i1"]]}]}
GDB -> App: {"token":1,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[]}}
GDB -> App: {"token":2,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[["source-path","/workspace:$cdir:$cwd"]]}}
GDB -> App: {"token":3,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[]}}
Running executable
4-exec-run
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"thread-group-started","output":[["id","i1"],["pid","24133"]]}]}
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"thread-created","output":[["id","1"],["group-id","i1"]]}]}
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"library-loaded","output":[["id","/lib64/ld-linux-x86-64.so.2"],["target-name","/lib64/ld-linux-x86-64.so.2"],["host-name","/lib64/ld-linux-x86-64.so.2"],["symbols-loaded","0"],["thread-group","i1"],["ranges",[[["from","0x00007ffff7fd0100"],["to","0x00007ffff7ff2674"]]]]]}]}
GDB -> App: {"token":4,"outOfBandRecord":[],"resultRecords":{"resultClass":"running","results":[]}}
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"exec","asyncClass":"running","output":[["thread-id","all"]]}]}
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"library-loaded","output":[["id","/lib/x86_64-linux-gnu/libpthread.so.0"],["target-name","/lib/x86_64-linux-gnu/libpthread.so.0"],["host-name","/lib/x86_64-linux-gnu/libpthread.so.0"],["symbols-loaded","0"],["thread-group","i1"],["ranges",[[["from","0x00007ffff7fa5ae0"],["to","0x00007ffff7fb54d5"]]]]]}]}
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"library-loaded","output":[["id","/lib/x86_64-linux-gnu/libstdc++.so.6"],["target-name","/lib/x86_64-linux-gnu/libstdc++.so.6"],["host-name","/lib/x86_64-linux-gnu/libstdc++.so.6"],["symbols-loaded","0"],["thread-group","i1"],["ranges",[[["from","0x00007ffff7e5a160"],["to","0x00007ffff7f42452"]]]]]}]}
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"library-loaded","output":[["id","/lib/x86_64-linux-gnu/libm.so.6"],["target-name","/lib/x86_64-linux-gnu/libm.so.6"],["host-name","/lib/x86_64-linux-gnu/libm.so.6"],["symbols-loaded","0"],["thread-group","i1"],["ranges",[[["from","0x00007ffff7c7c3c0"],["to","0x00007ffff7d22f18"]]]]]}]}
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"library-loaded","output":[["id","/lib/x86_64-linux-gnu/libgcc_s.so.1"],["target-name","/lib/x86_64-linux-gnu/libgcc_s.so.1"],["host-name","/lib/x86_64-linux-gnu/libgcc_s.so.1"],["symbols-loaded","0"],["thread-group","i1"],["ranges",[[["from","0x00007ffff7c555e0"],["to","0x00007ffff7c66045"]]]]]}]}
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"library-loaded","output":[["id","/lib/x86_64-linux-gnu/libc.so.6"],["target-name","/lib/x86_64-linux-gnu/libc.so.6"],["host-name","/lib/x86_64-linux-gnu/libc.so.6"],["symbols-loaded","0"],["thread-group","i1"],["ranges",[[["from","0x00007ffff7a85630"],["to","0x00007ffff7bfa20d"]]]]]}]}
GDB -> App: {"outOfBandRecord":[{"isStream":true,"type":"console","content":"[Thread debugging using libthread_db enabled]\n"}]}
[Thread debugging using libthread_db enabled]
GDB -> App: {"outOfBandRecord":[{"isStream":true,"type":"console","content":"Using host libthread_db library \"/lib/x86_64-linux-gnu/libthread_db.so.1\".\n"}]}
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
GDB -> App: {"outOfBandRecord":[{"isStream":true,"type":"console","content":"[Inferior 1 (process 24133) exited normally]\n"}]}
[Inferior 1 (process 24133) exited normally]
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"thread-exited","output":[["id","1"],["group-id","i1"]]}]}
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"thread-group-exited","output":[["id","i1"],["exit-code","0"]]}]}
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"exec","asyncClass":"stopped","output":[["reason","exited-normally"]]}]}
-gdb-exit
GDB -> App: {"outOfBandRecord":[],"resultRecords":{"resultClass":"exit","results":[]}}
5-thread-info

Rerunning it without changing anything sometimes leads to a successful breakpoint insertion:

1-gdb-set target-async on
2-environment-directory "/workspace"
3-file-exec-and-symbols "/workspace/build/executable"
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"thread-group-added","output":[["id","i1"]]}]}
GDB -> App: {"token":1,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[]}}
GDB -> App: {"token":2,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[["source-path","/workspace:$cdir:$cwd"]]}}
GDB -> App: {"token":3,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[]}}
4-break-delete
GDB -> App: {"token":4,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[]}}
5-break-insert -f "/workspace/Tests/RunAllTests.cpp:30"
GDB -> App: {"token":5,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[["bkpt",[["number","1"],["type","breakpoint"],["disp","keep"],["enabled","y"],["addr","0x000000000003a667"],["func","main(int, char**)"],["file","../../Tests/RunAllTests.cpp"],["fullname","/workspace/Tests/RunAllTests.cpp"],["line","30"],["thread-groups",["i1"]],["times","0"],["original-location","/workspace/Tests/RunAllTests.cpp:30"]]]]}}
Running executable
6-exec-run
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"thread-group-started","output":[["id","i1"],["pid","25360"]]}]}
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"thread-created","output":[["id","1"],["group-id","i1"]]}]}
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"breakpoint-modified","output":[["bkpt",[["number","1"],["type","breakpoint"],["disp","keep"],["enabled","y"],["addr","0x000055555558e667"],["func","main(int, char**)"],["file","../../Tests/RunAllTests.cpp"],["fullname","/workspace/Tests/RunAllTests.cpp"],["line","30"],["thread-groups",["i1"]],["times","0"],["original-location","/workspace/Tests/RunAllTests.cpp:30"]]]]}]}
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"library-loaded","output":[["id","/lib64/ld-linux-x86-64.so.2"],["target-name","/lib64/ld-linux-x86-64.so.2"],["host-name","/lib64/ld-linux-x86-64.so.2"],["symbols-loaded","0"],["thread-group","i1"],["ranges",[[["from","0x00007ffff7fd0100"],["to","0x00007ffff7ff2674"]]]]]}]}
GDB -> App: {"token":6,"outOfBandRecord":[],"resultRecords":{"resultClass":"running","results":[]}}
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"exec","asyncClass":"running","output":[["thread-id","all"]]}]}
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"library-loaded","output":[["id","/lib/x86_64-linux-gnu/libpthread.so.0"],["target-name","/lib/x86_64-linux-gnu/libpthread.so.0"],["host-name","/lib/x86_64-linux-gnu/libpthread.so.0"],["symbols-loaded","0"],["thread-group","i1"],["ranges",[[["from","0x00007ffff7fa5ae0"],["to","0x00007ffff7fb54d5"]]]]]}]}
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"library-loaded","output":[["id","/lib/x86_64-linux-gnu/libstdc++.so.6"],["target-name","/lib/x86_64-linux-gnu/libstdc++.so.6"],["host-name","/lib/x86_64-linux-gnu/libstdc++.so.6"],["symbols-loaded","0"],["thread-group","i1"],["ranges",[[["from","0x00007ffff7e5a160"],["to","0x00007ffff7f42452"]]]]]}]}
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"library-loaded","output":[["id","/lib/x86_64-linux-gnu/libm.so.6"],["target-name","/lib/x86_64-linux-gnu/libm.so.6"],["host-name","/lib/x86_64-linux-gnu/libm.so.6"],["symbols-loaded","0"],["thread-group","i1"],["ranges",[[["from","0x00007ffff7c7c3c0"],["to","0x00007ffff7d22f18"]]]]]}]}

Adding "showDevDebugOutput": true, increased the probability that the breakpoints were inserted -> Race Condition?!?

Also tested shortly with the latest master (15f7bae), but ran sometimes into issues that the debugging session never started.

@JanHildenbrandBosch
Copy link
Author

JanHildenbrandBosch commented Dec 23, 2021

After some digging and testing (with my very limited typescript knowledge), I do not understand the necessity of this.debugReady

code-debug/src/mibase.ts

Lines 203 to 265 in 15f7bae

protected setFunctionBreakPointsRequest(response: DebugProtocol.SetFunctionBreakpointsResponse, args: DebugProtocol.SetFunctionBreakpointsArguments): void {
const cb = (() => {
this.debugReady = true;
const all = [];
args.breakpoints.forEach(brk => {
all.push(this.miDebugger.addBreakPoint({ raw: brk.name, condition: brk.condition, countCondition: brk.hitCondition }));
});
Promise.all(all).then(brkpoints => {
const finalBrks = [];
brkpoints.forEach(brkp => {
if (brkp[0])
finalBrks.push({ line: brkp[1].line });
});
response.body = {
breakpoints: finalBrks
};
this.sendResponse(response);
}, msg => {
this.sendErrorResponse(response, 10, msg.toString());
});
}).bind(this);
if (this.debugReady)
cb();
else
this.miDebugger.once("debug-ready", cb);
}
protected setBreakPointsRequest(response: DebugProtocol.SetBreakpointsResponse, args: DebugProtocol.SetBreakpointsArguments): void {
const cb = (() => {
this.debugReady = true;
this.miDebugger.clearBreakPoints().then(() => {
let path = args.source.path;
if (this.isSSH) {
// trimCWD is the local path, switchCWD is the ssh path
path = systemPath.relative(this.trimCWD.replace(/\\/g, "/"), path.replace(/\\/g, "/"));
path = resolve(this.switchCWD.replace(/\\/g, "/"), path.replace(/\\/g, "/"));
}
const all = args.breakpoints.map(brk => {
return this.miDebugger.addBreakPoint({ file: path, line: brk.line, condition: brk.condition, countCondition: brk.hitCondition });
});
Promise.all(all).then(brkpoints => {
const finalBrks = [];
brkpoints.forEach(brkp => {
// TODO: Currently all breakpoints returned are marked as verified,
// which leads to verified breakpoints on a broken lldb.
if (brkp[0])
finalBrks.push(new DebugAdapter.Breakpoint(true, brkp[1].line));
});
response.body = {
breakpoints: finalBrks
};
this.sendResponse(response);
}, msg => {
this.sendErrorResponse(response, 9, msg.toString());
});
}, msg => {
this.sendErrorResponse(response, 9, msg.toString());
});
}).bind(this);
if (this.debugReady)
cb();
else
this.miDebugger.once("debug-ready", cb);

Removing the variable and directly calling the cb() seems to fix it for me:

protected setFunctionBreakPointsRequest(response: DebugProtocol.SetFunctionBreakpointsResponse, args: DebugProtocol.SetFunctionBreakpointsArguments): void {
	const cb = (() => {
		const all = [];
		args.breakpoints.forEach(brk => {
			all.push(this.miDebugger.addBreakPoint({ raw: brk.name, condition: brk.condition, countCondition: brk.hitCondition }));
		});
		Promise.all(all).then(brkpoints => {
			const finalBrks = [];
			brkpoints.forEach(brkp => {
				if (brkp[0])
					finalBrks.push({ line: brkp[1].line });
			});
			response.body = {
				breakpoints: finalBrks
			};
			this.sendResponse(response);
		}, msg => {
			this.sendErrorResponse(response, 10, msg.toString());
		});
	}).bind(this);
	cb();
}

protected setBreakPointsRequest(response: DebugProtocol.SetBreakpointsResponse, args: DebugProtocol.SetBreakpointsArguments): void {
	const cb = (() => {
		this.miDebugger.clearBreakPoints().then(() => {
			let path = args.source.path;
			if (this.isSSH) {
				// trimCWD is the local path, switchCWD is the ssh path
				path = systemPath.relative(this.trimCWD.replace(/\\/g, "/"), path.replace(/\\/g, "/"));
				path = resolve(this.switchCWD.replace(/\\/g, "/"), path.replace(/\\/g, "/"));
			}
			const all = args.breakpoints.map(brk => {
				return this.miDebugger.addBreakPoint({ file: path, line: brk.line, condition: brk.condition, countCondition: brk.hitCondition });
			});
			Promise.all(all).then(brkpoints => {
				const finalBrks = [];
				brkpoints.forEach(brkp => {
					// TODO: Currently all breakpoints returned are marked as verified,
					// which leads to verified breakpoints on a broken lldb.
					if (brkp[0])
						finalBrks.push(new DebugAdapter.Breakpoint(true, brkp[1].line));
				});
				response.body = {
					breakpoints: finalBrks
				};
				this.sendResponse(response);
			}, msg => {
				this.sendErrorResponse(response, 9, msg.toString());
			});
		}, msg => {
			this.sendErrorResponse(response, 9, msg.toString());
		});
	}).bind(this);
	cb();
}

Not sure whether this has some unwanted side effects or whether the cb() creation is necessary at all (sorry for my limited ts knowledge).

@WebFreak001
Copy link
Owner

WebFreak001 commented Dec 23, 2021

the debugReady seems to be set once the debug-ready event is emitted (happens after the load commands are ran in GDB, like loading the symbols, loading path translations, preparing async exec, etc. The if simply checks, if the event has been fired already, in which case to call the code immediately, otherwise wait for the event and call it once the event triggers once.

Running immediately instead of waiting for the event could mean that some configuration is skipped and with that bugs with the break insert functions could arise for example when the path translations aren't sent yet to GDB. I think your solution here is working for you because you are giving the callback more time in the race to finish, but it's not a solid solution and it will break once the break command is dependent on some of the previous setup commands. (like with SSH, WSL or MSYS/MinGW setups)

I would have thought this should be fixed on master with #304 being merged, after reading it might actually be that that is the cause for the race being lost by the break function now? (cc @brownts)

If that PR started this issue for you though, (PR can't be the reason it started happening because it's not in the currently released version where you said it also happens) reverting would not be a good choice - rather the underlying race condition should be solved. (wait for running for breaks, etc) It looks like before there was a 50ms timeout that may have been used to make this race work, which is not clean and error prone I think.

@JanHildenbrandBosch
Copy link
Author

JanHildenbrandBosch commented Dec 23, 2021

the debugReady seems to be set once the debug-ready event is emitted (happens after the load commands are ran in GDB, like loading the symbols, loading path translations, preparing async exec, etc. The if simply checks, if the event has been fired already, in which case to call the code immediately, otherwise wait for the event and call it once the event triggers once.

Running immediately instead of waiting for the event could mean that some configuration is skipped and with that bugs with the break insert functions could arise for example when the path translations aren't sent yet to GDB. I think your solution here is working for you because you are giving the callback more time in the race to finish, but it's not a solid solution and it will break once the break command is dependent on some of the previous setup commands. (like with SSH, WSL or MSYS/MinGW setups)

I thought so that I missed something, thanks for the explanation.

It could be fixed on master I'm not a 100% sure.
Currently if I run it on master, it either works, or it never starts (is in a deadlock/race condition):

1-gdb-set target-async on
2-environment-directory "/workspace"
3-file-exec-and-symbols "/workspace/build/example"
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"thread-group-added","output":[["id","i1"]]}]}
GDB -> App: {"token":1,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[]}}
GDB -> App: {"token":2,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[["source-path","/workspace:$cdir:$cwd"]]}}
GDB -> App: {"token":3,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[]}}

But this could be a separate issue.

@brownts
Copy link
Collaborator

brownts commented Dec 23, 2021

I took a look at where the "debug-ready" event is emitted and in this case it's the load routine. I suspect there might be a race condition between when that event is emitted and when the breakpoint requests sent from VSCode are processed. It appears the only way that debugReady can be set to "true" is via one of these breakpoint callbacks. Thus, I believe in order for this to work properly, the breakpoint request must be received prior to the "debug-ready" event emitted from the load routine (so the callback is registered with the event prior to the event firing). Otherwise, the event will have fired in the past, but the debugReady boolean will never have been set true (since no callback had been registered with that event yet). Then when the breakpoint request(s) are processed the boolean is still false and the callback is registered to fire after the "debug-ready" event occurs (but it never occurs again since it already happened).

That's my suspicion about what is going on here. It seems to me that the setting of the debugReady boolean should happen independently of the breakpoint callback, when the "debug-ready" event fires, to avoid this potential race condition.

A simple test to prove out this theory would be to add a handler for the "debug-ready" event that just sets this flag. Something like the following (untested of course 😉) added to the mibase.ts:initDebugger):

this.miDebugger.on("debug-ready", (() => { this.debugReady = true; }));

@JanHildenbrandBosch
Copy link
Author

JanHildenbrandBosch commented Jan 3, 2022

Sorry for the late reply.

Adding a log message at emit debug-ready (mi2.ts) and setting breakpoint request (mibase.ts) seems to verify your assumption.

Bad case:

1-gdb-set target-async on
2-environment-directory "/workspace"
3-file-exec-and-symbols "/workspace/build/example"
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"thread-group-added","output":[["id","i1"]]}]}
GDB -> App: {"token":1,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[]}}
GDB -> App: {"token":2,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[["source-path","/workspace:$cdir:$cwd"]]}}
GDB -> App: {"token":3,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[]}}
emit debug-ready
set breakpoint-request

Good case:

1-gdb-set target-async on
2-environment-directory "/workspace"
3-file-exec-and-symbols "/workspace/build/example"
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"thread-group-added","output":[["id","i1"]]}]}
GDB -> App: {"token":1,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[]}}
GDB -> App: {"token":2,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[["source-path","/workspace:$cdir:$cwd"]]}}
set breakpoint-request
GDB -> App: {"token":3,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[]}}
emit debug-ready
[...]

adding your proposal to initDebugger seems to fix this issue!

protected initDebugger() {
  [...]
  this.miDebugger.on("thread-exited", this.threadExitedEvent.bind(this));
  this.miDebugger.on("debug-ready", (() => { this.debugReady = true; }));
  this.sendEvent(new InitializedEvent());
  [...]
}

Now both cases work for me!

1-gdb-set target-async on
2-environment-directory "/workspace"
3-file-exec-and-symbols "/workspace/build/example"
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"thread-group-added","output":[["id","i1"]]}]}
GDB -> App: {"token":1,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[]}}
GDB -> App: {"token":2,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[["source-path","/workspace:$cdir:$cwd"]]}}
GDB -> App: {"token":3,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[]}}
emit debug-ready
set breakpoint-request
4-break-delete
GDB -> App: {"token":4,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[]}}
5-break-insert -f "/workspace/Test.cpp:107"
6-break-insert -f "/workspace/Test.cpp:182"

@brownts
Copy link
Collaborator

brownts commented Jan 3, 2022

Hi @JanHildenbrandBosch, no problem on the response time, I'm just glad we understand the problem and were able to get you unstuck.

@WebFreak001, I'm wondering why we implement the breakpoint setting in this manner (by potentially registering callbacks with the event system to handle them at a later time). It seems if we just delayed the sending of the "initialized" event back to the editor, we wouldn't have to add callbacks based on the debugReady boolean.

According to the DAP Specification section on "Configuring breakpoint and exception behavior", it indicates:

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.

Per the wording above, the protocol is supposed to be flexible enough to avoid having to "... implement a buffering strategy ...", which seems like what this is doing by adding the callbacks to the event. Currently, we send the "initialized" event during the early part of the "launch" or "attach", but I wonder if we should instead send it when the "debug-ready" event fires. This should guarantee that no breakpoint configuration is sent by the editor until after the debugger has been completely initialized. If we did that, I don't think we'd even need the debugReady boolean nor require callbacks for the setting of the breakpoints.

Maybe sending this event early was necessary when the 50ms timer was in place, however with the current implementation, the debugger will not be commanded to start running until after the configuration has completed.

@GitMensch
Copy link
Collaborator

Just a note: I think it is time for a new release once this issue is set. @brownts would you consider a PR?

@brownts
Copy link
Collaborator

brownts commented Jan 4, 2022

Just a note: I think it is time for a new release once this issue is set. @brownts would you consider a PR?

@GitMensch, can we resolve PR #259 before we create a PR for this issue, so we aren't having to resolve merge conflicts? There is some overlap between that PR and what would be changed here. It would be good to incorporate that PR for the next release as well.

@GitMensch
Copy link
Collaborator

@brownts Sure, the related PR is merged now :-)

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 a pull request may close this issue.

4 participants