/// <summary> /// Updates current steps, so that <see cref="IInternalCall.Steps"/> are used instead. /// Moreover, it adjusts the stack of calls, since that is necessary to maintain integrity. /// </summary> /// <param name="call">The call from which new steps are taken.</param> internal void PushCall(IInternalCall call) { var tmp = call.Steps; call.Steps = _steps; _steps = tmp; call.PreviousCall = _currentCall; _currentCall = call; }
/// <summary> /// Called when this event is the first in the agenda. /// </summary> internal override void Step() { // Target has to be cleaned before process is started up again. Target = null; // In SimPy 3, interrupts are sent to processes as exceptions. // However, this cannot be done in .NET; therefore, we dediced to throw // an exception if a process was interrupted, but it did not check for that. // To achieve this, we need to record the number of interrupts // this process has and we will see if it has properly decreased. var oldInterruptCount = _interruptCount; // We start the process again and see if it produces more events. if (_steps.MoveNext() && !ReferenceEquals(Target = _steps.Current, Env.EndEvent)) { // User has yielded an event. Since users may yield null events, // we need to check for them, as they are not allowed. if (Target == null) { throw new ArgumentNullException(ErrorMessages.NullEvent); } // If the interrupt count was zero, then we have nothing more to check. // Otherwise, we will need to check that it was decreased at least by one. if (oldInterruptCount != 0 && _interruptCount == oldInterruptCount) { throw new InterruptUncaughtException(); } Target.Subscribe(this); return; } // Body of generator has finished, therefore process or call has finished. // If the interrupt count was zero, then we have nothing more to check. // Otherwise, we will need to check that it was decreased at least by one. if (oldInterruptCount != 0 && _interruptCount == oldInterruptCount) { throw new InterruptUncaughtException(); } // If target event is the end event, then the process should exit, // no matter how many interrupts have been received. if (_currentCall != null) { _steps = _currentCall.Steps; _currentCall = _currentCall.PreviousCall; } else { // We have to remove current process from the agenda. Env.UnscheduleActiveProcess(); // Marks this event as succeeded, as processes cannot fail. End(); } }