diff --git a/components/lazdebuggers/lazdebuggerfp/fpdebugdebugger.pas b/components/lazdebuggers/lazdebuggerfp/fpdebugdebugger.pas index bd6b58c0bf..69ae5ceef5 100644 --- a/components/lazdebuggers/lazdebuggerfp/fpdebugdebugger.pas +++ b/components/lazdebuggers/lazdebuggerfp/fpdebugdebugger.pas @@ -152,7 +152,7 @@ type public constructor Create(ADebugger: TFpDebugDebuggerBase; ADbgBreakPoint: TFPBreakpoint); overload; procedure AbortSetBreak; override; - procedure RemoveBreakPoint_DecRef; override; + property DbgBreakPoint: TFPBreakpoint read FDbgBreakPoint; end; { TFpThreadWorkerBreakPointRemoveUpdate } @@ -578,6 +578,7 @@ type FBrkLogStackLimit: Integer; FBrkLogStackResult: array of String; FBrkLogExpr, FBrkLogResult: String; + procedure MaybeAbortWorker(AWait: Boolean = false); procedure SetBreak; procedure ResetBreak; procedure ThreadLogExpression; @@ -1102,9 +1103,9 @@ begin DecRef; end else - FResetBreakPoint := True; + FResetBreakPoint := 1; - if FResetBreakPoint then begin + if FResetBreakPoint <> 0 then begin if InternalBreakpoint <> nil then begin WorkItem := TFpThreadWorkerBreakPointRemoveUpdate.Create(FDebugger, InternalBreakpoint); FpDebugger.FWorkQueue.PushItem(WorkItem); @@ -1150,15 +1151,8 @@ end; procedure TFpThreadWorkerBreakPointSetUpdate.AbortSetBreak; begin - FResetBreakPoint := True; - RequestStop; -end; - -procedure TFpThreadWorkerBreakPointSetUpdate.RemoveBreakPoint_DecRef; -begin - assert(system.ThreadID = classes.MainThreadID, 'TFpThreadWorkerBreakPointSetUpdate.RemoveBreakPoint_DecRef: system.ThreadID = classes.MainThreadID'); + InterLockedExchange(FResetBreakPoint, 1); FDbgBreakPoint := nil; - UnQueue_DecRef; end; { TFpThreadWorkerBreakPointRemoveUpdate } @@ -1879,11 +1873,26 @@ begin result := nil; end; +procedure TFPBreakpoint.MaybeAbortWorker(AWait: Boolean); +begin + if FThreadWorker <> nil then begin + assert(FThreadWorker is TFpThreadWorkerBreakPointSetUpdate, 'TFPBreakpoint.ResetBreak: FThreadWorker is TFpThreadWorkerBreakPointSetUpdate'); + assert(FInternalBreakpoint = nil, 'TFPBreakpoint.ResetBreak: FInternalBreakpoint = nil'); + FThreadWorker.AbortSetBreak; + if AWait then + TFpDebugDebugger(Debugger).FWorkQueue.WaitForItem(FThreadWorker); + FThreadWorker.DecRef; + FThreadWorker := nil; + end; +end; + procedure TFPBreakpoint.SetBreak; begin debuglnEnter(DBG_BREAKPOINTS, ['>> TFPBreakpoint.SetBreak ADD ',FSource,':',FLine,'/',dbghex(Address),' ' ]); assert(FThreadWorker = nil, 'TFPBreakpoint.SetBreak: FThreadWorker = nil'); + assert((FThreadWorker = nil) or ( (FThreadWorker is TFpThreadWorkerBreakPointSetUpdate) and (TFpThreadWorkerBreakPointSetUpdate(FThreadWorker).DbgBreakPoint = nil) ), 'TFPBreakpoint.SetBreak: (FThreadWorker = nil) or ( (FThreadWorker is TFpThreadWorkerBreakPointSetUpdate) and (TFpThreadWorkerBreakPointSetUpdate(FThreadWorker).DbgBreakPoint = nil) )'); assert(FInternalBreakpoint=nil); + MaybeAbortWorker; FThreadWorker := TFpThreadWorkerBreakPointSetUpdate.Create(TFpDebugDebugger(Debugger), Self); TFpDebugDebugger(Debugger).FWorkQueue.PushItem(FThreadWorker); @@ -1900,12 +1909,8 @@ begin FIsSet:=false; if FThreadWorker <> nil then begin debugln(DBG_BREAKPOINTS, ['>> TFPBreakpoint.ResetBreak CANCEL / REMOVE ',FSource,':',FLine,'/',dbghex(Address),' ' ]); - assert(FThreadWorker is TFpThreadWorkerBreakPointSetUpdate, 'TFPBreakpoint.ResetBreak: FThreadWorker is TFpThreadWorkerBreakPointSetUpdate'); assert(FInternalBreakpoint = nil, 'TFPBreakpoint.ResetBreak: FInternalBreakpoint = nil'); - FThreadWorker.AbortSetBreak; - FThreadWorker.RemoveBreakPoint_DecRef; - FThreadWorker.DecRef; - FThreadWorker := nil; + MaybeAbortWorker; exit; end; @@ -2018,13 +2023,7 @@ begin If the next pause is a hit on this breakpoint, then it will be ignored *) ResetBreak; - - if FThreadWorker <> nil then begin - FThreadWorker.AbortSetBreak; - FThreadWorker.RemoveBreakPoint_DecRef; - FThreadWorker.DecRef; - FThreadWorker := nil; - end; + MaybeAbortWorker(True); inherited Destroy; end; diff --git a/components/lazdebuggers/lazdebuggerfp/fpdebugdebuggerworkthreads.pas b/components/lazdebuggers/lazdebuggerfp/fpdebugdebuggerworkthreads.pas index ea5d36c4b7..528bb15259 100644 --- a/components/lazdebuggers/lazdebuggerfp/fpdebugdebuggerworkthreads.pas +++ b/components/lazdebuggers/lazdebuggerfp/fpdebugdebuggerworkthreads.pas @@ -299,7 +299,6 @@ type TFpThreadWorkerBreakPoint = class(TFpDbgDebggerThreadWorkerItem) public - procedure RemoveBreakPoint_DecRef; virtual; procedure AbortSetBreak; virtual; end; @@ -317,7 +316,7 @@ type FWatchScope: TDBGWatchPointScope; FWatchKind: TDBGWatchPointKind; protected - FResetBreakPoint: Boolean; + FResetBreakPoint: longint; procedure UpdateBrkPoint_DecRef(Data: PtrInt = 0); virtual; abstract; procedure DoExecute; override; public @@ -1392,11 +1391,6 @@ end; { TFpThreadWorkerBreakPoint } -procedure TFpThreadWorkerBreakPoint.RemoveBreakPoint_DecRef; -begin - // -end; - procedure TFpThreadWorkerBreakPoint.AbortSetBreak; begin // @@ -1411,32 +1405,37 @@ var R: TFpValue; s: TFpDbgValueSize; begin - case FKind of - bpkAddress: - FInternalBreakpoint := FDebugger.DbgController.CurrentProcess.AddBreak(FAddress, True); - bpkSource: - FInternalBreakpoint := FDebugger.DbgController.CurrentProcess.AddBreak(FSource, FLine, True); - bpkData: begin - CurContext := FDebugger.DbgController.CurrentProcess.FindSymbolScope(FThreadId, FStackFrame); - if CurContext <> nil then begin - WatchPasExpr := TFpPascalExpression.Create(FWatchData, CurContext, True); - WatchPasExpr.IntrinsicPrefix := TFpDebugDebuggerProperties(FDebugger.GetProperties).IntrinsicPrefix; - WatchPasExpr.AutoDeref := TFpDebugDebuggerProperties(FDebugger.GetProperties).AutoDeref; - WatchPasExpr.Parse; - R := WatchPasExpr.ResultValue; // Address and Size - // TODO: Cache current value - if WatchPasExpr.Valid and IsTargetNotNil(R.Address) and R.GetSize(s) then begin - // pass context - FInternalBreakpoint := FDebugger.DbgController.CurrentProcess.AddWatch(R.Address.Address, SizeToFullBytes(s), FWatchKind, FWatchScope); + if InterlockedExchange(FResetBreakPoint, 0) = 0 then begin + case FKind of + bpkAddress: + FInternalBreakpoint := FDebugger.DbgController.CurrentProcess.AddBreak(FAddress, True); + bpkSource: + FInternalBreakpoint := FDebugger.DbgController.CurrentProcess.AddBreak(FSource, FLine, True); + bpkData: begin + CurContext := FDebugger.DbgController.CurrentProcess.FindSymbolScope(FThreadId, FStackFrame); + if CurContext <> nil then begin + WatchPasExpr := TFpPascalExpression.Create(FWatchData, CurContext, True); + WatchPasExpr.IntrinsicPrefix := TFpDebugDebuggerProperties(FDebugger.GetProperties).IntrinsicPrefix; + WatchPasExpr.AutoDeref := TFpDebugDebuggerProperties(FDebugger.GetProperties).AutoDeref; + WatchPasExpr.Parse; + R := WatchPasExpr.ResultValue; // Address and Size + // TODO: Cache current value + if WatchPasExpr.Valid and IsTargetNotNil(R.Address) and R.GetSize(s) then begin + // pass context + FInternalBreakpoint := FDebugger.DbgController.CurrentProcess.AddWatch(R.Address.Address, SizeToFullBytes(s), FWatchKind, FWatchScope); + end; + WatchPasExpr.Free; + CurContext.ReleaseReference; end; - WatchPasExpr.Free; - CurContext.ReleaseReference; end; end; end; - if FResetBreakPoint then begin - FDebugger.DbgController.CurrentProcess.RemoveBreak(FInternalBreakpoint); - FreeAndNil(FInternalBreakpoint); + + if InterlockedExchange(FResetBreakPoint, 0) = 1 then begin + if (FInternalBreakpoint <> nil) then begin + FDebugger.DbgController.CurrentProcess.RemoveBreak(FInternalBreakpoint); + FreeAndNil(FInternalBreakpoint); + end; end; Queue(@UpdateBrkPoint_DecRef); end;