/// <summary> /// Notify that the event handler has completed. /// </summary> /// <param name="info">SchedulableInfo</param> internal void NotifyEventHandlerCompleted(SchedulableInfo info) { Debug.WriteLine($"<ScheduleDebug> Completed event handler of '{info.Name}' with task id '{info.TaskId}'."); info.IsEnabled = false; info.IsCompleted = true; this.Schedule(); Debug.WriteLine($"<ScheduleDebug> Exit event handler of '{info.Name}' with task id '{info.TaskId}'."); }
/// <summary> /// Notify that an event handler has been created. /// </summary> /// <param name="info">SchedulableInfo</param> internal void NotifyEventHandlerCreated(SchedulableInfo info) { if (!this.SchedulableInfoMap.ContainsKey(info.Id)) { if (this.SchedulableInfoMap.Count == 0) { this.ScheduledMachine = info; } this.SchedulableInfoMap.Add(info.Id, info); } Debug.WriteLine($"<ScheduleDebug> Created event handler of '{info.Name}' with task id '{info.TaskId}'."); }
/// <summary> /// Waits for the event handler to start. /// </summary> /// <param name="info">SchedulableInfo</param> internal void WaitForEventHandlerToStart(SchedulableInfo info) { lock (info) { if (this.SchedulableInfoMap.Count == 1) { info.IsActive = true; System.Threading.Monitor.PulseAll(info); } else { while (!info.IsEventHandlerRunning) { System.Threading.Monitor.Wait(info); } } } }
/// <summary> /// Notify that the event handler has started. /// </summary> /// <param name="info">SchedulableInfo</param> internal void NotifyEventHandlerStarted(SchedulableInfo info) { Debug.WriteLine($"<ScheduleDebug> Started event handler of '{info.Name}' with task id '{info.TaskId}'."); lock (info) { info.IsEventHandlerRunning = true; System.Threading.Monitor.PulseAll(info); while (!info.IsActive) { Debug.WriteLine($"<ScheduleDebug> Sleep '{info.Name}' with task id '{info.TaskId}'."); System.Threading.Monitor.Wait(info); Debug.WriteLine($"<ScheduleDebug> Wake up '{info.Name}' with task id '{info.TaskId}'."); } if (!info.IsEnabled) { throw new ExecutionCanceledException(); } } }
/// <summary> /// Notify that a monitor was registered. /// </summary> /// <param name="info">SchedulableInfo</param> internal void NotifyMonitorRegistered(SchedulableInfo info) { SchedulableInfoMap.Add(info.Id, info); Debug.WriteLine($"<ScheduleDebug> Created monitor of '{info.Name}'."); }
/// <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(); } } } }
/// <summary> /// Schedules the next machine to execute. /// </summary> internal void Schedule() { 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; ISchedulable next = null; var choices = this.Infos.Values.OrderBy(choice => choice.Id).Select(choice => choice as ISchedulable).ToList(); if (!this.Strategy.TryGetNext(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); this.ScheduledMachine.ProgramCounter = 0; if (this.Runtime.Configuration.CacheProgramState && this.Runtime.Configuration.SafetyPrefixBound <= this.ExploredSteps) { this.Runtime.StateCache.CaptureState(this.Runtime.ScheduleTrace.Peek()); } // Checks the liveness monitors for potential liveness bugs. this.Runtime.LivenessChecker.CheckLivenessAtShedulingStep(); 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.IsCompleted) { 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(); } } } }