/// <summary> /// This method is used in a DFS exploration of nondet choice. /// It will pop off bool choices that are 1 until /// it reaches a 0 that will then be changed to a 1. /// The NextNondetChoiceIndex will be reset ready for replay. /// </summary> /// <param name="contract">IContract</param> /// <returns>false if there are no more nondet choices to explore</returns> public bool BacktrackNondetChoices(IContract contract) { if (NondetChoices == null) { return(false); } contract.Assert(NextNondetChoiceIndex == NondetChoices.Count); NextNondetChoiceIndex = 0; while (NondetChoices.Count > 0) { NonDetChoice choice = NondetChoices[NondetChoices.Count - 1]; contract.Assert(choice.IsBoolChoice, "DFS DPOR only supports bool choices."); if (choice.Choice == 0) { choice.Choice = 1; NondetChoices[NondetChoices.Count - 1] = choice; return(true); } contract.Assert(choice.Choice == 1, "Unexpected choice value."); NondetChoices.RemoveAt(NondetChoices.Count - 1); } return(false); }
/// <summary> /// Get a nondet choice. /// This may replay a nondet choice or make (and record) a new nondet choice. /// </summary> /// <param name="isBoolChoice">If true, a boolean choice; otherwise, an int choice.</param> /// <param name="rand">Random</param> /// <param name="contract">IContract</param> public int MakeOrReplayNondetChoice(bool isBoolChoice, IRandomNumberGenerator rand, IContract contract) { contract.Assert( rand != null || isBoolChoice, "A DFS DPOR exploration of int nondeterminstic choices " + "is not currently supported because this won't scale."); if (NondetChoices == null) { NondetChoices = new List <NonDetChoice>(); } if (NextNondetChoiceIndex < NondetChoices.Count) { // Replay: NonDetChoice choice = NondetChoices[NextNondetChoiceIndex]; ++NextNondetChoiceIndex; contract.Assert(choice.IsBoolChoice == isBoolChoice); return(choice.Choice); } // Adding a choice. contract.Assert(NextNondetChoiceIndex == NondetChoices.Count); NonDetChoice ndc = new NonDetChoice { IsBoolChoice = isBoolChoice, Choice = rand == null ? 0 : (isBoolChoice ? rand.Next(2) : rand.Next()) }; NondetChoices.Add(ndc); ++NextNondetChoiceIndex; return(ndc.Choice); }
/// <summary> /// Push a list of tid entries onto the stack. /// If we are replaying, this will verify that /// the list is what we expected. /// </summary> /// <param name="machines"></param> /// <param name="prevThreadIndex"></param> /// <returns>true if a new element was added to the stack, otherwise the existing entry was verified</returns> public bool Push(List <ISchedulable> machines, int prevThreadIndex) { List <TidEntry> list = new List <TidEntry>(); foreach (var machineInfo in machines) { list.Add( new TidEntry( (int)machineInfo.Id, machineInfo.IsEnabled, machineInfo.NextOperationType, machineInfo.NextTargetType, (int)machineInfo.NextTargetId, (int)machineInfo.NextOperationMatchingSendIndex)); } Contract.Assert(NextStackPos <= StackInternal.Count, "DFS strategy unexpected stack state."); bool added = NextStackPos == StackInternal.Count; if (added) { StackInternal.Add(new TidEntryList(list)); } else { CheckMatches(list); } ++NextStackPos; return(added); }
/// <summary> /// Gets the selected thread. /// Asserts that there is a selected thread. /// </summary> /// <param name="contract">IContract</param> public int GetSelected(IContract contract) { int res = TryGetSelected(contract); contract.Assert(res != -1, "DFS Strategy: No selected tid entry!"); return(res); }
/// <summary> /// Add all enabled threads to the backtrack set. /// </summary> /// <param name="contract">IContract</param> public void SetAllEnabledToBeBacktracked(IContract contract) { foreach (var tidEntry in List) { if (tidEntry.Enabled) { tidEntry.Backtrack = true; // TODO: Remove? contract.Assert(tidEntry.Enabled); } } }
/// <summary> /// Gets all threads in backtrack that are not slept and not selected. /// </summary> /// <param name="contract">IContract</param> public List <int> GetAllBacktrackNotSleptNotSelected(IContract contract) { List <int> res = new List <int>(); for (int i = 0; i < List.Count; ++i) { if (List[i].Backtrack && !List[i].Sleep && List[i].Id != SelectedEntry) { contract.Assert(List[i].Enabled); res.Add(i); } } return(res); }
private void DoRandomRaceReverse(Stack stack, IRandomNumberGenerator rand) { int raceIndex = rand.Next(Races.Count); if (raceIndex == 0) { return; } Race race = Races[raceIndex]; Contract.Assert(RaceReplaySuffix.Count == 0, "Tried to reverse race but replay suffix was not empty!"); int threadIdOfA = GetSelectedTidEntry(stack, race.A).Id; // Add to RaceReplaySuffix: all steps between a and b that do not h.a. a. for (int i = race.A; i < race.B; ++i) { if (HB(threadIdOfA, race.A, i)) { // Skip it. // But track the missing thread id if this is a create operation. if (GetSelectedTidEntry(stack, i).OpType == OperationType.Create) { var missingThreadId = GetThreadsAt(stack, i).List.Count; var index = MissingThreadIds.BinarySearch(missingThreadId); // We should not find it. Contract.Assert(index < 0); // Get the next largest index (see BinarySearch). index = ~index; // Insert before the next largest item. MissingThreadIds.Insert(index, missingThreadId); } } else { // Add thread id to the RaceReplaySuffix, but adjust // it for missing thread ids. AddThreadIdToRaceReplaySuffix(GetThreadsAt(stack, i)); } } AddThreadIdToRaceReplaySuffix(GetThreadsAt(stack, race.B)); AddThreadIdToRaceReplaySuffix(GetThreadsAt(stack, race.A)); // Remove steps from a onwards. Indexes start at one so we must subtract 1. stack.StackInternal.RemoveRange(race.A - 1, stack.StackInternal.Count - (race.A - 1)); }
/// <summary> /// Add the first enabled and not slept thread to the backtrack set. /// </summary> /// <param name="startingFrom">a thread id to start from</param> /// <param name="contract">IContract</param> public void AddFirstEnabledNotSleptToBacktrack(int startingFrom, IContract contract) { int size = List.Count; int i = startingFrom; for (int count = 0; count < size; ++count) { if (List[i].Enabled && !List[i].Sleep) { List[i].Backtrack = true; // TODO: Remove? contract.Assert(List[i].Enabled); return; } ++i; if (i >= size) { i = 0; } } }
/// <summary> /// Sets the selected thread id. /// There must not already be a selected thread id. /// </summary> /// <param name="tid">thread id to be set to selected</param> /// <param name="contract">IContract</param> public void SetSelected(int tid, IContract contract) { contract.Assert(SelectedEntry < 0); contract.Assert(tid >= 0 && tid < List.Count); SelectedEntry = tid; }
/// <summary> /// Add a thread to the backtrack set. /// </summary> /// <param name="tid">a thread id to add</param> /// <param name="contract">IContract</param> public void AddToBacktrack(int tid, IContract contract) { List[tid].Backtrack = true; contract.Assert(List[tid].Enabled); }
/// <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); }