/// <summary> /// Returns the next controlled operation to schedule. /// </summary> /// <param name="ops">The set of available operations.</param> /// <param name="current">The currently scheduled operation.</param> /// <param name="isYielding">True if the current operation is yielding, else false.</param> /// <param name="next">The next operation to schedule.</param> /// <returns>True if there is a next choice, else false.</returns> internal bool GetNextOperation(IEnumerable <ControlledOperation> ops, ControlledOperation current, bool isYielding, out ControlledOperation next) { // Filter out any operations that cannot be scheduled. var enabledOps = ops.Where(op => op.Status is OperationStatus.Enabled); if (enabledOps.Any()) { // Invoke any installed schedule reducers. foreach (var reducer in this.Reducers) { var reducedOps = reducer.ReduceOperations(enabledOps, current); if (reducedOps.Any()) { enabledOps = reducedOps; } } // Invoke the strategy to choose the next operation. if (this.Strategy is InterleavingStrategy strategy && strategy.GetNextOperation(enabledOps, current, isYielding, out next)) { this.Trace.AddSchedulingChoice(next.Id); return(true); } } next = null; return(false); }
/// <summary> /// Signals the specified waiting operation that the resource has been released. /// </summary> internal void Signal(ControlledOperation op) { if (this.AwaitingOperations.Contains(op)) { op.Status = OperationStatus.Enabled; this.AwaitingOperations.Remove(op); } }
/// <summary> /// Explores a possible interleaving due to a 'WRITE' operation on the specified shared state. /// </summary> /// <param name="state">The shared state that is being written represented as a string.</param> /// <param name="comparer"> /// Checks if the written shared state is equal with another shared state that is being accessed concurrently. /// </param> public static void Write(string state, IEqualityComparer <string> comparer = default) { var runtime = CoyoteRuntime.Current; if (runtime.SchedulingPolicy is SchedulingPolicy.Interleaving) { ControlledOperation op = runtime.GetExecutingOperation(); op.LastAccessedSharedState = state; runtime.ScheduleNextOperation(SchedulingPointType.Write, isSuppressible: false); op.LastAccessedSharedState = string.Empty; } }
/// <summary> /// Returns the next integer choice. /// </summary> /// <param name="current">The currently scheduled operation.</param> /// <param name="maxValue">The max value.</param> /// <param name="next">The next integer choice.</param> /// <returns>True if there is a next choice, else false.</returns> internal bool GetNextIntegerChoice(ControlledOperation current, int maxValue, out int next) { if (this.Strategy is InterleavingStrategy strategy && strategy.GetNextIntegerChoice(current, maxValue, out next)) { this.Trace.AddNondeterministicIntegerChoice(next); return(true); } next = 0; return(false); }
/// <inheritdoc/> public IEnumerable <ControlledOperation> ReduceOperations(IEnumerable <ControlledOperation> ops, ControlledOperation current) { // Find all operations that are not invoking a user-defined scheduling decision. var noUserDefinedSchedulingOps = ops.Where( op => !SchedulingPoint.IsUserDefined(op.LastSchedulingPoint)); if (noUserDefinedSchedulingOps.Any()) { // One or more operations exist that are not invoking a user-defined // scheduling decision, so return them. return(noUserDefinedSchedulingOps); } else { // Split the operations that are accessing shared state into a 'READ' and 'WRITE' group. var readAccessOps = ops.Where(op => op.LastSchedulingPoint is SchedulingPointType.Read); var writeAccessOps = ops.Where(op => op.LastSchedulingPoint is SchedulingPointType.Write); // Update the known 'READ' and 'WRITE' access sets so far. this.ReadAccesses.UnionWith(readAccessOps.Select(op => op.LastAccessedSharedState)); this.WriteAccesses.UnionWith(writeAccessOps.Select(op => op.LastAccessedSharedState)); // Find if any operations are explicitly interleaving, and if yes do not perform any reduction. if (!ops.Any(op => op.LastSchedulingPoint is SchedulingPointType.Interleave || op.LastSchedulingPoint is SchedulingPointType.Yield)) { // Find if there are any read-only accesses. Note that this is just an approximation // based on current knowledge. An access that is considered read-only might not be // considered anymore in later steps or iterations once the known 'READ' and 'WRITE' // access sets have been updated. var readOnlyAccessOps = readAccessOps.Where(op => !this.WriteAccesses.Any( state => state.StartsWith(op.LastAccessedSharedState) || op.LastAccessedSharedState.StartsWith(state))); if (readOnlyAccessOps.Any()) { // Return all read-only access operations. return(readOnlyAccessOps); } } } return(ops); }
/// <summary> /// Returns the next delay. /// </summary> /// <param name="ops">Operations executing during the current test iteration.</param> /// <param name="current">The operation requesting the delay.</param> /// <param name="maxValue">The max value.</param> /// <param name="next">The next delay.</param> /// <returns>True if there is a next delay, else false.</returns> internal bool GetNextDelay(IEnumerable <ControlledOperation> ops, ControlledOperation current, int maxValue, out int next) => (this.Strategy as FuzzingStrategy).GetNextDelay(ops, current, maxValue, out next);