@@ -27,6 +27,7 @@ import {
2727 Event ,
2828} from '@vscode/debugadapter' ;
2929import { DebugProtocol } from '@vscode/debugprotocol' ;
30+ import { Mutex } from 'async-mutex' ;
3031import { ContinuedEvent } from '../events/continuedEvent' ;
3132import { StoppedEvent } from '../events/stoppedEvent' ;
3233import { VarObjType } from '../varManager' ;
@@ -191,6 +192,12 @@ export abstract class GDBDebugSessionBase extends LoggingDebugSession {
191192 // first of them pauses, and the last to complete resumes
192193 protected pauseCount = 0 ;
193194
195+ // Serializes the bodies of the breakpoint request handlers so their
196+ // read-modify-write of GDB's global breakpoint list cannot interleave.
197+ // pauseIfNeeded/continueIfNeeded only coalesces the target pause, it does
198+ // not prevent concurrent handlers from acting on stale snapshots.
199+ protected breakpointMutex = new Mutex ( ) ;
200+
194201 // Pending requests to pause a thread silently (without sending stopped event).
195202 // At the moment only used with pauseIfRunning().
196203 protected silentPauseRequests : PendingPauseRequest [ ] = [ ] ;
@@ -917,6 +924,15 @@ export abstract class GDBDebugSessionBase extends LoggingDebugSession {
917924 protected async setDataBreakpointsRequest (
918925 response : DebugProtocol . SetDataBreakpointsResponse ,
919926 args : DebugProtocol . SetDataBreakpointsArguments
927+ ) : Promise < void > {
928+ await this . breakpointMutex . runExclusive ( ( ) =>
929+ this . doSetDataBreakpointsRequest ( response , args )
930+ ) ;
931+ }
932+
933+ protected async doSetDataBreakpointsRequest (
934+ response : DebugProtocol . SetDataBreakpointsResponse ,
935+ args : DebugProtocol . SetDataBreakpointsArguments
920936 ) : Promise < void > {
921937 // If this is the first time sending this breakpoint and there are no breakpoints to set,
922938 // do not change state of the target by avoiding an unnecessary pause
@@ -1027,18 +1043,17 @@ export abstract class GDBDebugSessionBase extends LoggingDebugSession {
10271043 response : DebugProtocol . SetInstructionBreakpointsResponse ,
10281044 args : DebugProtocol . SetInstructionBreakpointsArguments
10291045 ) : Promise < void > {
1030- try {
1031- return await this . doSetInstructionBreakpointsRequest (
1032- response ,
1033- args
1034- ) ;
1035- } catch ( err ) {
1036- this . sendErrorResponse (
1037- response ,
1038- 1 ,
1039- err instanceof Error ? err . message : String ( err )
1040- ) ;
1041- }
1046+ await this . breakpointMutex . runExclusive ( async ( ) => {
1047+ try {
1048+ await this . doSetInstructionBreakpointsRequest ( response , args ) ;
1049+ } catch ( err ) {
1050+ this . sendErrorResponse (
1051+ response ,
1052+ 1 ,
1053+ err instanceof Error ? err . message : String ( err )
1054+ ) ;
1055+ }
1056+ } ) ;
10421057 }
10431058
10441059 protected async doSetInstructionBreakpointsRequest (
@@ -1166,6 +1181,15 @@ export abstract class GDBDebugSessionBase extends LoggingDebugSession {
11661181 protected async setBreakPointsRequest (
11671182 response : DebugProtocol . SetBreakpointsResponse ,
11681183 args : DebugProtocol . SetBreakpointsArguments
1184+ ) : Promise < void > {
1185+ await this . breakpointMutex . runExclusive ( ( ) =>
1186+ this . doSetBreakPointsRequest ( response , args )
1187+ ) ;
1188+ }
1189+
1190+ protected async doSetBreakPointsRequest (
1191+ response : DebugProtocol . SetBreakpointsResponse ,
1192+ args : DebugProtocol . SetBreakpointsArguments
11691193 ) : Promise < void > {
11701194 // If this is the first time sending this breakpoint and there are no breakpoints to set,
11711195 // do not change state of the target by avoiding an unnecessary pause
@@ -1417,6 +1441,15 @@ export abstract class GDBDebugSessionBase extends LoggingDebugSession {
14171441 protected async setFunctionBreakPointsRequest (
14181442 response : DebugProtocol . SetFunctionBreakpointsResponse ,
14191443 args : DebugProtocol . SetFunctionBreakpointsArguments
1444+ ) {
1445+ await this . breakpointMutex . runExclusive ( ( ) =>
1446+ this . doSetFunctionBreakPointsRequest ( response , args )
1447+ ) ;
1448+ }
1449+
1450+ protected async doSetFunctionBreakPointsRequest (
1451+ response : DebugProtocol . SetFunctionBreakpointsResponse ,
1452+ args : DebugProtocol . SetFunctionBreakpointsArguments
14201453 ) {
14211454 // If this is the first time sending this breakpoint and there are no breakpoints to set,
14221455 // do not change state of the target by avoiding an unnecessary pause
0 commit comments