/// <summary> /// Invoked by an <see cref="ActivationEvent"/> to execute the /// <see cref="DesTask"/>. /// </summary> /// <param name="evt"> /// The <see cref="ActivationEvent"/> that triggered this /// <see cref="DesTask"/> to execute. /// </param> internal void RunFromActivationEvent(ActivationEvent evt) { // Internal consistency check if (_actevt != evt) { throw new InvalidOperationException("Event mis-match."); } RestorePriority(); _actevt = null; ExecuteTask(evt.Activator, evt.Data); ClearInterrupt(); }
//===================================================================== //==== INTERNAL IMPLEMENTATION ==== //===================================================================== /// <summary> /// Cancel the pending <see cref="ActivationEvent"/>. /// </summary> /// <param name="evt"> /// The <see cref="ActivationEvent"/> to cancel. /// </param> internal void CancelPending(ActivationEvent evt) { if (_actevt != null) { // Internal consistency check if (_actevt != evt) { throw new InvalidOperationException("Event mis-match."); } _actevt = null; evt.Cancel(); } }
/// <summary> /// Run the <see cref="Simulation"/> using the provided generator /// <see cref="DesTask"/> instances. /// </summary> /// <remarks> /// The array of generators must contain zero (0) or more /// <see cref="DesTask"/> instances; it cannot be <see langword="null"/>. /// </remarks> /// <exception cref="ArgumentNullException"> /// If <paramref name="generators"/> is <see langword="null"/>. /// </exception> /// <param name="generators"> /// An array of generator <see cref="DesTask"/> instances. /// </param> /// <returns> /// The number of <see cref="ActivationEvent"/> instances that /// remained in the event queue at the time the /// <see cref="Simulation"/> stopped. /// </returns> public virtual int Run(DesTask [] generators) { // Reset from a previous run. _currentTime = 0L; _stopTime = ulong.MaxValue; ActivateGenerators(generators); State = SimulationState.Running; while (_stopTime >= _currentTime && _eventQueue.Count > 0 && _nDiscardableTasks < _eventQueue.Count) { ActivationEvent evt = _eventQueue.Dequeue(); _currentTime = evt.Time; if (evt.Priority == TaskPriority.Discardable) { _nDiscardableTasks--; } if (_currentTime > _stopTime) { // Time to stop. Put the event back on the event queue so // it's propertly counted as one of the events not fired. _eventQueue.Enqueue(evt); } else if (evt.IsPending) { evt.Fire(this); } } // Make some final time updates. if (_currentTime < _stopTime) { _stopTime = _currentTime; } else { _currentTime = _stopTime; } int nNotRun = _eventQueue.Count; _eventQueue.Clear(); State = SimulationState.Completed; return(nNotRun); }
//==================================================================== //==== Internal/Private Implementation ==== //==================================================================== /// <summary> /// Gets or frees a reserved resource item. /// </summary> /// <remarks> /// This method decrements the reserve count and, if /// <paramref name="evt"/> is pending it will actually allocate a /// resource item to the <see cref="Task"/> which will be run by /// <paramref name="evt"/>. /// </remarks> /// <param name="evt"> /// The <see cref="ActivationEvent"/> making the data request. /// </param> /// <returns> /// The resource item associated with the allocated resource or /// <see langword="null"/> if resources are not assocatiated with /// arbitrary objects. Also returns <see langword="null"/> if /// <paramref name="evt"/> is not pending (i.e. the /// <see cref="ActivationEvent.IsPending"/> method is <b>false</b>). /// </returns> private object GetOrFreeReserved(ActivationEvent evt) { object obj; _nReserved--; if (evt.IsPending) { System.Diagnostics.Debug.Assert(evt.Task != null); obj = AllocateResource(); SetOwner(evt.Task, obj); } else { obj = null; } return(obj); }
/// <summary> /// Activates the <see cref="DesTask"/> at some time in the future and /// specifying the DesTask priority and client-specific DesTask data. /// </summary> /// <remarks> /// <see cref="DesTask"/> implementations can normally treat this method /// as the "designated" version of the <b>Activate</b> method, which /// all other versions of <b>Activate</b> invoke. That, in fact, is /// how the <see cref="DesTask"/> class implements <b>Activate</b>. /// </remarks> /// <exception cref="InvalidOperationException"> /// If <see cref="Interrupted"/> is <b>true</b>. Before calling /// this method, ensure that the <see cref="DesTask"/> is no longer /// in an interrupted state. /// </exception> /// <param name="activator"> /// The object that is activating the <see cref="DesTask"/>. May be /// <see langword="null"/>. /// </param> /// <param name="relTime"> /// The time relative to the current time when the <see cref="DesTask"/> /// should be scheduled to run. /// </param> /// <param name="data"> /// An object containing client-specific data for the /// <see cref="DesTask"/>. /// </param> /// <param name="priority"> /// The DesTask priority. Higher values indicate higher priorities. /// </param> public virtual void Activate(object activator, ulong relTime, object data, int priority) { if (Interrupted) { throw new InvalidOperationException( "DesTask is in an interrupted state. Clear interrupt flag."); } else { CancelPending(_actevt); ClearBlocks(); ElevatePriority(priority); ActivationEvent evt = new ActivationEvent(this, activator, relTime); evt.Data = data; Simulation.ScheduleEvent(evt); _actevt = evt; } }
/// <summary> /// Adds the specified <see cref="ActivationEvent"/> to the event queue /// (future event set). /// </summary> /// <remarks> /// <para> /// Once <paramref name="evt"/> is scheduled, it cannot be removed from /// the event queue, but it may be canceled. Canceled /// <see cref="ActivationEvent"/>s remain in the queue, but are simply /// discarded rather than fired when they are removed from the queue. /// </para> /// <para> /// Most client code will not need to call this method, rather one of /// the <b>Activate</b> methods of the <see cref="Task"/> class should /// be used to schedule <see cref="Task"/>s to run. /// </para> /// <para> /// <b>Important:</b> If the <see cref="Simulation"/> is in the /// <see cref="React.SimulationState.Stopping"/> state, /// <paramref name="evt"/> is silently ignored, <b>it is not /// scheduled</b>. /// </para> /// </remarks> /// <exception cref="BackClockingException"> /// If <paramref name="evt"/> has an event time earlier than the /// current simulation time, <see cref="Now"/>. /// </exception> /// <exception cref="InvalidOperationException"> /// If the simulation <see cref="State"/> is either /// <see cref="React.SimulationState.Completed"/> or /// <see cref="React.SimulationState.Failed"/>. /// </exception> /// <param name="evt"> /// The <see cref="ActivationEvent"/> to schedule (add to the event queue). /// </param> public virtual void ScheduleEvent(ActivationEvent evt) { if (evt.Time < Now) { throw new BackClockingException(this, evt.Time); } if (State == SimulationState.Completed || State == SimulationState.Failed) { throw new InvalidOperationException( "Simulation state is " + State.ToString()); } if (State != SimulationState.Stopping) { _eventQueue.Enqueue(evt); if (evt.Priority == TaskPriority.Discardable) { _nDiscardableTasks++; } } }
/// <summary> /// Method used as a <see cref="DeferredDataCallback"/> delegate. /// </summary> /// <remarks> /// This method will decrement the number of consumer reservations. /// It will also either: (1) remove an object from the /// <see cref="_items"/> queue; or (2) decrement <see cref="_count"/>. /// If actual CLR objects are not being put into the /// <see cref="BoundedBuffer"/>, the <see cref="_items"/> queue should /// be <see langword="null"/> and <see cref="_count"/> is decremented. /// </remarks> /// <param name="evt"> /// The <see cref="ActivationEvent"/> requesting data. /// </param> /// <returns> /// An item removed from the <see cref="_items"/> queue or /// <see langword="null"/> if actual CLR objects are not being stored /// in the <see cref="BoundedBuffer"/>. /// </returns> private object ConsumerGetOrFree(ActivationEvent evt) { object obj; _nConsumerReserved--; if (evt.IsPending) { if (_items != null) { obj = _items.Dequeue(); } else { _count--; obj = null; } } else { obj = null; } ResumeWaitingProducers(); return(obj); }