mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-12 16:09:41 +02:00
DBG: Prevent exec-commands from running nested in other commands. Always queue, and run in the outer most "RunQueue" call.
Prevents state driven changes to IDE objects, while IDE is working on them (IDE-locals are destroyed while being evaluated). Issue #19551 git-svn-id: trunk@31208 -
This commit is contained in:
parent
34bc282ea3
commit
23d4607e5d
@ -277,15 +277,24 @@ type
|
||||
property Properties: TGDBMIDebuggerCommandProperts read FProperties write FProperties;
|
||||
end;
|
||||
|
||||
{ TGDBMIDebuggerCommandList }
|
||||
|
||||
TGDBMIDebuggerCommandList = class(TRefCntObjList)
|
||||
private
|
||||
function Get(Index: Integer): TGDBMIDebuggerCommand;
|
||||
procedure Put(Index: Integer; const AValue: TGDBMIDebuggerCommand);
|
||||
public
|
||||
property Items[Index: Integer]: TGDBMIDebuggerCommand read Get write Put; default;
|
||||
end;
|
||||
|
||||
{ TGDBMIDebugger }
|
||||
|
||||
TGDBMIDebugger = class(TCmdLineDebugger)
|
||||
private
|
||||
FCommandQueue: TList;
|
||||
FCommandQueue: TGDBMIDebuggerCommandList;
|
||||
FCurrentCommand: TGDBMIDebuggerCommand;
|
||||
FCommandQueueExecLock: Integer;
|
||||
FCommandProcessingLock: Integer;
|
||||
FProcessingExeCmdLock: Integer;
|
||||
|
||||
FMainAddr: TDbgPtr;
|
||||
FBreakAtMain: TDBGBreakPoint;
|
||||
@ -1449,6 +1458,18 @@ begin
|
||||
Result := '"' + Result + '"';
|
||||
end;
|
||||
|
||||
{ TGDBMIDebuggerCommandList }
|
||||
|
||||
function TGDBMIDebuggerCommandList.Get(Index: Integer): TGDBMIDebuggerCommand;
|
||||
begin
|
||||
Result := TGDBMIDebuggerCommand(inherited Items[Index]);
|
||||
end;
|
||||
|
||||
procedure TGDBMIDebuggerCommandList.Put(Index: Integer; const AValue: TGDBMIDebuggerCommand);
|
||||
begin
|
||||
inherited Items[Index] := AValue;
|
||||
end;
|
||||
|
||||
{ TGDBMIDebuggerCommandChangeFilename }
|
||||
|
||||
function TGDBMIDebuggerCommandChangeFilename.DoExecute: Boolean;
|
||||
@ -4608,8 +4629,6 @@ begin
|
||||
FNextExecQueued := False;
|
||||
//ContinueExecution := True;
|
||||
|
||||
FTheDebugger.FProcessingExeCmdLock := FTheDebugger.FInExecuteCount;
|
||||
try
|
||||
FTheDebugger.QueueExecuteLock; // prevent other commands from executing
|
||||
try
|
||||
if not ExecuteCommand(FCommand, FResult)
|
||||
@ -4686,10 +4705,6 @@ begin
|
||||
debugln(['ERROR: Got NO stop params at all, but was running']);
|
||||
//SetDebuggerState(dsError); // we cannot be running anymore
|
||||
end;
|
||||
finally
|
||||
FTheDebugger.FProcessingExeCmdLock := -1;
|
||||
end;
|
||||
|
||||
end;
|
||||
|
||||
constructor TGDBMIDebuggerCommandExecute.Create(AOwner: TGDBMIDebugger;
|
||||
@ -4702,6 +4717,7 @@ constructor TGDBMIDebuggerCommandExecute.Create(AOwner: TGDBMIDebugger;
|
||||
const ExecType: TGDBMIExecCommandType; Args: array of const);
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
FQueueRunLevel := 0; // Execommands are only allowed at level 0
|
||||
FCanKillNow := False;
|
||||
FDidKillNow := False;;
|
||||
FNextExecQueued := False;
|
||||
@ -5369,7 +5385,7 @@ begin
|
||||
FBreakErrorBreakID := -1;
|
||||
FRunErrorBreakID := -1;
|
||||
FExceptionBreakID := -1;
|
||||
FCommandQueue := TList.Create;
|
||||
FCommandQueue := TGDBMIDebuggerCommandList.Create;
|
||||
FTargetInfo.TargetPID := 0;
|
||||
FTargetInfo.TargetFlags := [];
|
||||
FDebuggerFlags := [];
|
||||
@ -5378,7 +5394,6 @@ begin
|
||||
FSourceNames.Duplicates := dupError;
|
||||
FSourceNames.CaseSensitive := False;
|
||||
FCommandQueueExecLock := 0;
|
||||
FProcessingExeCmdLock := -1;
|
||||
FRunQueueOnUnlock := False;
|
||||
FThreadGroups := TStringList.Create;
|
||||
|
||||
@ -5729,7 +5744,7 @@ begin
|
||||
LockRelease;
|
||||
try
|
||||
repeat
|
||||
Cmd := TGDBMIDebuggerCommand(FCommandQueue[0]);
|
||||
Cmd := FCommandQueue[0];
|
||||
if (Cmd.QueueRunLevel >= 0) and (Cmd.QueueRunLevel < FInExecuteCount)
|
||||
then break;
|
||||
|
||||
@ -5797,49 +5812,65 @@ end;
|
||||
procedure TGDBMIDebugger.QueueCommand(const ACommand: TGDBMIDebuggerCommand; ForceQueue: Boolean = False);
|
||||
var
|
||||
i, p: Integer;
|
||||
QueueExeInExe, CanRunQueue: Boolean;
|
||||
CanRunQueue: Boolean;
|
||||
begin
|
||||
(* TODO: if an exec-command is queued, cancel watches-commands, etc (unless required for snapshot)
|
||||
This may occur if multiply exe are queued.
|
||||
Currently, they will be ForcedQueue, and end up, after the exec command => cancel by state change
|
||||
*)
|
||||
|
||||
|
||||
p := ACommand.Priority;
|
||||
i := 0;
|
||||
// CanRunQueue: The queue can be run for "ACommand"
|
||||
// Either the queue is empty (so no other command will run)
|
||||
// Or the first command on the queue is blocked by "QueueRunLevel"
|
||||
CanRunQueue := (FCommandQueue.Count = 0)
|
||||
or ( (FCommandQueue.Count > 0)
|
||||
and (TGDBMIDebuggerCommand(FCommandQueue[0]).QueueRunLevel >= 0)
|
||||
and (TGDBMIDebuggerCommand(FCommandQueue[0]).QueueRunLevel < FInExecuteCount)
|
||||
and (FCommandQueue[0].QueueRunLevel >= 0)
|
||||
and (FCommandQueue[0].QueueRunLevel < FInExecuteCount)
|
||||
);
|
||||
|
||||
if (ACommand is TGDBMIDebuggerCommandExecute) then begin
|
||||
// Execute-commands, must be queued at the end. They have QueueRunLevel, so they only run in the outer loop
|
||||
CanRunQueue := (FCommandQueue.Count = 0);
|
||||
i := FCommandQueue.Add(ACommand);
|
||||
end
|
||||
else
|
||||
if p > 0 then begin
|
||||
// Queue Pririty commands
|
||||
// TODO: check for "CanRunQueue": should be at start?
|
||||
while (i < FCommandQueue.Count)
|
||||
and (TGDBMIDebuggerCommand(FCommandQueue[i]).Priority >= p)
|
||||
and (FCommandQueue[i].Priority >= p)
|
||||
and ( (ForceQueue)
|
||||
or (TGDBMIDebuggerCommand(FCommandQueue[i]).QueueRunLevel < 0)
|
||||
or (TGDBMIDebuggerCommand(FCommandQueue[i]).QueueRunLevel >= FInExecuteCount)
|
||||
or (FCommandQueue[i].QueueRunLevel < 0)
|
||||
or (FCommandQueue[i].QueueRunLevel >= FInExecuteCount)
|
||||
)
|
||||
do inc(i);
|
||||
FCommandQueue.Insert(i, ACommand);
|
||||
end
|
||||
else begin
|
||||
// Queue normal commands
|
||||
if (not ForceQueue) and (FCommandQueue.Count > 0)
|
||||
and CanRunQueue // first item is deffered, so new item inserted can run
|
||||
and CanRunQueue // first item is deferred, so new item inserted can run
|
||||
then
|
||||
FCommandQueue.Insert(0, ACommand)
|
||||
else
|
||||
i := FCommandQueue.Add(ACommand);
|
||||
end;
|
||||
|
||||
QueueExeInExe := (FProcessingExeCmdLock > 0)
|
||||
and (ACommand is TGDBMIDebuggerCommandExecute);
|
||||
// if other commands do run the queue,
|
||||
// make sure this command only runs after the CurrentCommand finished
|
||||
if ForceQueue then
|
||||
if ForceQueue and
|
||||
( (ACommand.QueueRunLevel < 0) or (ACommand.QueueRunLevel >= FInExecuteCount) )
|
||||
then
|
||||
ACommand.QueueRunLevel := FInExecuteCount - 1;
|
||||
if QueueExeInExe then
|
||||
ACommand.QueueRunLevel := FProcessingExeCmdLock - 1;
|
||||
|
||||
if (not CanRunQueue) or (FCommandQueueExecLock > 0)
|
||||
or (FCommandProcessingLock > 0) or ForceQueue or QueueExeInExe
|
||||
or (FCommandProcessingLock > 0) or ForceQueue
|
||||
then begin
|
||||
{$IFDEF DBGMI_QUEUE_DEBUG}
|
||||
debugln(['Queueing (Recurse-Count=', FInExecuteCount, ') at pos=', i, ' cnt=',FCommandQueue.Count-1, ' State=',DBGStateNames[State], ' Lock=',FCommandQueueExecLock, ' Forced=', dbgs(ForceQueue), ' ExeInExe=', dbgs(QueueExeInExe), ' Prior=',p, ': "', ACommand.DebugText,'"']);
|
||||
debugln(['Queueing (Recurse-Count=', FInExecuteCount, ') at pos=', i, ' cnt=',FCommandQueue.Count-1, ' State=',DBGStateNames[State], ' Lock=',FCommandQueueExecLock, ' Forced=', dbgs(ForceQueue), ' Prior=',p, ': "', ACommand.DebugText,'"']);
|
||||
{$ENDIF}
|
||||
ACommand.DoQueued;
|
||||
|
||||
|
@ -880,7 +880,9 @@ begin
|
||||
then FCurrentBreakpoint := nil;
|
||||
|
||||
// Notify FSnapshots of new state (while dialogs still in updating)
|
||||
if (FCurrentBreakpoint <> nil) and (bpaTakeSnapshot in FCurrentBreakpoint.Actions) then begin
|
||||
if (FCurrentBreakpoint <> nil) and (bpaTakeSnapshot in FCurrentBreakpoint.Actions) and
|
||||
(State in [dsPause, dsInternalPause])
|
||||
then begin
|
||||
FSnapshots.DoStateChange(OldState);
|
||||
FSnapshots.Current.AddToSnapshots;
|
||||
FSnapshots.DoDebuggerIdle(True);
|
||||
|
Loading…
Reference in New Issue
Block a user