Пример #1
0
        /// <summary>
        /// Returns or forces the next choice to schedule.
        /// </summary>
        private bool GetNextHelper(ref IAsyncOperation next, List <IAsyncOperation> ops, IAsyncOperation current)
        {
            int currentSchedulableId = (int)current.SourceId;

            // "Yield" and "Waiting for quiescence" hack.
            if (ops.TrueForAll(op => !op.IsEnabled))
            {
                if (ops.Exists(op => op.Type is AsyncOperationType.Yield))
                {
                    foreach (var op in ops)
                    {
                        if (op.Type is AsyncOperationType.Yield)
                        {
                            op.IsEnabled = true;
                        }
                    }
                }
                else if (ops.Exists(op => op.Type is AsyncOperationType.WaitForQuiescence))
                {
                    foreach (var op in ops)
                    {
                        if (op.Type is AsyncOperationType.WaitForQuiescence)
                        {
                            op.IsEnabled = true;
                        }
                    }
                }
            }

            // Forced choice.
            if (next != null)
            {
                this.AbdandonReplay(false);
            }

            bool          added = this.Stack.Push(ops);
            TaskEntryList top   = this.Stack.GetTop();

            Debug.Assert(next is null || added, "DPOR: Forced choice implies we should have added to stack.");

            if (added)
            {
                if (this.UseSleepSets)
                {
                    SleepSets.UpdateSleepSets(this.Stack);
                }

                if (this.Dpor is null)
                {
                    top.SetAllEnabledToBeBacktracked();
                }
                else if (this.Dpor.RaceReplaySuffix.Count > 0 && this.Dpor.ReplayRaceIndex < this.Dpor.RaceReplaySuffix.Count)
                {
                    // Replaying a race:
                    var tidReplay = this.Dpor.RaceReplaySuffix[this.Dpor.ReplayRaceIndex];

                    // Restore the nondet choices on the top of stack.
                    top.NondetChoices = tidReplay.NondetChoices;

                    // Add the replay tid to the backtrack set.
                    top.List[tidReplay.Id].Backtrack = true;
                    Debug.Assert(top.List[tidReplay.Id].Enabled || top.List[tidReplay.Id].OpType is AsyncOperationType.Yield, "Failed.");
                    ++this.Dpor.ReplayRaceIndex;
                }
                else
                {
                    // TODO: Here is where we can combine with another scheduler:
                    // For now, we just do round-robin when doing DPOR and random when doing random DPOR.

                    // If our choice is forced by parent scheduler:
                    if (next != null)
                    {
                        top.AddToBacktrack((int)next.SourceId);
                    }
                    else if (this.Rand is null)
                    {
                        top.AddFirstEnabledNotSleptToBacktrack(currentSchedulableId);
                    }
                    else
                    {
                        top.AddRandomEnabledNotSleptToBacktrack(this.Rand);
                    }
                }
            }
            else if (this.Rand != null)
            {
                // When doing random DPOR: we are replaying a schedule prefix so rewind the nondet choices now.
                top.RewindNondetChoicesForReplay();
            }

            int nextTid = this.Stack.GetSelectedOrFirstBacktrackNotSlept(currentSchedulableId);

            if (nextTid < 0)
            {
                next = null;

                // TODO: if nextTidIndex == DPORAlgorithm.SLEEP_SET_BLOCKED then let caller know that this is the case.
                // I.e. this is not deadlock.
                return(false);
            }

            if (top.TryGetSelected() != nextTid)
            {
                top.SetSelected(nextTid);
            }

            Debug.Assert(nextTid < ops.Count, "nextTid >= choices.Count");
            next = ops[nextTid];

            // TODO: Part of yield hack.
            if (!next.IsEnabled && next.Type is AsyncOperationType.Yield)
            {
                // Uncomment to avoid waking a yielding task.
                // next = null;
                // TODO: let caller know that this is not deadlock.
                // return false;
                next.IsEnabled = true;
            }

            Debug.Assert(next.IsEnabled, "Not enabled.");
            return(true);
        }
Пример #2
0
        /// <summary>
        /// Returns or forces the next choice to schedule.
        /// </summary>
        /// <param name="next">Next</param>
        /// <param name="choices">Choices</param>
        /// <param name="current">Curent</param>
        private bool GetNextHelper(
            ref ISchedulable next,
            List <ISchedulable> choices,
            ISchedulable current)
        {
            int currentSchedulableId = (int)current.Id;

            // "Yield" and "Waiting for quiescence" hack.
            if (choices.TrueForAll(info => !info.IsEnabled))
            {
                if (choices.Exists(info => info.NextOperationType == OperationType.Yield))
                {
                    foreach (var actorInfo in choices)
                    {
                        if (actorInfo.NextOperationType == OperationType.Yield)
                        {
                            actorInfo.IsEnabled = true;
                        }
                    }
                }
                else if (choices.Exists(
                             info => info.NextOperationType == OperationType.WaitForQuiescence))
                {
                    foreach (var actorInfo in choices)
                    {
                        if (actorInfo.NextOperationType == OperationType.WaitForQuiescence)
                        {
                            actorInfo.IsEnabled = true;
                        }
                    }
                }
            }

            // Forced choice.
            if (next != null)
            {
                AbdandonReplay(false);
            }

            bool         added = Stack.Push(choices, currentSchedulableId);
            TidEntryList top   = Stack.GetTop();

            Contract.Assert(next == null || added, "DPOR: Forced choice implies we should have added to stack.");

            if (added)
            {
                if (UseSleepSets)
                {
                    SleepSets.UpdateSleepSets(Stack, Contract);
                }

                if (Dpor == null)
                {
                    top.SetAllEnabledToBeBacktracked(Contract);
                }
                else if (Dpor.RaceReplaySuffix.Count > 0 && Dpor.ReplayRaceIndex < Dpor.RaceReplaySuffix.Count)
                {
                    // Replaying a race:
                    var tidReplay = Dpor.RaceReplaySuffix[Dpor.ReplayRaceIndex];
                    // Restore the nondet choices on the top of stack.
                    top.NondetChoices = tidReplay.NondetChoices;
                    // Add the replay tid to the backtrack set.
                    top.List[tidReplay.Id].Backtrack = true;
                    Contract.Assert(
                        top.List[tidReplay.Id].Enabled ||
                        top.List[tidReplay.Id].OpType == OperationType.Yield);
                    ++Dpor.ReplayRaceIndex;
                }
                else
                {
                    // TODO: Here is where we can combine with another scheduler:
                    // For now, we just do round-robin when doing DPOR and random when doing random DPOR.

                    // If our choice is forced by parent scheduler:
                    if (next != null)
                    {
                        top.AddToBacktrack((int)next.Id, Contract);
                    }
                    else if (Rand == null)
                    {
                        top.AddFirstEnabledNotSleptToBacktrack(currentSchedulableId, Contract);
                    }
                    else
                    {
                        top.AddRandomEnabledNotSleptToBacktrack(Rand);
                    }
                }
            }
            else if (Rand != null)
            {
                // When doing random DPOR: we are replaying a schedule prefix so rewind the nondet choices now.
                top.RewindNondetChoicesForReplay();
            }

            int nextTid = Stack.GetSelectedOrFirstBacktrackNotSlept(currentSchedulableId);

            if (nextTid < 0)
            {
                next = null;
                // TODO: if nextTidIndex == DPORAlgorithm.SLEEP_SET_BLOCKED then let caller know that this is the case.
                // I.e. this is not deadlock.
                return(false);
            }

            if (top.TryGetSelected(Contract) != nextTid)
            {
                top.SetSelected(nextTid, Contract);
            }

            Contract.Assert(nextTid < choices.Count);
            next = choices[nextTid];

            // TODO: Part of yield hack.
            if (!next.IsEnabled &&
                next.NextOperationType == OperationType.Yield)
            {
                //                // Uncomment to avoid waking a yielding thread.
                //                next = null;
                //                // TODO: let caller know that this is not deadlock.
                //                return false;
                next.IsEnabled = true;
            }

            Contract.Assert(next.IsEnabled);
            return(true);
        }