/// <summary> /// Sets the next operation to schedule. /// </summary> /// <param name="operationType">Type of the operation.</param> /// <param name="targetType">Type of the target of the operation.</param> /// <param name="targetId">Id of the target.</param> internal void SetNextOperation(OperationType operationType, OperationTargetType targetType, ulong targetId) { NextOperationType = operationType; NextTargetType = targetType; NextTargetId = targetId; OperationCount++; EventHandlerOperationCount++; }
/// <summary> /// /// </summary> /// <param name="id"></param> /// <param name="enabled"></param> /// <param name="opType"></param> /// <param name="targetType"></param> /// <param name="targetId"></param> /// <param name="sendStepIndex"></param> public TidEntry(int id, bool enabled, OperationType opType, OperationTargetType targetType, int targetId, int sendStepIndex) { Id = id; Enabled = enabled; Sleep = false; Backtrack = false; OpType = opType; TargetType = targetType; TargetId = targetId; SendStepIndex = sendStepIndex; }
/// <summary> /// Schedules the next <see cref="ISchedulable"/> operation to execute. /// </summary> /// <param name="operationType">Type of the operation.</param> /// <param name="targetType">Type of the target of the operation.</param> /// <param name="targetId">Id of the target.</param> internal void Schedule(OperationType operationType, OperationTargetType targetType, 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(); } // Checks if synchronisation not controlled by P# was used. this.CheckIfExternalSynchronizationIsUsed(); // Checks if the scheduling steps bound has been reached. this.CheckIfSchedulingStepsBoundIsReached(); SchedulableInfo current = this.ScheduledMachine; current.SetNextOperation(operationType, targetType, targetId); // Get and order the schedulable choices by their id. var choices = this.SchedulableInfoMap.Values.OrderBy(choice => choice.Id).Select(choice => choice as ISchedulable).ToList(); ISchedulable next = null; if (!this.Strategy.GetNext(out next, choices, current)) { // Checks if the program has livelocked. this.CheckIfProgramHasLivelocked(choices.Select(choice => choice as SchedulableInfo)); Debug.WriteLine("<ScheduleDebug> Schedule explored."); this.HasFullyExploredSchedule = true; this.Stop(); } this.ScheduledMachine = next as SchedulableInfo; this.Runtime.ScheduleTrace.AddSchedulingChoice(next.Id); (next as MachineInfo).ProgramCounter = 0; Debug.WriteLine($"<ScheduleDebug> Schedule '{next.Name}' with task id '{this.ScheduledMachine.TaskId}'."); if (current != next) { current.IsActive = false; lock (next) { this.ScheduledMachine.IsActive = true; System.Threading.Monitor.PulseAll(next); } lock (current) { if (!current.IsEventHandlerRunning) { return; } while (!current.IsActive) { Debug.WriteLine($"<ScheduleDebug> Sleep '{current.Name}' with task id '{current.TaskId}'."); System.Threading.Monitor.Wait(current); Debug.WriteLine($"<ScheduleDebug> Wake up '{current.Name}' with task id '{current.TaskId}'."); } if (!current.IsEnabled) { throw new ExecutionCanceledException(); } } } }