/// <summary> /// Initializes a new instance of the <see cref="TaskEntry"/> class. /// </summary> public TaskEntry(int id, bool enabled, AsyncOperationType opType, AsyncOperationTarget target, int targetId, int sendStepIndex) { this.Id = id; this.Enabled = enabled; this.Sleep = false; this.Backtrack = false; this.OpType = opType; this.OpTarget = target; this.TargetId = targetId; this.SendStepIndex = sendStepIndex; }
/// <summary> /// Schedules the next asynchronous operation. /// </summary> internal void ScheduleNextOperation(AsyncOperationType type, AsyncOperationTarget target, ulong targetId) { int?taskId = Task.CurrentId; // If the caller is the root task, then return. if (taskId != null && taskId == this.Runtime.RootTaskId) { return; } if (!this.IsSchedulerRunning) { this.Stop(); throw new ExecutionCanceledException(); } // Checks if concurrency not controlled by the runtime was used. this.Runtime.AssertNoExternalConcurrencyUsed(); // Checks if the scheduling steps bound has been reached. this.CheckIfSchedulingStepsBoundIsReached(); AsyncOperation current = this.ScheduledOperation; current.SetNextOperation(type, target, targetId); // Get and order the operations by their id. var ops = this.OperationMap.Values.OrderBy(op => op.SourceId).Select(op => op as IAsyncOperation).ToList(); if (!this.Strategy.GetNext(out IAsyncOperation next, ops, current)) { // Checks if the program has livelocked. this.CheckIfProgramHasLivelocked(ops.Select(op => op as AsyncOperation)); Debug.WriteLine("<ScheduleDebug> Schedule explored."); this.HasFullyExploredSchedule = true; this.Stop(); throw new ExecutionCanceledException(); } this.ScheduledOperation = next as AsyncOperation; this.Runtime.ScheduleTrace.AddSchedulingChoice(next.SourceId); Debug.WriteLine($"<ScheduleDebug> Schedule '{next.SourceName}' with task id '{this.ScheduledOperation.Task.Id}'."); if (current != next) { current.IsActive = false; lock (next) { this.ScheduledOperation.IsActive = true; System.Threading.Monitor.PulseAll(next); } lock (current) { if (!current.IsInboxHandlerRunning) { return; } while (!current.IsActive) { Debug.WriteLine($"<ScheduleDebug> Sleep '{current.SourceName}' with task id '{current.Task.Id}'."); System.Threading.Monitor.Wait(current); Debug.WriteLine($"<ScheduleDebug> Wake up '{current.SourceName}' with task id '{current.Task.Id}'."); } if (!current.IsEnabled) { throw new ExecutionCanceledException(); } } } }
/// <summary> /// Sets the next operation to schedule. /// </summary> internal void SetNextOperation(AsyncOperationType operationType, AsyncOperationTarget target, ulong targetId) { this.Type = operationType; this.Target = target; this.TargetId = targetId; }