Exemple #1
0
        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);
        }
Exemple #3
0
        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;
        }