Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/Utilities/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,10 @@
<data name="ToolTask.ToolCommandExitedZeroWithErrors" xml:space="preserve">
<value>The command exited with return value 0, but errors were detected during execution. ExitCode was set to -1.</value>
</data>
<data name="ToolTask.PipeEofTimeoutOnExit" xml:space="preserve">
<value>Tool process exited but did not close its stdout/stderr pipes within {0} seconds. Output may be truncated; this usually indicates a grandchild process inherited the pipes.</value>
<comment>{StrBegin="MSBUILD : "}{0} is the configured EOF timeout in seconds (e.g. "30"). Logged at MessageImportance.Low.</comment>
</data>
<!--
The Utilities message bucket is: MSB6001 - MSB6200

Expand Down
5 changes: 5 additions & 0 deletions src/Utilities/Resources/xlf/Strings.cs.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Utilities/Resources/xlf/Strings.de.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Utilities/Resources/xlf/Strings.es.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Utilities/Resources/xlf/Strings.fr.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Utilities/Resources/xlf/Strings.it.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Utilities/Resources/xlf/Strings.ja.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Utilities/Resources/xlf/Strings.ko.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Utilities/Resources/xlf/Strings.pl.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Utilities/Resources/xlf/Strings.pt-BR.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Utilities/Resources/xlf/Strings.ru.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Utilities/Resources/xlf/Strings.tr.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Utilities/Resources/xlf/Strings.zh-Hans.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Utilities/Resources/xlf/Strings.zh-Hant.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

47 changes: 43 additions & 4 deletions src/Utilities/ToolTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1127,12 +1127,51 @@ private void WaitForProcessExit(Process proc)
// (delivering any final partial line) and sends Data=null via the callback.
// Our ReceiveStandardErrorOrOutputData handler signals the EOF events.
//
// Use a bounded timeout as a safety net for the grandchild case where
// EOF never arrives because grand child inherited the pipe and keeps it open.
const int eofTimeoutSec = 2;
// We poll in short slices and drain whatever has already been delivered
// between slices. That way, even if the outer budget expires (the
// grandchild-inherited-pipe case), every line the reader already pushed
// onto our queues has been logged before we return -- the caller's
// single post-return drain is no longer the only chance.
//
// The total budget is bounded as a safety net for grandchildren that
// keep the pipes open forever. 30 s is large compared to the worst CI
// pipe-flush latency observed (#13734) but still small compared to
// legitimate tool runtimes that would have already hit their own timeout.
const int eofTimeoutMs = 30_000;
const int sliceMs = 50;

WaitHandle[] eofEvents = [_standardOutputEOF, _standardErrorEOF];
WaitHandle.WaitAll(eofEvents, TimeSpan.FromSeconds(eofTimeoutSec));
int waitedMs = 0;
bool eofReached = false;
while (waitedMs < eofTimeoutMs)
{
int thisSlice = Math.Min(sliceMs, eofTimeoutMs - waitedMs);
if (WaitHandle.WaitAll(eofEvents, thisSlice))
{
eofReached = true;
break;
}

// Pump whatever the reader has delivered so far. The consumer
// loop calls these again after we return; calling them here is
// safe because the underlying queues are drained, and it ensures
// no data is lost if we ultimately time out below.
LogMessagesFromStandardError();
LogMessagesFromStandardOutput();
waitedMs += thisSlice;
}

if (!eofReached)
{
// Rare grandchild-inherited-pipe case. Surface it as a low-importance
// diagnostic so that future occurrences are recognizable in the
// binlog without needing to repro. Output up to this point has
// already been logged by the drain loop above.
LogPrivate.LogMessageFromResources(
MessageImportance.Low,
"ToolTask.PipeEofTimeoutOnExit",
eofTimeoutMs / 1000);
}
}
else
{
Expand Down
Loading