/// <summary> /// Sends an asynchronous <see cref="Event"/> to a machine and /// executes the event handler if the machine is available. /// </summary> /// <param name="mid">MachineId</param> /// <param name="e">Event</param> /// <param name="sender">Sender machine</param> internal override async Task SendEventAndExecute(MachineId mid, Event e, AbstractMachine sender) { Machine machine = null; if (!this.MachineMap.TryGetValue(mid.Value, out machine)) { if (sender != null) { base.Log($"<SendLog> Machine '{sender.Id}' sent event '{e.GetType().FullName}' to a halted machine '{mid}'."); } else { base.Log($"<SendLog> The event '{e.GetType().FullName}' was sent to a halted machine '{mid}'."); } return; } bool runNewHandler = false; this.EnqueueEvent(machine, e, sender, ref runNewHandler); if (runNewHandler) { await this.RunMachineEventHandlerAsync(machine, null, false); } }
/// <summary> /// Returns a nondeterministic integer choice, that can be /// controlled during analysis or testing. /// </summary> /// <param name="machine">Machine</param> /// <param name="maxValue">Max value</param> /// <returns>Integer</returns> internal virtual int GetNondeterministicIntegerChoice( AbstractMachine machine, int maxValue) { Random random = new Random(DateTime.Now.Millisecond); return(random.Next(maxValue)); }
/// <summary> /// Notifies that a machine exited a state. /// </summary> /// <param name="machine">AbstractMachine</param> internal override void NotifyExitedState(AbstractMachine machine) { if (base.Configuration.Verbose <= 1) { return; } if (machine is Machine) { string machineState = (machine as Machine).CurrentStateName; base.Log($"<StateLog> Machine '{machine.Id}' exits " + $"state '{machineState}'."); } else if (machine is Monitor) { string liveness = ""; string monitorState = (machine as Monitor).CurrentStateName; if ((machine as Monitor).IsInHotState()) { liveness = "'hot' "; monitorState += "[hot]"; } else if ((machine as Monitor).IsInColdState()) { liveness = "'cold' "; monitorState += "[cold]"; } base.Log($"<MonitorLog> Monitor '{machine.GetType().Name}' " + $"exits {liveness}state '{monitorState}'."); } }
/// <summary> /// Invokes the specified <see cref="PSharp.Monitor"/> with the specified <see cref="Event"/>. /// </summary> /// <param name="sender">Sender machine</param> /// <param name="type">Type of the monitor</param> /// <param name="e">Event</param> internal override void Monitor(Type type, AbstractMachine sender, Event e) { if (!base.Configuration.EnableMonitorsInProduction) { // No-op in production. return; } Monitor monitor = null; lock (this.Monitors) { foreach (var m in this.Monitors) { if (m.GetType() == type) { monitor = m; break; } } } if (monitor != null) { lock (monitor) { monitor.MonitorEvent(e); } } }
/// <summary> /// Returns a nondeterministic integer choice, that can be /// controlled during analysis or testing. /// </summary> /// <param name="machine">Machine</param> /// <param name="maxValue">Max value</param> /// <returns>Integer</returns> internal override int GetNondeterministicIntegerChoice(AbstractMachine machine, int maxValue) { Random random = new Random(DateTime.Now.Millisecond); var result = random.Next(maxValue); base.Logger.OnRandom(machine?.Id, result); return(result); }
/// <summary> /// Sends an asynchronous event to a machine. /// </summary> /// <param name="sender">Sender machine</param> /// <param name="mid">MachineId</param> /// <param name="e">Event</param> /// <param name="isStarter">Is starting a new operation</param> internal virtual void Send(AbstractMachine sender, MachineId mid, Event e, bool isStarter) { EventOriginInfo originInfo = null; if (sender != null && sender is Machine) { originInfo = new EventOriginInfo(sender.Id, (sender as Machine).GetType().Name, Machine.GetQualifiedStateName((sender as Machine).CurrentState)); } EventInfo eventInfo = new EventInfo(e, originInfo); Machine machine = null; if (!this.MachineMap.TryGetValue(mid.Value, out machine)) { return; } bool runHandler = false; machine.Enqueue(eventInfo, ref runHandler); if (!runHandler) { return; } Task task = new Task(() => { try { machine.RunEventHandler(); } catch (Exception) { if (this.Configuration.ThrowInternalExceptions) { throw; } } finally { this.TaskMap.TryRemove(Task.CurrentId.Value, out machine); } }); this.MachineTasks.Add(task); this.TaskMap.TryAdd(task.Id, machine); task.Start(); }
/// <summary> /// Enqueues an asynchronous <see cref="Event"/> to a machine. /// </summary> /// <param name="machine">Machine</param> /// <param name="e">Event</param> /// <param name="sender">Sender machine</param> /// <param name="operationGroupId">Operation group id</param> /// <param name="runNewHandler">Run a new handler</param> private void EnqueueEvent(Machine machine, Event e, AbstractMachine sender, Guid operationGroupId, ref bool runNewHandler) { EventInfo eventInfo = new EventInfo(e, null); eventInfo.SetOperationGroupId(operationGroupId); var senderState = (sender as Machine)?.CurrentStateName ?? string.Empty; base.Logger.OnSend(machine.Id, sender?.Id, senderState, e.GetType().FullName, operationGroupId, isTargetHalted: false); machine.Enqueue(eventInfo, ref runNewHandler); }
/// <summary> /// Gets the target machine for an event; if not found, logs a halted-machine entry. /// </summary> /// <param name="targetMachineId">The id of target machine.</param> /// <param name="e">The event that will be sent.</param> /// <param name="sender">The machine that is sending the event.</param> /// <param name="operationGroupId">The operation group id.</param> /// <param name="targetMachine">Receives the target machine, if found.</param> protected bool GetTargetMachine(MachineId targetMachineId, Event e, AbstractMachine sender, Guid operationGroupId, out Machine targetMachine) { if (!this.MachineMap.TryGetValue(targetMachineId, out targetMachine)) { var senderState = (sender as Machine)?.CurrentStateName ?? string.Empty; this.Logger.OnSend(targetMachineId, sender?.Id, senderState, e.GetType().FullName, operationGroupId, isTargetHalted: true); return(false); } return(true); }
/// <summary> /// Returns a nondeterministic boolean choice, that can be /// controlled during analysis or testing. /// </summary> /// <param name="machine">Machine</param> /// <param name="maxValue">Max value</param> /// <returns>Boolean</returns> internal virtual bool GetNondeterministicBooleanChoice( AbstractMachine machine, int maxValue) { Random random = new Random(DateTime.Now.Millisecond); bool result = false; if (random.Next(maxValue) == 0) { result = true; } return(result); }
/// <summary> /// Returns a nondeterministic boolean choice, that can be /// controlled during analysis or testing. /// </summary> /// <param name="machine">Machine</param> /// <param name="maxValue">Max value</param> /// <returns>Boolean</returns> internal override bool GetNondeterministicBooleanChoice(AbstractMachine machine, int maxValue) { Random random = new Random(DateTime.Now.Millisecond); bool result = false; if (random.Next(maxValue) == 0) { result = true; } base.Logger.OnRandom(machine?.Id, result); return(result); }
/// <summary> /// Sets the operation group id for the specified machine. /// </summary> /// <param name="created">Machine created</param> /// <param name="sender">Sender machine</param> /// <param name="operationGroupId">Operation group id</param> internal void SetOperationGroupIdForMachine(Machine created, AbstractMachine sender, Guid?operationGroupId) { if (operationGroupId.HasValue) { created.Info.OperationGroupId = operationGroupId.Value; } else if (sender != null) { created.Info.OperationGroupId = sender.Info.OperationGroupId; } else { created.Info.OperationGroupId = Guid.Empty; } }
/// <summary> /// Gets the new operation group id to propagate. /// </summary> /// <param name="sender">Sender machine</param> /// <param name="operationGroupId">Operation group id</param> /// <returns>Operation group Id</returns> internal Guid GetNewOperationGroupId(AbstractMachine sender, Guid?operationGroupId) { if (operationGroupId.HasValue) { return(operationGroupId.Value); } else if (sender != null) { return(sender.Info.OperationGroupId); } else { return(Guid.Empty); } }
/// <summary> /// Enqueues an asynchronous <see cref="Event"/> to a machine. /// </summary> /// <param name="machine">Machine</param> /// <param name="e">Event</param> /// <param name="sender">Sender machine</param> /// <param name="runNewHandler">Run a new handler</param> private void EnqueueEvent(Machine machine, Event e, AbstractMachine sender, ref bool runNewHandler) { EventInfo eventInfo = new EventInfo(e, null); if (sender != null) { base.Log($"<SendLog> Machine '{sender.Id}' sent event '{eventInfo.EventName}' to '{machine.Id}'."); } else { base.Log($"<SendLog> Event '{eventInfo.EventName}' was sent to '{machine.Id}'."); } machine.Enqueue(eventInfo, ref runNewHandler); }
/// <summary> /// Sends an asynchronous <see cref="Event"/> to a machine. /// </summary> /// <param name="mid">MachineId</param> /// <param name="e">Event</param> /// <param name="sender">Sender machine</param> /// <param name="options">Optional parameters of a send operation.</param> internal override void SendEvent(MachineId mid, Event e, AbstractMachine sender, SendOptions options) { var operationGroupId = base.GetNewOperationGroupId(sender, options?.OperationGroupId); if (!base.GetTargetMachine(mid, e, sender, operationGroupId, out Machine machine)) { return; } bool runNewHandler = false; this.EnqueueEvent(machine, e, sender, operationGroupId, ref runNewHandler); if (runNewHandler) { this.RunMachineEventHandler(machine, null, false); } }
/// <summary> /// Returns a nondeterministic integer choice, that can be /// controlled during analysis or testing. /// </summary> /// <param name="machine">Machine</param> /// <param name="maxValue">Max value</param> /// <returns>Integer</returns> internal override int GetNondeterministicIntegerChoice(AbstractMachine machine, int maxValue) { Random random = new Random(DateTime.Now.Millisecond); var result = random.Next(maxValue); if (machine != null) { base.Log($"<RandomLog> Machine '{machine.Id}' " + $"nondeterministically chose '{result}'."); } else { base.Log($"<RandomLog> Runtime nondeterministically chose '{result}'."); } return(result); }
/// <summary> /// Determines whether the specified System.Object is equal /// to the current System.Object. /// </summary> /// <param name="obj">Object</param> /// <returns>Boolean</returns> public override bool Equals(object obj) { if (obj == null) { return(false); } AbstractMachine m = obj as AbstractMachine; if (m == null || this.GetType() != m.GetType()) { return(false); } return(this.Id.Value == m.Id.Value); }
/// <summary> /// Sends an asynchronous <see cref="Event"/> to a machine and /// executes the event handler if the machine is available. /// </summary> /// <param name="mid">MachineId</param> /// <param name="e">Event</param> /// <param name="sender">Sender machine</param> /// <param name="isStarter">Is starting a new operation</param> internal override async Task SendEventAndExecute(MachineId mid, Event e, AbstractMachine sender, bool isStarter) { Machine machine = null; if (!this.MachineMap.TryGetValue(mid.Value, out machine)) { return; } bool runNewHandler = false; this.EnqueueEvent(machine, e, sender, ref runNewHandler); if (runNewHandler) { await this.RunMachineEventHandlerAsync(machine, null, false); } }
/// <summary> /// Notifies that a machine raised an <see cref="Event"/>. /// </summary> /// <param name="machine">AbstractMachine</param> /// <param name="eventInfo">EventInfo</param> /// <param name="isStarter">Is starting a new operation</param> internal override void NotifyRaisedEvent(AbstractMachine machine, EventInfo eventInfo, bool isStarter) { if (base.Configuration.Verbose <= 1) { return; } if (machine is Machine) { string machineState = (machine as Machine).CurrentStateName; base.Log($"<RaiseLog> Machine '{machine.Id}' raised " + $"event '{eventInfo.EventName}'."); } else if (machine is Monitor) { string monitorState = (machine as Monitor).CurrentStateName; base.Log($"<MonitorLog> Monitor '{machine.GetType().Name}' raised " + $"event '{eventInfo.EventName}'."); } }
/// <summary> /// Notifies that a machine invoked an action. /// </summary> /// <param name="machine">AbstractMachine</param> /// <param name="action">Action</param> /// <param name="receivedEvent">Event</param> internal override void NotifyInvokedAction(AbstractMachine machine, MethodInfo action, Event receivedEvent) { if (base.Configuration.Verbose <= 1) { return; } if (machine is Machine) { string machineState = (machine as Machine).CurrentStateName; base.Log($"<ActionLog> Machine '{machine.Id}' invoked action " + $"'{action.Name}' in state '{machineState}'."); } else if (machine is Monitor) { string monitorState = (machine as Monitor).CurrentStateName; base.Log($"<MonitorLog> Monitor '{machine.GetType().Name}' executed " + $"action '{action.Name}' in state '{monitorState}'."); } }
/// <summary> /// Returns a nondeterministic boolean choice, that can be /// controlled during analysis or testing. /// </summary> /// <param name="machine">Machine</param> /// <param name="maxValue">Max value</param> /// <returns>Boolean</returns> internal override bool GetNondeterministicBooleanChoice(AbstractMachine machine, int maxValue) { Random random = new Random(DateTime.Now.Millisecond); bool result = false; if (random.Next(maxValue) == 0) { result = true; } if (machine != null) { base.Log($"<RandomLog> Machine '{machine.Id}' " + $"nondeterministically chose '{result}'."); } else { base.Log($"<RandomLog> Runtime nondeterministically chose '{result}'."); } return(result); }
/// <summary> /// Notifies that a machine called Receive. /// </summary> /// <param name="machine">AbstractMachine</param> internal virtual void NotifyReceiveCalled(AbstractMachine machine) { // No-op for real execution. }
/// <summary> /// Notifies that a machine raised an event. /// </summary> /// <param name="machine">AbstractMachine</param> /// <param name="eventInfo">EventInfo</param> /// <param name="isStarter">Is starting a new operation</param> internal virtual void NotifyRaisedEvent(AbstractMachine machine, EventInfo eventInfo, bool isStarter) { // No-op for real execution. }
/// <summary> /// Notifies that a machine called Pop. /// </summary> /// <param name="machine">AbstractMachine</param> internal virtual void NotifyPop(AbstractMachine machine) { // No-op for real execution. }
/// <summary> /// Notifies that a machine invoked an action. /// </summary> /// <param name="machine">AbstractMachine</param> /// <param name="action">Action</param> /// <param name="receivedEvent">Event</param> internal virtual void NotifyInvokedAction(AbstractMachine machine, MethodInfo action, Event receivedEvent) { // No-op for real execution. }
/// <summary> /// Notifies that a machine exited a state. /// </summary> /// <param name="machine">AbstractMachine</param> internal virtual void NotifyExitedState(AbstractMachine machine) { // No-op for real execution. }
/// <summary> /// Returns a fair nondeterministic boolean choice, that can be /// controlled during analysis or testing. /// </summary> /// <param name="machine">Machine</param> /// <param name="uniqueId">Unique id</param> /// <returns>Boolean</returns> internal virtual bool GetFairNondeterministicBooleanChoice( AbstractMachine machine, string uniqueId) { return(this.GetNondeterministicBooleanChoice(machine, 2)); }
/// <summary> /// Invokes the specified monitor with the specified event. /// </summary> /// <param name="sender">Sender machine</param> /// <typeparam name="T">Type of the monitor</typeparam> /// <param name="e">Event</param> internal virtual void Monitor <T>(AbstractMachine sender, Event e) { // No-op for real execution. }
/// <summary> /// Sends an asynchronous event to a remote machine. /// </summary> /// <param name="sender">Sender machine</param> /// <param name="mid">MachineId</param> /// <param name="e">Event</param> /// <param name="isStarter">Is starting a new operation</param> internal virtual void SendRemotely(AbstractMachine sender, MachineId mid, Event e, bool isStarter) { this.NetworkProvider.RemoteSend(mid, e); }
/// <summary> /// Sends an asynchronous <see cref="Event"/> to a machine. Returns immediately /// if the target machine was already running. Otherwise blocks until the machine handles /// the event and reaches quiescense again. /// </summary> /// <param name="mid">MachineId</param> /// <param name="e">Event</param> /// <param name="sender">Sender machine</param> /// <param name="options">Optional parameters of a send operation.</param> /// <returns>True if event was handled, false if the event was only enqueued</returns> internal override async Task <bool> SendEventAndExecute(MachineId mid, Event e, AbstractMachine sender, SendOptions options) { var operationGroupId = base.GetNewOperationGroupId(sender, options?.OperationGroupId); if (!base.GetTargetMachine(mid, e, sender, operationGroupId, out Machine machine)) { return(true); } bool runNewHandler = false; this.EnqueueEvent(machine, e, sender, operationGroupId, ref runNewHandler); if (runNewHandler) { await this.RunMachineEventHandlerAsync(machine, null, false); return(true); } return(false); }
/// <summary> /// Sends an asynchronous <see cref="Event"/> to a remote machine. /// </summary> /// <param name="mid">MachineId</param> /// <param name="e">Event</param> /// <param name="sender">Sender machine</param> /// <param name="options">Optional parameters of a send operation.</param> internal override void SendEventRemotely(MachineId mid, Event e, AbstractMachine sender, SendOptions options) { base.NetworkProvider.RemoteSend(mid, e); }