/// <summary> /// Returns the next choice to schedule. /// </summary> /// <param name="next">Next</param> /// <param name="choices">Choices</param> /// <param name="current">Curent</param> /// <returns>Boolean</returns> public bool GetNext(out ISchedulable next, List <ISchedulable> choices, ISchedulable current) { if (IsReplaying) { var enabledChoices = choices.Where(choice => choice.IsEnabled).ToList(); if (enabledChoices.Count == 0) { next = null; return(false); } try { if (ScheduledSteps >= ScheduleTrace.Count) { ErrorText = "Trace is not reproducible: execution is longer than trace."; throw new InvalidOperationException(ErrorText); } ScheduleStep nextStep = ScheduleTrace[ScheduledSteps]; if (nextStep.Type != ScheduleStepType.SchedulingChoice) { ErrorText = "Trace is not reproducible: next step is not a scheduling choice."; throw new InvalidOperationException(ErrorText); } next = enabledChoices.FirstOrDefault(choice => choice.Id == nextStep.ScheduledMachineId); if (next == null) { ErrorText = $"Trace is not reproducible: cannot detect id '{nextStep.ScheduledMachineId}'."; throw new InvalidOperationException(ErrorText); } } catch (InvalidOperationException ex) { if (SuffixStrategy == null) { if (!Configuration.DisableEnvironmentExit) { Error.ReportAndExit(ex.Message); } next = null; return(false); } else { IsReplaying = false; return(SuffixStrategy.GetNext(out next, choices, current)); } } ScheduledSteps++; return(true); } return(SuffixStrategy.GetNext(out next, choices, current)); }
/// <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> /// <returns>Boolean</returns> private bool GetNextHelper(ref ISchedulable next, List <ISchedulable> choices, ISchedulable current) { ++ScheduledSteps; switch (Reduction) { case ReductionStrategy.ForceSchedule: { var partialOrderChoices = choices .Where(choice => choice.IsEnabled && IsPartialOrderOperation(choice.NextOperationType)) .ToList(); // If we are being forced: if (next != null) { if (!partialOrderChoices.Contains(next)) { // Tell child strategy that we were forced (to do a particular send). ChildStrategy.ForceNext(next, choices, current); return(true); } // We would have forced this choice anyway so don't tell ChildStrategy. return(true); } // Not being forced: if (partialOrderChoices.Count > 0) { // Force this non-send but don't tell ChildStrategy. next = partialOrderChoices[0]; return(true); } // Normal schedule: return(ChildStrategy.GetNext(out next, choices, current)); } case ReductionStrategy.OmitSchedulingPoints: { // Otherwise, don't schedule before non-Send. bool continueWithCurrent = current.IsEnabled && IsPartialOrderOperation(current.NextOperationType); // We are being forced: if (next != null) { // ...to do something different than we would have: if (continueWithCurrent && current != next) { // ...so tell child. ChildStrategy.ForceNext(next, choices, current); return(true); } // Otherwise, don't tell child. return(true); } // Not being forced: if (continueWithCurrent) { next = current; return(true); } // Normal schedule: return(ChildStrategy.GetNext(out next, choices, current)); } case ReductionStrategy.None: { // Normal schedule: if (next != null) { ChildStrategy.ForceNext(next, choices, current); return(true); } return(ChildStrategy.GetNext(out next, choices, current)); } default: throw new ArgumentOutOfRangeException(); } }