public Process(Environment environment, IEnumerable<Event> generator) : base(environment) { this.generator = generator.GetEnumerator(); IsOk = true; target = new Initialize(environment, this); }
protected virtual void CollectValues(Event @event) { if (@event.IsOk) { var value = new OrderedDictionary(); foreach (var v in GetValues()) value.Add(v.Key, v.Value); Value = value; } }
protected virtual void TriggerRequest(Event @event = null) { while (RequestQueue.Count > 0) { var request = RequestQueue.Peek(); DoRequest(request); if (request.IsTriggered) { RequestQueue.Dequeue(); } else break; } }
protected virtual void TriggerGet(Event @event = null) { while (GetQueue.Count > 0) { var get = GetQueue.Peek(); DoGet(get); if (get.IsTriggered) { GetQueue.Dequeue(); } else break; } }
protected virtual void TriggerPut(Event @event = null) { while (PutQueue.Count > 0) { var put = PutQueue.Peek(); DoPut(put); if (put.IsTriggered) { PutQueue.Dequeue(); } else break; } }
protected virtual void TriggerRequest(Event @event = null) { while (RequestQueue.Count > 0) { var request = RequestQueue.First.Value; DoRequest(request); if (request.IsTriggered) { RequestQueue.RemoveFirst(); } else break; } }
/// <summary> /// This interrupts a process and causes the IsOk flag to be set to false. /// If a process is interrupted the iterator method needs to call HandleFault() /// before continuing to yield further events. /// </summary> /// <exception cref="InvalidOperationException">This is thrown in three conditions: /// - If the process has already been triggered. /// - If the process attempts to interrupt itself. /// - If the process continues to yield events despite being faulted.</exception> /// <param name="cause">The cause of the interrupt.</param> public virtual void Interrupt(object cause = null) { if (IsTriggered) throw new InvalidOperationException("The process has terminated and cannot be interrupted."); if (Environment.ActiveProcess == this) throw new InvalidOperationException("A process is not allowed to interrupt itself."); var interruptEvent = new Event(Environment); interruptEvent.AddCallback(Resume); interruptEvent.Fail(cause); if (Target != null) Target.RemoveCallback(Resume); }
protected virtual void TriggerRequest(Event @event = null) { var current = RequestQueue.First; while (current != null) { var request = current.Value; DoRequest(request); if (request.IsTriggered) { var next = current.Next; RequestQueue.Remove(current); current = next; } if (Resources.Count == 0) break; } }
protected void Check(Event @event) { if (IsTriggered || IsProcessed) { if ([email protected]) throw new InvalidOperationException( @"Errors that happen after the condition has been triggered will not be handled by the condition and cause the simulation to crash."); return; } FiredEvents.Add(@event); if ([email protected]) Fail(@event.Value); else if (Evaluate()) { Succeed(); } }
protected virtual void TriggerRequest(Event @event = null) { foreach (var entry in RequestQueue) { var cascade = false; var requests = entry.Value; while (requests.Count > 0) { var req = requests.Peek(); DoRequest(req); if (req.IsTriggered) { requests.Dequeue(); } else { cascade = true; break; } } if (cascade) break; } }
protected virtual void Resume(Event @event) { Environment.ActiveProcess = this; while (true) { if (@event.IsOk) { if (generator.MoveNext()) { if (IsTriggered) { // the generator called e.g. Environment.ActiveProcess.Fail Environment.ActiveProcess = null; return; } if (ProceedToEvent()) break; } else if (!IsTriggered) { Succeed(@event.Value); break; } else break; } else { /* Fault handling differs from SimPy as in .NET it is not possible to inject an * exception into an enumerator and it is impossible to put a yield return inside * a try-catch block. In SimSharp the Process will set IsOk and will then move to * the next yield in the generator. However, if after this move IsOk is still false * we know that the error was not handled. It is assumed the error is handled if * HandleFault() is called on the environment's ActiveProcess which will reset the * flag. */ IsOk = false; Value = @event.Value; if (generator.MoveNext()) { if (IsTriggered) { // the generator called e.g. Environment.ActiveProcess.Fail Environment.ActiveProcess = null; return; } // if we move next, but IsOk is still false if (!IsOk) throw new InvalidOperationException("The process did not react to being faulted."); // otherwise HandleFault was called and the fault was handled if (ProceedToEvent()) break; } else if (!IsTriggered) { if (!IsOk) Fail(@event.Value); else Succeed(@event.Value); break; } else break; } } Environment.ActiveProcess = null; }
public virtual void ScheduleD(double delay, Event @event) { Schedule(TimeSpan.FromSeconds(DefaultTimeStepSeconds * delay), @event); }
protected virtual void StopSimulation(Event @event) { throw new StopSimulationException(@event.Value); }
public virtual object Run(Event stopEvent = null) { if (stopEvent != null) { if (stopEvent.IsProcessed) return stopEvent.Value; stopEvent.AddCallback(StopSimulation); } try { var stop = Queue.Count == 0 && ScheduleQ.Count == 0; while (!stop) { Step(); ProcessedEvents++; lock (locker) { stop = Queue.Count == 0 && ScheduleQ.Count == 0; } } } catch (StopSimulationException e) { return e.Value; } if (stopEvent == null) return null; if (!stopEvent.IsTriggered) throw new InvalidOperationException("No scheduled events left but \"until\" event was not triggered."); return stopEvent.Value; }
protected virtual void TriggerRelease(Event @event = null) { while (ReleaseQueue.Count > 0) { var release = ReleaseQueue.Peek(); DoRelease(release); if (release.IsTriggered) { ReleaseQueue.Dequeue(); } else break; } }
protected virtual bool ProceedToEvent() { target = generator.Current; Value = target.Value; if (target.IsProcessed) return false; target.AddCallback(Resume); return true; }
/// <summary> /// This method schedules the event right now. It takes the IsOk state /// and uses the <see cref="Value"/> of the given <paramref name="@event"/>. /// Thus if the given event fails, this event will also be triggered as /// failing. /// </summary> /// <exception cref="InvalidOperationException"> /// Thrown when the event has already been triggered. /// </exception> /// <remarks> /// The signature of this method allows it to be used as a callback. /// </remarks> /// <param name="event">The event that triggers this event.</param> public virtual void Trigger(Event @event) { if (IsTriggered) throw new InvalidOperationException("Event has already been triggered."); IsOk = @event.IsOk; Value = @event.Value; IsTriggered = true; Environment.Schedule(this); }
protected virtual void TriggerGet(Event @event = null) { var current = GetQueue.First; while (current != null) { var get = current.Value; DoGet(get); if (get.IsTriggered) { var next = current.Next; GetQueue.Remove(current); current = next; } else current = current.Next; if (Items.Count == 0) break; } }
public virtual void Schedule(Event @event) { lock (locker) { Queue.Enqueue(@event); } }
protected virtual void DisposeCallback(Event @event) { var request = @event as Request; if (request != null) Release(request); }
public virtual void Schedule(TimeSpan delay, Event @event) { if (delay < TimeSpan.Zero) throw new ArgumentException("Negative delays are not allowed in Schedule(TimeSpan, Event)."); lock (locker) { if (delay == TimeSpan.Zero) { Queue.Enqueue(@event); return; } var eventTime = Now + delay; DoSchedule(eventTime, @event); } }
protected virtual void TriggerRequest(Event @event = null) { foreach (var entry in RequestQueue) { var requests = entry.Value; var current = requests.First; while (current != null) { var request = current.Value; DoRequest(request); if (request.IsTriggered) { var next = current.Next; requests.Remove(current); current = next; } else current = current.Next; } } }
protected virtual EventQueueNode DoSchedule(DateTime date, Event @event) { if (ScheduleQ.MaxSize == ScheduleQ.Count) { // the capacity has to be adjusted, there are more events in the queue than anticipated var oldSchedule = ScheduleQ; ScheduleQ = new EventQueue(ScheduleQ.MaxSize * 2); foreach (var e in oldSchedule) ScheduleQ.Enqueue(e.Priority, e.Event); } return ScheduleQ.Enqueue(date, @event); }
protected void DisposeCallback(Event @event) { var request = @event as PreemptiveRequest; if (request != null) Release(request); }
public virtual object Run(DateTime until) { if (until <= Now) throw new InvalidOperationException("Simulation end date must lie in the future."); var stopEvent = new Event(this); var node = DoSchedule(until, stopEvent); // stop event is always the first to execute at the given time node.InsertionIndex = -1; ScheduleQ.OnNodeUpdated(node); return Run(stopEvent); }