internal bool TryCreateWait(WeakTrackedLockReference weakLock, out DeadlockInfo deadlock, out Wait wait) { var lck = (TrackedLock)weakLock.Target; if (lck == null) { wait = default(Wait); deadlock = default(DeadlockInfo); return(false); } var currentThread = Thread.CurrentThread; var waits = Waits.GetOrCreate(lck, MakeWaitList); wait = new Wait(this, lck, currentThread); lock (waits) waits.Enqueue(wait, false); deadlock = DetectDeadlock(wait); if (deadlock != null) { lock (waits) waits.Remove(wait); var wasSignaled = wait.IsSignaled; wait.Dispose(); wait = null; // It's possible, albeit incredibly unlikely, for someone to call Wake on our wait // before we do the deadlock check. // If this happens, try to dequeue another wait from the queue and wake it up in our stead. // This can probably still break, though... if (wasSignaled) { if (TryDequeueOneWait(lck, out wait)) { wait.Wake(); } } return(false); } return(true); }
// Obtain deadlock details - new style location based logic private int[] SetDeadlockLocationBased(int index, TrackCircuitPartialPathRoute route, TrackCircuitPartialPathRoute otherRoute, Train otherTrain) { int[] returnValue = new int[2]; returnValue[1] = -1; // set to no alternative path used TrackCircuitRouteElement firstElement = route[index]; int firstSectionIndex = firstElement.TrackCircuitSection.Index; bool alreadyActive = false; int trainSectionIndex; int otherTrainSectionIndex; // double index variables required as last valid index must be known when exiting loop int trainIndex = index; int trainNextIndex = trainIndex; int otherTrainIndex = otherRoute.GetRouteIndex(firstSectionIndex, 0); int otherTrainNextIndex = otherTrainIndex; int otherFirstIndex = otherTrainIndex; TrackCircuitRouteElement trainElement; TrackCircuitRouteElement otherTrainElement; bool validPassLocation = false; int endSectionRouteIndex = -1; bool endOfLoop = false; // loop while not at end of route for either train and sections are equal // loop is also exited when alternative path is found for either train while (!endOfLoop) { trainIndex = trainNextIndex; trainElement = route[trainIndex]; otherTrainIndex = otherTrainNextIndex; trainSectionIndex = trainElement.TrackCircuitSection.Index; otherTrainElement = otherRoute[otherTrainIndex]; otherTrainSectionIndex = otherTrainElement.TrackCircuitSection.Index; TrackCircuitSection section = otherTrainElement.TrackCircuitSection; // if sections not equal : test length of next not-common section, if long enough then exit loop if (trainSectionIndex != otherTrainSectionIndex) { int nextThisRouteIndex = trainIndex; TrackCircuitSection passLoopSection = ValidRoute[0][nextThisRouteIndex].TrackCircuitSection; _ = otherRoute.GetRouteIndex(passLoopSection.Index, otherTrainIndex); float passLength = passLoopSection.Length; bool endOfPassLoop = false; while (!endOfPassLoop) { // loop is longer as at least one of the trains so is valid if (passLength > Length || passLength > otherTrain.Length) { endOfPassLoop = true; endOfLoop = true; } // get next section else if (nextThisRouteIndex < ValidRoute[0].Count - 2) { nextThisRouteIndex++; passLoopSection = ValidRoute[0][nextThisRouteIndex].TrackCircuitSection; int nextOtherRouteIndex = otherRoute.GetRouteIndexBackward(passLoopSection.Index, otherTrainIndex); // new common section after too short loop - not a valid deadlock point if (nextOtherRouteIndex >= 0) { endOfPassLoop = true; trainNextIndex = nextThisRouteIndex; otherTrainNextIndex = nextOtherRouteIndex; } else { passLength += passLoopSection.Length; } } // end of route else { endOfPassLoop = true; endOfLoop = true; } } } // if section is a deadlock boundary, check available paths for both trains else { List <int> trainAllocatedPaths = new List <int>(); List <int> otherTrainAllocatedPaths = new List <int>(); bool gotoNextSection = true; if (section.DeadlockReference >= 0 && trainElement.FacingPoint) // test for facing points only { bool trainFits = false; bool otherTrainFits = false; int endSectionIndex = -1; validPassLocation = true; // get allocated paths for this train DeadlockInfo deadlockInfo = Simulator.Instance.SignalEnvironment.DeadlockInfoList[section.DeadlockReference]; // get allocated paths for this train - if none yet set, create references int trainReferenceIndex = deadlockInfo.GetTrainAndSubpathIndex(Number, TCRoute.ActiveSubPath); if (!deadlockInfo.TrainReferences.ContainsKey(trainReferenceIndex)) { deadlockInfo.SetTrainDetails(Number, TCRoute.ActiveSubPath, Length, ValidRoute[0], trainIndex); } // if valid path for this train if (deadlockInfo.TrainReferences.ContainsKey(trainReferenceIndex)) { trainAllocatedPaths = deadlockInfo.TrainReferences[deadlockInfo.GetTrainAndSubpathIndex(Number, TCRoute.ActiveSubPath)]; // if paths available, get end section and check train against shortest path if (trainAllocatedPaths.Count > 0) { endSectionIndex = deadlockInfo.AvailablePathList[trainAllocatedPaths[0]].EndSectionIndex; endSectionRouteIndex = route.GetRouteIndex(endSectionIndex, trainIndex); Dictionary <int, bool> trainFitList = deadlockInfo.TrainLengthFit[deadlockInfo.GetTrainAndSubpathIndex(Number, TCRoute.ActiveSubPath)]; foreach (int i in trainAllocatedPaths) { if (trainFitList[i]) { trainFits = true; break; } } } } else { validPassLocation = false; } // get allocated paths for other train - if none yet set, create references int otherTrainReferenceIndex = deadlockInfo.GetTrainAndSubpathIndex(otherTrain.Number, otherTrain.TCRoute.ActiveSubPath); if (!deadlockInfo.TrainReferences.ContainsKey(otherTrainReferenceIndex)) { int otherTrainElementIndex = otherTrain.ValidRoute[0].GetRouteIndexBackward(endSectionIndex, otherFirstIndex); if (otherTrainElementIndex < 0) // train joins deadlock area on different node { validPassLocation = false; deadlockInfo.RemoveTrainAndSubpathIndex(otherTrain.Number, otherTrain.TCRoute.ActiveSubPath); // remove index as train has no valid path } else { deadlockInfo.SetTrainDetails(otherTrain.Number, otherTrain.TCRoute.ActiveSubPath, otherTrain.Length, otherTrain.ValidRoute[0], otherTrainElementIndex); } } // if valid path for other train if (validPassLocation && deadlockInfo.TrainReferences.ContainsKey(otherTrainReferenceIndex)) { otherTrainAllocatedPaths = deadlockInfo.TrainReferences[deadlockInfo.GetTrainAndSubpathIndex(otherTrain.Number, otherTrain.TCRoute.ActiveSubPath)]; // if paths available, get end section (if not yet set) and check train against shortest path if (otherTrainAllocatedPaths.Count > 0) { if (endSectionRouteIndex < 0) { endSectionIndex = deadlockInfo.AvailablePathList[otherTrainAllocatedPaths[0]].EndSectionIndex; endSectionRouteIndex = route.GetRouteIndex(endSectionIndex, trainIndex); } Dictionary <int, bool> otherTrainFitList = deadlockInfo.TrainLengthFit[deadlockInfo.GetTrainAndSubpathIndex(otherTrain.Number, otherTrain.TCRoute.ActiveSubPath)]; foreach (int iPath in otherTrainAllocatedPaths) { if (otherTrainFitList[iPath]) { otherTrainFits = true; break; } } } } else // other train has no valid path relating to the passing path, so passing not possible { validPassLocation = false; } // if both trains have only one route, make sure it's not the same (inverse) route if (trainAllocatedPaths.Count == 1 && otherTrainAllocatedPaths.Count == 1) { if (deadlockInfo.InverseInfo.ContainsKey(trainAllocatedPaths[0]) && deadlockInfo.InverseInfo[trainAllocatedPaths[0]] == otherTrainAllocatedPaths[0]) { validPassLocation = false; } } // if there are passing paths and at least one train fits in shortest path, it is a valid location so break loop if (validPassLocation) { gotoNextSection = false; if (trainFits || otherTrainFits) { if (section.IsSet(otherTrain, true)) { alreadyActive = true; } endOfLoop = true; } else { trainNextIndex = endSectionRouteIndex; otherTrainNextIndex = otherRoute.GetRouteIndexBackward(endSectionIndex, otherTrainIndex); if (otherTrainNextIndex < 0) { endOfLoop = true; } } } } // if loop not yet ended - not a valid pass location, move to next section (if available) if (gotoNextSection) { // if this section is occupied by other train, break loop - further checks are of no use if (section.IsSet(otherTrain, true)) { alreadyActive = true; endOfLoop = true; } else { trainNextIndex++; otherTrainNextIndex--; if (trainNextIndex > route.Count - 1 || otherTrainNextIndex < 0) { endOfLoop = true; // end of path reached for either train } } } } } // if valid pass location : set return index if (validPassLocation && endSectionRouteIndex >= 0) { returnValue[1] = endSectionRouteIndex; } // get sections on which loop ended trainElement = route[trainIndex]; trainSectionIndex = trainElement.TrackCircuitSection.Index; otherTrainElement = otherRoute[otherTrainIndex]; otherTrainSectionIndex = otherTrainElement.TrackCircuitSection.Index; // if last sections are still equal - end of route reached for one of the trains // otherwise, last common sections was previous sections for this train TrackCircuitSection lastSection = (trainSectionIndex == otherTrainSectionIndex) ? TrackCircuitSection.TrackCircuitList[trainSectionIndex] : route[trainIndex - 1].TrackCircuitSection; // TODO : if section is not a junction but deadlock is already active, wind back to last junction // if section is not a junction, check if either route not ended, if so continue up to next junction if (lastSection.CircuitType != TrackCircuitType.Junction) { bool endSectionFound = false; if (trainIndex < (route.Count - 1)) { for (int iIndex = trainIndex; iIndex < route.Count - 1 && !endSectionFound; iIndex++) { lastSection = route[iIndex].TrackCircuitSection; endSectionFound = lastSection.CircuitType == TrackCircuitType.Junction; } } else if (otherTrainIndex > 0) { for (int i = otherTrainIndex; i >= 0 && !endSectionFound; i--) { lastSection = otherRoute[i].TrackCircuitSection; endSectionFound = false; // junction found - end of loop if (lastSection.CircuitType == TrackCircuitType.Junction) { endSectionFound = true; } // train has active wait condition at this location - end of loop else if (otherTrain.CheckWaitCondition(lastSection.Index)) { endSectionFound = true; } if (lastSection.IsSet(otherTrain, true)) { alreadyActive = true; } } } } // set deadlock info for both trains SetDeadlockInfo(firstSectionIndex, lastSection.Index, otherTrain.Number); otherTrain.SetDeadlockInfo(lastSection.Index, firstSectionIndex, Number); if (alreadyActive) { lastSection.SetDeadlockTrap(otherTrain, otherTrain.DeadlockInfo[lastSection.Index]); returnValue[1] = route.Count; // set beyond end of route - no further checks required } // if any section occupied by own train, reverse deadlock is active TrackCircuitSection firstSection = TrackCircuitSection.TrackCircuitList[firstSectionIndex]; int firstRouteIndex = ValidRoute[0].GetRouteIndex(firstSectionIndex, 0); int lastRouteIndex = ValidRoute[0].GetRouteIndex(lastSection.Index, 0); for (int i = firstRouteIndex; i < lastRouteIndex; i++) { TrackCircuitSection partSection = ValidRoute[0][i].TrackCircuitSection; if (partSection.IsSet(this, true)) { firstSection.SetDeadlockTrap(this, DeadlockInfo[firstSectionIndex]); } } returnValue[0] = route.GetRouteIndex(lastSection.Index, index); if (returnValue[0] < 0) { returnValue[0] = trainIndex; } return(returnValue); }
internal bool TryCreateWait (WeakTrackedLockReference weakLock, out DeadlockInfo deadlock, out Wait wait) { var lck = (TrackedLock)weakLock.Target; if (lck == null) { wait = default(Wait); deadlock = default(DeadlockInfo); return false; } var currentThread = Thread.CurrentThread; var waits = Waits.GetOrCreate(lck, MakeWaitList); wait = new Wait(this, lck, currentThread); lock (waits) waits.Enqueue(wait, false); deadlock = DetectDeadlock(wait); if (deadlock != null) { lock (waits) waits.Remove(wait); var wasSignaled = wait.IsSignaled; wait.Dispose(); wait = null; // It's possible, albeit incredibly unlikely, for someone to call Wake on our wait // before we do the deadlock check. // If this happens, try to dequeue another wait from the queue and wake it up in our stead. // This can probably still break, though... if (wasSignaled) { if (TryDequeueOneWait(lck, out wait)) wait.Wake(); } return false; } return true; }