/// <summary> /// Update the sleep sets for the top operation on the stack. /// This will look at the second from top element in the stack /// and copy forward the sleep set, excluding threads that are dependent /// with the executed operation. /// </summary> /// <param name="stack">Stack</param> /// <param name="contract">IContract</param> public static void UpdateSleepSets(Stack stack, IContract contract) { if (stack.GetNumSteps() <= 1) { return; } TidEntryList prevTop = stack.GetSecondFromTop(); TidEntry prevSelected = prevTop.List[prevTop.GetSelected(contract)]; TidEntryList currTop = stack.GetTop(); // For each thread on the top of stack (except previously selected thread and new threads): // if thread was slept previously // and thread's op was independent with selected op then: // the thread is still slept. // else: not slept. for (int i = 0; i < prevTop.List.Count; i++) { if (i == prevSelected.Id) { continue; } if (prevTop.List[i].Sleep && !IsDependent(prevTop.List[i], prevSelected)) { currTop.List[i].Sleep = true; } } }
/// <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); }