// // // // // **** Finalizing() **** // /// <summary> /// This is called by the internal hub thread, just after it falls out the bottom /// of the WaitListen() loop, immediately prior to dying forever. /// </summary> protected virtual void Finalizing() { // Log.SubmitLogEntry("Stopping.", EngineLog.Highest); m_WaitHandle.Close(); m_WaitHandle = null; m_WaitListenState = WaitListenState.ReadyToStart; m_Thread = null; // TODO: Signal to subscribers my state change? //HubEventHandler(null); // signal my state change. }//end Finalizing().
}//end TriggerEvent(). // // // #endregion//public methods #region Private & Protected Methods // ************************************************************* // **** Private Methods **** // ************************************************************* // // **** WaitListStart() **** /// <summary> /// Any actions that are to be performed by the hub thread immediatedly /// before it first enters the WaitListen() method can be implememented here /// by overriding this method. Overloading method must finally call this method at end. /// </summary> protected virtual void WaitListenStart() { m_WaitListenState = WaitListenState.Working; m_DiagnoticStopWatch = new Stopwatch(); m_DiagnoticStopWatch.Start(); StopwatchTickFreq = Stopwatch.Frequency; // TODO: Shouldn't the Starting event be triggered here? (If gui invokes work nicely?) WaitListen(); }//end WaitListenStart().
}//end Start() // // // // // **** Stop() **** // /// <summary> /// Called by any external thread, this attempts a friendly shut-down of the hub listener. /// When this is overloaded by another class, it should call this base method also!! /// </summary> protected virtual void Stop() { if (this.Stopping != null) { Stopping(this, EventArgs.Empty); } // Call any objects requesting Stop call. if (m_DiagnoticStopWatch != null && m_DiagnoticStopWatch.IsRunning) { m_DiagnoticStopWatch.Stop(); } m_WaitListenState = WaitListenState.Stopping; // this enum is volatile. if (m_WaitHandle != null) { m_WaitHandle.Set(); } // trigger a wake-up signal for hub thread. // TODO: Push stop request event onto queue. }//end Stop().
}//end WaitListenStart(). // // // // **** WaitListen() **** // /// <summary> /// This method is owned by the hub thread only. /// </summary> private void WaitListen() { while (m_WaitListenState != WaitListenState.Stopping) { // // First check my event queue. // m_WaitListenLoopCount++; // increment loop counter. m_WaitListenState = WaitListenState.Working; EventArgs[] eventArgs = null; lock (m_HubBaseLock) { int nEventsInQueue = m_HubEventQueue.Count; if (nEventsInQueue > 0) { // Found events in my queue. // Copy them into array, call event handler. eventArgs = new EventArgs[nEventsInQueue]; m_HubEventQueue.CopyTo(eventArgs); m_HubEventQueue.Clear(); m_EventCount += nEventsInQueue; // increment our diagnostic event counter. } } // // Send my events out. // if (eventArgs != null) { // There were events in the HubQueue. Process them. // Log.SubmitLogEntry(String.Format("WaitListen(): Handling {0} events in HubQueue.", eventArgs.Length.ToString()), EngineLog.Verbose); HubEventHandler(eventArgs); // Overriden by sub-class, here is where work gets done. if (m_WaitListenUpdatePeriod > 0) { UpdatePeriodicCheck(); } } else { // I awoke, but with an empty queue. if (m_WaitListenUpdatePeriod > 0) { UpdatePeriodicCheck(); } } // // Prepare to Sleep! // int nMsgsInQueue = 0; // First check for any new messages. lock (m_HubBaseLock) { nMsgsInQueue = m_HubEventQueue.Count; } if ((nMsgsInQueue == 0)) { // No messages waiting for us in the queue, continue preparing to sleep. if (m_EventCount > m_EventCountMax) { UpdateDiagnostics(); // before sleeping update periodics. } if (m_WaitListenState != WaitListenState.Stopping) { // I am not supposed to stop running, prepare to sleep. // // Go to sleep now! // m_WaitListenState = WaitListenState.Waiting; // set my flag to waiting. long ticksAtSleep = m_DiagnoticStopWatch.ElapsedTicks; // take note of the time. if (m_WaitListenUpdatePeriod > 0) { // User has set a update period. Go to sleep, after setting the alarm clock. m_WaitHandle.WaitOne(m_WaitListenUpdatePeriod, false); } else { // User has no periodic update set. Go peacefully to sleep - without setting alarm clock! m_WaitHandle.WaitOne(); } m_TicksWhileASleep += (m_DiagnoticStopWatch.ElapsedTicks - ticksAtSleep); // note the time elapsed since we went to sleep. }//if not stopping. } else { // New messages have appeared while I was away. m_SleepSkippedCounter++; m_EventsFoundWaitingCounter += nMsgsInQueue; m_WaitHandle.Reset(); // reset wait handle since I will now handle these messages now. } }//wend not stopping - repeat this main wait loop forever. // // Exit. // Finalizing(); // Stop wait/listen cycle by falling out the bottom. }//end WaitListen().