in src/Deprecated/Engine/Introspector/Introspector.cs [36:193]
internal int DetectDeadlock( int queueCounts, long lastLoopActivity, int currentTimeout)
{
// Don't try to detect deadlock in single threaded mode or on a child node
if (parentEngine.Router.ChildMode || parentEngine.Router.SingleThreadedMode)
{
return Timeout.Infinite;
}
// Calculate time since last loop activity
TimeSpan timeSinceLastLoopActivity =
new TimeSpan(DateTime.Now.Ticks - lastLoopActivity);
// If there are items in the queue waiting to be processed or there was loop activity
// not so long ago - continue
if (queueCounts > 0 || timeSinceLastLoopActivity.TotalMilliseconds < currentTimeout)
{
return currentTimeout;
}
if (nodeManager.TaskExecutionModule == null)
{
return currentTimeout;
}
// Calculate the time since the last task activity
TimeSpan timeSinceLastTEMActivity =
new TimeSpan(DateTime.Now.Ticks - nodeManager.TaskExecutionModule.LastTaskActivity());
// If there was not task activity for the whole time period - check with individual nodes
// to see if there was activity there
if (timeSinceLastTEMActivity.TotalMilliseconds < currentTimeout)
{
// Increase the timeout since tasks are taking a long time
return calculateNewLoopTimeout(currentTimeout);
}
// Check if we are waiting on an outcome of an operation
if ((ignoreTimeout - DateTime.Now.Ticks) > 0)
{
return currentTimeout;
}
long requestStartTime = DateTime.Now.Ticks;
NodeStatus[] nodeStatus = nodeManager.RequestStatusForNodes(nodeStatusReplyTimeout);
long requestDurationTime = DateTime.Now.Ticks - requestStartTime;
for (int i = 0; i < nodeStatus.Length; i++)
{
if (nodeStatus[i] == null)
{
// A node failed to respond to the request for status. The only option is to shutdown
// the build and error out
LogOrDumpError("FailedToReceiveChildStatus", i + 1, nodeStatusReplyTimeout);
SystemShutdown();
return currentTimeout;
}
else if (nodeStatus[i].HasExited)
{
// A node has exited prematurely. The only option is to shutdown
LogOrDumpError("ChildExitedPrematurely", i + 1);
SystemShutdown();
return currentTimeout;
}
else if (nodeStatus[i].IsActive)
{
// Calculate the time since last node activity
TimeSpan timeSinceLastNodeTaskActivity = new TimeSpan(nodeStatus[i].TimeSinceLastTaskActivity);
TimeSpan timeSinceLastNodeLoopActivity = new TimeSpan(nodeStatus[i].TimeSinceLastLoopActivity);
// Check if there was activity on the node within the timeout
if (nodeStatus[i].QueueDepth > 0 ||
timeSinceLastNodeTaskActivity.TotalMilliseconds < currentTimeout ||
timeSinceLastNodeLoopActivity.TotalMilliseconds < currentTimeout)
{
// If the time out has been exceeded while one of the nodes was
// active lets increase the timeout
return calculateNewLoopTimeout(currentTimeout);
}
}
else if (nodeStatus[i].IsLaunchInProgress)
{
// If there is a node in process of being launched, only the NodeProvider
// knows how long that should take so the decision to error out can
// only be made by the node provider.
return currentTimeout;
}
}
// There was no detected activity within the system for the whole time period. Check
// if there is a cycle in the in progress targets
TargetCycleDetector cycleDetector = new TargetCycleDetector(parentEngine.LoggingServices, parentEngine.EngineCallback);
AddTargetStatesToCycleDetector(nodeStatus, cycleDetector);
NodeStatus localStatus = parentEngine.RequestStatus(0);
cycleDetector.AddTargetsToGraph(localStatus.StateOfInProgressTargets);
if (cycleDetector.FindCycles())
{
if (Engine.debugMode)
{
Console.WriteLine("Breaking cycle between " + cycleDetector.CycleEdgeChild.TargetId.name + " and " +
cycleDetector.CycleEdgeParent.TargetId.name);
}
// A cycle has been detected - it needs to be broken for the build to continue
nodeManager.PostCycleNotification(cycleDetector.CycleEdgeChild.TargetId.nodeId,
cycleDetector.CycleEdgeChild,
cycleDetector.CycleEdgeParent);
// Use the amount of time it took us to receive the NodeStatus and buffer it a little because node status is sent via a faster code path
ignoreTimeout = DateTime.Now.Ticks + requestDurationTime + (cycleBreakTimeout * TimeSpan.TicksPerMillisecond);
return currentTimeout;
}
// The system doesn't appear to be making progress. Switch to a largest sampling interval.
if (currentTimeout != maxLoopTimeout)
{
return maxLoopTimeout;
}
// Should make at least two observations before assuming that no forward progress is being made
if (previousStatus == null || previousLocalStatus == null || nodeStatus.Length != previousStatus.Length)
{
previousStatus = nodeStatus;
previousLocalStatus = localStatus;
return currentTimeout;
}
// There was some activity between previous and current status checks on the local node
if (localStatus.LastLoopActivity != previousLocalStatus.LastLoopActivity ||
localStatus.LastTaskActivity != previousLocalStatus.LastTaskActivity )
{
previousStatus = nodeStatus;
previousLocalStatus = localStatus;
return currentTimeout;
}
for (int i = 0; i < nodeStatus.Length; i++)
{
// There was some activity between previous and current status checks on the child node
if (nodeStatus[i].LastTaskActivity != previousStatus[i].LastTaskActivity ||
nodeStatus[i].LastLoopActivity != previousStatus[i].LastLoopActivity)
{
previousStatus = nodeStatus;
previousLocalStatus = localStatus;
return currentTimeout;
}
}
// The system is not making forward progress for an unknown reason. The
// only recourse to is to collect as much data as possible and shutdown with
// an error message
// UNDONE - using logging and resource string to output the state dump
GatherNodeInformationForShutdown(nodeStatus, localStatus);
SystemShutdown();
return currentTimeout;
}