Timer.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / TransactionBridge / Microsoft / Transactions / Wsat / Protocol / Timer.cs / 1 / Timer.cs

                            //------------------------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
using System;
using System.Collections; 
using System.Diagnostics;
using System.Threading; 
 
using Microsoft.Transactions.Bridge;
using Microsoft.Transactions.Wsat.Messaging; 
using System.ServiceModel.Diagnostics;

namespace Microsoft.Transactions.Wsat.Protocol
{ 
    interface ITimerRecipient
    { 
        TimeSpan NextNotification { get; } 
        Guid UniqueId { get; }
 
        void OnTimerNotification (object token);
    }

    // 
    // There is one timer manager per protocol instance, so this is effectively a static class
    // 
    class TimerManager : IComparer 
    {
        ProtocolState state; 

        SortedList timerList;
        Timer timer;
        bool active; 

        // Wake up every so often to check the list 
        TimeSpan reminderGranularity = new TimeSpan (0, 0, 10); 

        // If the recipient wants a callback in the near future, deliver it now 
        TimeSpan reminderTolerance = new TimeSpan (0, 0, 1);

        // No timer notifications more than a 1/2 hour in the future, please
        TimeSpan maxNotificationTime = new TimeSpan (0, 30, 0); 

 		public TimerManager (ProtocolState state) 
		{ 
            this.state = state;
            this.timerList = new SortedList (this); 

            // The timer starts out disabled
            this.timer = new Timer(DiagnosticUtility.Utility.ThunkCallback(new TimerCallback(OnTimer)), null, Timeout.Infinite, Timeout.Infinite);
        } 

        // IComparer.Compare 
        public int Compare (object x, object y) 
        {
            if (ReferenceEquals (x, y)) 
                return 0;

            ITimerRecipient left = (ITimerRecipient) x;
            ITimerRecipient right = (ITimerRecipient) y; 

            TimeSpan leftSpan = left.NextNotification; 
            TimeSpan rightSpan = right.NextNotification; 

            int compare = leftSpan.CompareTo (rightSpan); 
            if (compare == 0)
            {
                // If the relative times are the same, we still can't declare equality
                // because sorted lists can't handle objects with equal keys. :-\ 
                // They throw ArgumentException with "Item has already been added."
                // Therefore, we use the objects' unique identifiers as discriminants 
 
                compare = left.UniqueId.CompareTo (right.UniqueId);
                if (compare == 0) 
                {
                    // It is a product bug to add the same item to the timer list twice.
                    // This needs to be reported back to Microsoft.
                    DiagnosticUtility.FailFast("A duplicate object was added to the timer list"); 
                }
            } 
 
            // We want the list to be sorted in decreasing order, so oldest items are at the end of the list
            return - compare; 
        }

        void OnTimer(object obj)
        { 
            try
            { 
                ExecuteTimer(); 
            }
#pragma warning suppress 56500 // Only catch Exception for InvokeFinalHandler 
            catch (Exception e)
            {
                // A timer event cannot fail or throw an exception.
                // This indicates that things have gone seriously wrong, 
                // so we cannot be trusted to perform any further processing.
                // This is a QFE-worthy event. 
                DiagnosticUtility.InvokeFinalHandler(e); 
            }
        } 

        void ExecuteTimer()
        {
            DebugTrace.TraceEnter (this, "OnTimer"); 

            ArrayList recipientList = null; 
            TimeSpan now = state.ElapsedTime; 

#if DEBUG 
            lock (this.timerList.SyncRoot)
            {
                int check = this.timerList.Count - 1;
                for (int i = 0; i < check; i++) 
                {
                    ITimerRecipient later = (ITimerRecipient) this.timerList.GetKey (i); 
                    ITimerRecipient earlier = (ITimerRecipient) this.timerList.GetKey (i + 1); 

                    if (earlier.NextNotification >= later.NextNotification) 
                    {
                        // The timer list must be sorted in ascending order.
                        // If any entries are out of Time sequence, we have a product
                        // bug that must be reported back to Microsoft. 
                        DiagnosticUtility.FailFast("Timer list sorted backwards");
                    } 
                } 
            }
#endif 
            lock (this.timerList.SyncRoot)
            {
                int timerEntries = this.timerList.Count;
                DebugTrace.Trace (TraceLevel.Verbose, "Timer list depth at {0}", timerEntries); 

                // Count down from the oldest to the most recent, pulling items off the end 
                for (int i = timerEntries - 1; i >= 0; i --) 
                {
                    ITimerRecipient recipient = (ITimerRecipient) this.timerList.GetKey (i); 

                    // Compare the timer entry to the current time
                    TimeSpan difference = recipient.NextNotification - now;
                    if (difference > this.reminderTolerance) 
                    {
                        // The list is sorted, so no more recipients need a notification 
                        if (DebugTrace.Verbose) 
                        {
                            DebugTrace.Trace ( 
                                TraceLevel.Verbose,
                                "Timer list found entry scheduled for {0} ms in the future",
                                (long) difference.TotalMilliseconds
                                ); 
                        }
                        break; 
                    } 

                    if (DebugTrace.Verbose) 
                    {
                        DebugTrace.Trace (
                            TraceLevel.Verbose,
                            "Timer list dispatching to recipient scheduled for {0} ms in the {1}", 
                            (long) difference.Duration().TotalMilliseconds,
                            difference > TimeSpan.Zero ? "future" : "past" 
                            ); 
                    }
 
                    // Find the object's state token and remove it from the list
                    object token = this.timerList.GetByIndex (i);
                    this.timerList.RemoveAt (i);
 
                    // Add to the dispatch list. We buffer the recipients because we don't want to
                    // call into the timer notification code while holding a lock 
                    if (recipientList == null) 
                    {
                        recipientList = new ArrayList (32); 
                    }

                    recipientList.Add (recipient);
                    recipientList.Add (token); 
                }
 
                // If we removed the last element from the list, shut down the timer 
                if (recipientList != null && this.timerList.Count == 0)
                { 
                    DeactivateTimer();
                }
            }
 
            // Process all the recipients we pulled off the list
            if (recipientList != null) 
            { 
                int listCount = recipientList.Count;
                if (listCount % 2 != 0) 
                {
                    // We always add or remove from the RecipientList in
                    // pairs (recipient, token). If we did not add in a pair,
                    // an assumption is violated, resulting in a product bug. 
                    // We need to report the bug back to Microsoft.
                    DiagnosticUtility.FailFast("Recipient list count must be even"); 
                } 

                if (DebugTrace.Verbose) 
                {
                    int recipients = listCount / 2;
                    DebugTrace.Trace (
                        TraceLevel.Verbose, 
                        "Dispatching timer notification to {0} recipient{1}",
                        recipients, recipients != 1 ? "s" : string.Empty); 
                } 

                for (int i = 0; i < listCount; i += 2) 
                {
                    ITimerRecipient recipient = (ITimerRecipient) recipientList [i];
                    object token = recipientList [i + 1];
 
                    recipient.OnTimerNotification (token);
                } 
            } 

            DebugTrace.TraceLeave (this, "OnTimer"); 
        }

        public void Add (ITimerRecipient recipient, object token)
        { 
            DebugTrace.TraceEnter (this, "Add");
 
            // Validate notification time is within the range expected 
            TimeSpan interval = recipient.NextNotification - state.ElapsedTime;
 
            if (!(interval > TimeSpan.Zero && interval < this.maxNotificationTime))
            {
                // All Timer intervals must be between TimeSpan.Zero and
                // maxNotificationTime. If this assumption is violated, 
                // we have a product bug that must be reported back to MSFT.
                DiagnosticUtility.FailFast("The timer object has an invalid notification time"); 
            } 

            // Add entry to the timer list 
            int entries;
            lock (this.timerList.SyncRoot)
            {
                AssertState(); 

                this.timerList.Add (recipient, token); 
 
                entries = this.timerList.Count;
                if (entries == 1) 
                {
                    ActivateTimer();
                }
            } 

            if (DebugTrace.Verbose) 
            { 
                DebugTrace.Trace(TraceLevel.Verbose, "Added timer recipient to be reminded in {0} ms", (long) interval.TotalMilliseconds);
                DebugTrace.Trace (TraceLevel.Verbose, "Timer list depth at {0}", entries); 
            }

            DebugTrace.TraceLeave (this, @"Add");
        } 

        public void Remove (ITimerRecipient recipient) 
        { 
            DebugTrace.TraceEnter (this, "Remove");
 
            int before, after;
            lock (this.timerList.SyncRoot)
            {
                AssertState(); 

                before = this.timerList.Count; 
                this.timerList.Remove (recipient); 
                after = this.timerList.Count;
 
                if (before != after && this.timerList.Count == 0)
                {
                    DeactivateTimer();
                } 
            }
 
            if (DebugTrace.Verbose) 
            {
                if (before == after) 
                {
                    DebugTrace.Trace (
                        TraceLevel.Verbose,
                        "Timer recipient was not present. Timer list depth is still {0}", 
                        after);
                } 
                else 
                {
                    DebugTrace.Trace ( 
                        TraceLevel.Verbose,
                        "Removed timer recipient. Timer list depth is now {0}",
                        after);
                } 
            }
 
            DebugTrace.TraceLeave (this, "Remove"); 
        }
 
        void ActivateTimer()
        {
            // Reactivate the timer
            bool changed = this.timer.Change (this.reminderGranularity, this.reminderGranularity); 
            if (!changed)
            { 
                // We assume that all timer changes work. 
                if (DebugTrace.Info)
                { 
                    DebugTrace.Trace(TraceLevel.Info, "TimerManager.ActivateTimer: Timer.Change returned false");
                }
            }
 
            this.active = true;
            AssertState(); 
 
            if (DebugTrace.Verbose)
            { 
                DebugTrace.Trace (
                    TraceLevel.Verbose,
                    "Activated timer notification to {0} seconds",
                    (int) this.reminderGranularity.TotalSeconds); 
            }
        } 
 
        void DeactivateTimer()
        { 
            DebugTrace.Trace (
                TraceLevel.Verbose, "Timer list is now empty. Canceling periodic timer notification");

            bool changed = this.timer.Change (Timeout.Infinite, Timeout.Infinite); 
            if (!changed)
            { 
                // We assume that all timer changes work. 
                if (DebugTrace.Info)
                { 
                    DebugTrace.Trace(TraceLevel.Info, "TimerManager.DeactivateTimer: Timer.Change returned false");
                }
            }
 
            this.active = false;
            AssertState(); 
        } 

        void AssertState() 
        {
            if (this.active)
            {
                if (this.timerList.Count <= 0) 
                {
                    // An active TimerManager must have timers in its list. 
                    DiagnosticUtility.FailFast("The timer list must not be empty"); 
                }
            } 
            else
            {
                if (this.timerList.Count != 0)
                { 
                    // An inactive TimerManager must not have any timers in its list.
                    DiagnosticUtility.FailFast("The timer list must be empty"); 
                } 
            }
        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK