/// <summary> /// Runs a new asynchronous machine event handler. /// </summary> /// <param name="machine">Machine that executes this event handler.</param> /// <param name="initialEvent">Event for initializing the machine.</param> /// <param name="isFresh">If true, then this is a new machine.</param> private async Task RunMachineEventHandlerAsync(Machine machine, Event initialEvent, bool isFresh) { bool completed; try { if (isFresh) { await machine.GotoStartState(initialEvent); } completed = await machine.RunEventHandler(true); } catch (AssertionFailureException) { base.IsRunning = false; return; } catch (Exception ex) { base.IsRunning = false; base.RaiseOnFailureEvent(ex); return; } if (!completed) { RunMachineEventHandler(machine, null, false); } }
/// <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> /// Tries to create a new machine of the specified type. /// </summary> /// <param name="creator">Creator machine</param> /// <param name="type">Type of the machine</param> /// <param name="friendlyName">Friendly machine name used for logging</param> /// <param name="e">Event</param> /// <returns>MachineId</returns> internal virtual MachineId TryCreateMachine(Machine creator, Type type, string friendlyName, Event e) { this.Assert(type.IsSubclassOf(typeof(Machine)), $"Type '{type.Name}' is not a machine."); MachineId mid = new MachineId(type, friendlyName, this); if (!MachineConstructorMap.ContainsKey(type)) { Func <Machine> constructor = Expression.Lambda <Func <Machine> >( Expression.New(type.GetConstructor(Type.EmptyTypes))).Compile(); MachineConstructorMap[type] = constructor; } Machine machine = MachineConstructorMap[type](); machine.SetMachineId(mid); machine.InitializeStateInformation(); bool result = this.MachineMap.TryAdd(mid.Value, machine); this.Assert(result, $"Machine '{mid}' was already created."); Task task = new Task(() => { try { machine.GotoStartState(e); 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(); return(mid); }
/// <summary> /// Runs a new asynchronous machine event handler. /// </summary> /// <param name="machine">Machine that executes this event handler.</param> /// <param name="initialEvent">Event for initializing the machine.</param> /// <param name="isFresh">If true, then this is a new machine.</param> private async Task RunMachineEventHandlerAsync(Machine machine, Event initialEvent, bool isFresh) { try { if (isFresh) { await machine.GotoStartState(initialEvent); } await machine.RunEventHandler(); } catch (Exception ex) { base.IsRunning = false; base.RaiseOnFailureEvent(ex); return; } }
/// <summary> /// Tries to create a new machine of the given type with an optional payload. /// </summary> /// <param name="type">Type of the machine</param> /// <param name="payload">Optional payload</param> /// <returns>Machine id</returns> internal static MachineId TryCreateMachine(Type type, params Object[] payload) { if (type.IsSubclassOf(typeof(Machine))) { Machine machine = Activator.CreateInstance(type) as Machine; MachineId mid = machine.Id; mid.IpAddress = PSharpRuntime.IpAddress; mid.Port = PSharpRuntime.Port; if (!PSharpRuntime.MachineMap.TryAdd(mid.Value, machine)) { ErrorReporter.ReportAndExit("Machine {0}({1}) was already created.", type.Name, mid.Value); } Task task = new Task(() => { PSharpRuntime.TaskMap.TryAdd(Task.CurrentId.Value, machine); try { machine.AssignInitialPayload(payload); machine.GotoStartState(); machine.RunEventHandler(); } finally { PSharpRuntime.TaskMap.TryRemove(Task.CurrentId.Value, out machine); } }); task.Start(); return(mid); } else { ErrorReporter.ReportAndExit("Type '{0}' is not a machine.", type.Name); return(null); } }
/// <summary> /// Runs a new asynchronous machine event handler. /// This is a fire and forget invocation. /// </summary> /// <param name="machine">Machine</param> /// <param name="e">Event</param> /// <param name="isFresh">Is a new machine</param> private void RunMachineEventHandler(Machine machine, Event e, bool isFresh) { Task.Run(async() => { try { if (isFresh) { await machine.GotoStartState(e); } await machine.RunEventHandler(); } catch (Exception ex) { base.IsRunning = false; base.RaiseOnFailureEvent(ex); } }); }
/// <summary> /// Sends an asynchronous event to a machine. /// </summary> /// <param name="mid">Machine id</param> /// <param name="e">Event</param> internal static void Send(MachineId mid, Event e) { if (mid == null) { ErrorReporter.ReportAndExit("Cannot send to a null machine."); } else if (e == null) { ErrorReporter.ReportAndExit("Cannot send a null event."); } Machine machine = PSharpRuntime.MachineMap[mid.Value]; bool runHandler = false; machine.Enqueue(e, ref runHandler); if (!runHandler) { return; } Task task = new Task(() => { PSharpRuntime.TaskMap.TryAdd(Task.CurrentId.Value, machine as Machine); try { machine.RunEventHandler(); } finally { PSharpRuntime.TaskMap.TryRemove(Task.CurrentId.Value, out machine); } }); task.Start(); }
/// <summary> /// Sends an asynchronous event to a machine. /// </summary> /// <param name="mid">Machine id</param> /// <param name="e">Event</param> internal static void Send(MachineId mid, Event e) { if (mid == null) { ErrorReporter.ReportAndExit("Cannot send to a null machine."); } else if (e == null) { ErrorReporter.ReportAndExit("Cannot send a null event."); } if (PSharpRuntime.TaskMap.ContainsKey((int)Task.CurrentId)) { Machine sender = PSharpRuntime.TaskMap[(int)Task.CurrentId]; Output.Log("<SendLog> Machine '{0}({1})' sent event '{2}' to '{3}({4})'.", sender, sender.Id.MVal, e.GetType(), mid.Type, mid.MVal); } else { Output.Log("<SendLog> Event '{0}' was sent to '{1}({2})'.", e.GetType(), mid.Type, mid.MVal); } Machine machine = PSharpRuntime.MachineMap[mid.Value]; bool runHandler = false; machine.Enqueue(e, ref runHandler); if (!runHandler) { PSharpRuntime.BugFinder.Schedule(); return; } Task task = new Task(() => { PSharpRuntime.BugFinder.NotifyTaskStarted(); machine.RunEventHandler(); PSharpRuntime.BugFinder.NotifyTaskCompleted(); }); lock (PSharpRuntime.Lock) { PSharpRuntime.MachineTasks.Add(task); PSharpRuntime.TaskMap.Add(task.Id, machine as Machine); } PSharpRuntime.BugFinder.NotifyNewTaskCreated(task.Id, machine); if (PSharpRuntime.Configuration.ScheduleIntraMachineConcurrency) { task.Start(PSharpRuntime.TaskScheduler); } else { task.Start(); } PSharpRuntime.BugFinder.WaitForTaskToStart(task.Id); PSharpRuntime.BugFinder.Schedule(); }