mirror of https://gitlab.com/basile.b/dexed.git
fix #336 - Out of order messages
This commit is contained in:
parent
a5d47eb6d1
commit
492cd4e8e5
|
@ -2586,7 +2586,7 @@ end;
|
||||||
procedure TGdbWidget.gdboutQuiet(sender: TObject);
|
procedure TGdbWidget.gdboutQuiet(sender: TObject);
|
||||||
begin
|
begin
|
||||||
fCommandProcessed := true;
|
fCommandProcessed := true;
|
||||||
fGdb.OutputStack.Clear;
|
fGdb.StdoutEx.Clear;
|
||||||
fGdb.OnReadData:=@gdboutJsonize;
|
fGdb.OnReadData:=@gdboutJsonize;
|
||||||
end;
|
end;
|
||||||
{$ENDREGION}
|
{$ENDREGION}
|
||||||
|
|
|
@ -5,7 +5,7 @@ unit u_processes;
|
||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils, ExtCtrls, process, asyncprocess;
|
Classes, SysUtils, ExtCtrls, process, asyncprocess, pipes;
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
||||||
|
@ -19,6 +19,9 @@ type
|
||||||
- TAsyncProcess.OnReadData event is not usable to read full output lines.
|
- TAsyncProcess.OnReadData event is not usable to read full output lines.
|
||||||
Here the output is accumulated in a TMemoryStream which allows to keep data
|
Here the output is accumulated in a TMemoryStream which allows to keep data
|
||||||
at the left of an unterminated line when a buffer is available.
|
at the left of an unterminated line when a buffer is available.
|
||||||
|
- When StdErr is redirect to Output, both streams can be blended. Here the
|
||||||
|
option is deactivated on execution, a falg is set, and the error stream
|
||||||
|
is always added to after the output.
|
||||||
|
|
||||||
The member Output is not usable anymore. Instead:
|
The member Output is not usable anymore. Instead:
|
||||||
|
|
||||||
|
@ -29,10 +32,11 @@ type
|
||||||
}
|
}
|
||||||
TDexedProcess = class(TASyncProcess)
|
TDexedProcess = class(TASyncProcess)
|
||||||
private
|
private
|
||||||
|
fErrToOut: boolean;
|
||||||
fRealOnTerminate: TNotifyEvent;
|
fRealOnTerminate: TNotifyEvent;
|
||||||
fRealOnReadData: TNotifyEvent;
|
fRealOnReadData: TNotifyEvent;
|
||||||
fOutputStack: TMemoryStream;
|
fStdoutEx: TMemoryStream;
|
||||||
fStdError: TMemoryStream;
|
fStderrEx: TMemoryStream;
|
||||||
fTerminateChecker: TTimer;
|
fTerminateChecker: TTimer;
|
||||||
fDoneTerminated: boolean;
|
fDoneTerminated: boolean;
|
||||||
fHasRead: boolean;
|
fHasRead: boolean;
|
||||||
|
@ -49,12 +53,14 @@ type
|
||||||
constructor create(aOwner: TComponent); override;
|
constructor create(aOwner: TComponent); override;
|
||||||
destructor destroy; override;
|
destructor destroy; override;
|
||||||
procedure execute; override;
|
procedure execute; override;
|
||||||
// reads TProcess.OUtput in OutputStack
|
// reads TProcess.Output and StdErr in their "Ex" versions.
|
||||||
procedure fillOutputStack;
|
procedure fillOutputStack;
|
||||||
// fills list with the full lines contained in OutputStack
|
// fills list with the full lines contained in StdoutEx
|
||||||
procedure getFullLines(list: TStrings; consume: boolean = true);
|
procedure getFullLines(list: TStrings; consume: boolean = true);
|
||||||
// access to a flexible copy of TProcess.Output
|
// access to a flexible copy of TProcess.Output
|
||||||
property OutputStack: TMemoryStream read fOutputStack;
|
property StdoutEx: TMemoryStream read fStdoutEx;
|
||||||
|
// access to a flexible copy of TProcess.Error
|
||||||
|
property StdErrEx: TMemoryStream read fStderrEx;
|
||||||
// indicates if an output buffer is read
|
// indicates if an output buffer is read
|
||||||
property hasRead: boolean read fHasRead;
|
property hasRead: boolean read fHasRead;
|
||||||
end;
|
end;
|
||||||
|
@ -160,13 +166,12 @@ end;
|
||||||
constructor TDexedProcess.create(aOwner: TComponent);
|
constructor TDexedProcess.create(aOwner: TComponent);
|
||||||
begin
|
begin
|
||||||
inherited;
|
inherited;
|
||||||
FOutputStack := TMemoryStream.Create;
|
fStdoutEx := TMemoryStream.Create;
|
||||||
fStdError := TMemoryStream.Create;
|
fStderrEx := TMemoryStream.Create;
|
||||||
FTerminateChecker := TTimer.Create(nil);
|
FTerminateChecker := TTimer.Create(nil);
|
||||||
FTerminateChecker.Interval := 50;
|
FTerminateChecker.Interval := 50;
|
||||||
fTerminateChecker.OnTimer := @checkTerminated;
|
fTerminateChecker.OnTimer := @checkTerminated;
|
||||||
fTerminateChecker.Enabled := false;
|
fTerminateChecker.Enabled := false;
|
||||||
//fTerminateChecker.AutoEnabled:= true;
|
|
||||||
TAsyncProcess(self).OnTerminate := @internalDoOnTerminate;
|
TAsyncProcess(self).OnTerminate := @internalDoOnTerminate;
|
||||||
TAsyncProcess(self).OnReadData := @internalDoOnReadData;
|
TAsyncProcess(self).OnReadData := @internalDoOnReadData;
|
||||||
end;
|
end;
|
||||||
|
@ -174,17 +179,20 @@ end;
|
||||||
destructor TDexedProcess.destroy;
|
destructor TDexedProcess.destroy;
|
||||||
begin
|
begin
|
||||||
FTerminateChecker.Free;
|
FTerminateChecker.Free;
|
||||||
FOutputStack.Free;
|
fStdoutEx.Free;
|
||||||
fStdError.Free;
|
fStderrEx.Free;
|
||||||
inherited;
|
inherited;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TDexedProcess.Execute;
|
procedure TDexedProcess.Execute;
|
||||||
begin
|
begin
|
||||||
fHasRead := false;
|
fHasRead := false;
|
||||||
fOutputStack.Clear;
|
fStdoutEx.Clear;
|
||||||
fStdError.Clear;
|
fStderrEx.Clear;
|
||||||
fDoneTerminated := false;
|
fDoneTerminated := false;
|
||||||
|
fErrToOut := poStderrToOutPut in Options;
|
||||||
|
if fErrToOut then
|
||||||
|
Options := Options - [poStderrToOutPut];
|
||||||
TAsyncProcess(self).OnReadData := @internalDoOnReadData;
|
TAsyncProcess(self).OnReadData := @internalDoOnReadData;
|
||||||
TAsyncProcess(self).OnTerminate := @internalDoOnTerminate;
|
TAsyncProcess(self).OnTerminate := @internalDoOnTerminate;
|
||||||
fTerminateChecker.Enabled := true;
|
fTerminateChecker.Enabled := true;
|
||||||
|
@ -192,21 +200,28 @@ begin
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TDexedProcess.fillOutputStack;
|
procedure TDexedProcess.fillOutputStack;
|
||||||
var
|
|
||||||
sum, cnt: Integer;
|
procedure fill(inStr: TInputPipeStream; outStr: TMemoryStream);
|
||||||
|
var
|
||||||
|
s: integer;
|
||||||
|
c: integer;
|
||||||
|
begin
|
||||||
|
s := outStr.size;
|
||||||
|
while (inStr <> nil) and (inStr.NumBytesAvailable > 0) do
|
||||||
|
begin
|
||||||
|
outStr.SetSize(s + 1024);
|
||||||
|
c := inStr.Read((outStr.Memory + s)^, 1024);
|
||||||
|
s += c;
|
||||||
|
end;
|
||||||
|
outStr.SetSize(s);
|
||||||
|
end;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
if not (poUsePipes in Options) then
|
if not (poUsePipes in Options) then
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
// output
|
fill(Output, StdoutEx);
|
||||||
sum := fOutputStack.Size;
|
fill(Stderr, stderrEx);
|
||||||
while (Output <> nil) and (NumBytesAvailable > 0) do
|
|
||||||
begin
|
|
||||||
fOutputStack.SetSize(sum + 1024);
|
|
||||||
cnt := Output.Read((fOutputStack.Memory + sum)^, 1024);
|
|
||||||
sum += cnt;
|
|
||||||
end;
|
|
||||||
fOutputStack.SetSize(sum);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TDexedProcess.getFullLines(list: TStrings; consume: boolean = true);
|
procedure TDexedProcess.getFullLines(list: TStrings; consume: boolean = true);
|
||||||
|
@ -219,23 +234,33 @@ var
|
||||||
begin
|
begin
|
||||||
if not Running then
|
if not Running then
|
||||||
begin
|
begin
|
||||||
list.LoadFromStream(fOutputStack);
|
// stderr has been read in its own stream
|
||||||
|
// preventing interleaving, now put it at the end...
|
||||||
|
if (poStderrToOutPut in Options) or fErrToOut then
|
||||||
|
begin
|
||||||
|
fStdoutEx.Position:=fStdoutEx.Size;
|
||||||
|
fStdoutEx.Write(fStderrEx.Memory^, fStderrEx.Size);
|
||||||
if consume then
|
if consume then
|
||||||
fOutputStack.Clear;
|
fStderrEx.Clear;
|
||||||
|
end;
|
||||||
|
fStdoutEx.Position:=0;
|
||||||
|
list.LoadFromStream(fStdoutEx);
|
||||||
|
if consume then
|
||||||
|
fStdoutEx.Clear;
|
||||||
end else
|
end else
|
||||||
begin
|
begin
|
||||||
lastTerm := fOutputStack.Position;
|
lastTerm := fStdoutEx.Position;
|
||||||
stored := fOutputStack.Position;
|
stored := fStdoutEx.Position;
|
||||||
while fOutputStack.Read(buff, 1) = 1 do
|
while fStdoutEx.Read(buff, 1) = 1 do
|
||||||
if buff = 10 then lastTerm := fOutputStack.Position;
|
if buff = 10 then lastTerm := fStdoutEx.Position;
|
||||||
fOutputStack.Position := stored;
|
fStdoutEx.Position := stored;
|
||||||
if lastTerm <> stored then
|
if lastTerm <> stored then
|
||||||
begin
|
begin
|
||||||
str := TMemoryStream.Create;
|
str := TMemoryStream.Create;
|
||||||
try
|
try
|
||||||
toread := lastTerm - stored;
|
toread := lastTerm - stored;
|
||||||
str.SetSize(toRead);
|
str.SetSize(toRead);
|
||||||
fOutputStack.Read(str.Memory^, toread);
|
fStdoutEx.Read(str.Memory^, toread);
|
||||||
list.LoadFromStream(str);
|
list.LoadFromStream(str);
|
||||||
finally
|
finally
|
||||||
str.Free;
|
str.Free;
|
||||||
|
@ -271,6 +296,11 @@ begin
|
||||||
if fDoneTerminated then exit;
|
if fDoneTerminated then exit;
|
||||||
fDoneTerminated := true;
|
fDoneTerminated := true;
|
||||||
|
|
||||||
|
// restore if same proc is called again,
|
||||||
|
// self.execute will exclude the option.
|
||||||
|
if fErrToOut then
|
||||||
|
Options := Options + [poStderrToOutPut];
|
||||||
|
|
||||||
// note: made to fix a leak in the process used by the linter
|
// note: made to fix a leak in the process used by the linter
|
||||||
// onTerminate is sometimes determined by an internal timer
|
// onTerminate is sometimes determined by an internal timer
|
||||||
// and not the base method of TAsyncProcess (which usually unhooks)
|
// and not the base method of TAsyncProcess (which usually unhooks)
|
||||||
|
@ -310,19 +340,19 @@ end;
|
||||||
|
|
||||||
procedure TAutoBufferedProcess.execute;
|
procedure TAutoBufferedProcess.execute;
|
||||||
begin
|
begin
|
||||||
fPreviousSize := fOutputStack.Size;
|
fPreviousSize := fStdoutEx.Size;
|
||||||
fNewBufferChecker.Enabled:=true;
|
fNewBufferChecker.Enabled:=true;
|
||||||
inherited;
|
inherited;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TAutoBufferedProcess.newBufferCheckerChecks(sender: TObject);
|
procedure TAutoBufferedProcess.newBufferCheckerChecks(sender: TObject);
|
||||||
begin
|
begin
|
||||||
if fOutputStack.Size = fPreviousSize then
|
if fStdoutEx.Size = fPreviousSize then
|
||||||
begin
|
begin
|
||||||
if assigned(fRealOnReadData) then
|
if assigned(fRealOnReadData) then
|
||||||
fRealOnReadData(self);
|
fRealOnReadData(self);
|
||||||
end;
|
end;
|
||||||
fPreviousSize := fOutputStack.Size;
|
fPreviousSize := fStdoutEx.Size;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TAutoBufferedProcess.internalDoOnReadData(sender: TObject);
|
procedure TAutoBufferedProcess.internalDoOnReadData(sender: TObject);
|
||||||
|
|
|
@ -861,10 +861,10 @@ begin
|
||||||
|
|
||||||
fToolProc.OnTerminate := nil;
|
fToolProc.OnTerminate := nil;
|
||||||
fToolProc.OnReadData := nil;
|
fToolProc.OnReadData := nil;
|
||||||
fToolProc.OutputStack.Position:=0;
|
fToolProc.StdoutEx.Position:=0;
|
||||||
if fToolProc.OutputStack.Size = 0 then
|
if fToolProc.StdoutEx.Size = 0 then
|
||||||
exit;
|
exit;
|
||||||
fSyms.LoadFromTool(fToolProc.OutputStack);
|
fSyms.LoadFromTool(fToolProc.StdoutEx);
|
||||||
|
|
||||||
flt := TreeFilterEdit1.Filter;
|
flt := TreeFilterEdit1.Filter;
|
||||||
TreeFilterEdit1.Text := '';
|
TreeFilterEdit1.Text := '';
|
||||||
|
|
|
@ -488,8 +488,8 @@ end;
|
||||||
|
|
||||||
procedure TTodoListWidget.toolTerminated(Sender: TObject);
|
procedure TTodoListWidget.toolTerminated(Sender: TObject);
|
||||||
begin
|
begin
|
||||||
fToolProc.OutputStack.Position := 0;
|
fToolProc.StdoutEx.Position := 0;
|
||||||
fTodos.loadFromTxtStream(fToolProc.OutputStack);
|
fTodos.loadFromTxtStream(fToolProc.StdoutEx);
|
||||||
fillTodoList;
|
fillTodoList;
|
||||||
fToolProc.OnTerminate := nil;
|
fToolProc.OnTerminate := nil;
|
||||||
end;
|
end;
|
||||||
|
|
|
@ -235,9 +235,9 @@ begin
|
||||||
if previous.isNotNil and previous.outputToNext
|
if previous.isNotNil and previous.outputToNext
|
||||||
and (poUsePipes in previous.Options) and (poUsePipes in Options) then
|
and (poUsePipes in previous.Options) and (poUsePipes in Options) then
|
||||||
begin
|
begin
|
||||||
setLength(inp, previous.process.OutputStack.Size);
|
setLength(inp, previous.process.StdoutEx.Size);
|
||||||
previous.process.OutputStack.Position:=0;
|
previous.process.StdoutEx.Position:=0;
|
||||||
previous.process.OutputStack.Read(inp[1], inp.length);
|
previous.process.StdoutEx.Read(inp[1], inp.length);
|
||||||
fProcess.Input.Write(inp[1], inp.length);
|
fProcess.Input.Write(inp[1], inp.length);
|
||||||
fProcess.CloseInput;
|
fProcess.CloseInput;
|
||||||
end;
|
end;
|
||||||
|
|
Loading…
Reference in New Issue