IOThreadTimer.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 / ServiceModel / System / ServiceModel / Channels / IOThreadTimer.cs / 1 / IOThreadTimer.cs

                            //------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------
namespace System.ServiceModel.Channels
{ 
    using System;
    using System.Runtime.InteropServices; 
    using System.Security; 
    using System.Threading;
    using System.Collections.Generic; 
    using Microsoft.Win32.SafeHandles;
    using System.Diagnostics;
    using System.ComponentModel;
    using System.ServiceModel.Diagnostics; 

 
    // IOThreadTimer has several characterstics that are important for performance: 
    // - Timers that expire benefit from being scheduled to run on IO threads using IOThreadScheduler.Schedule.
    // - The timer "waiter" thread thread is only allocated if there are set timers. 
    // - The timer waiter thread itself is an IO thread, which allows it to go away if there is no need for it,
    //   and allows it to be reused for other purposes.
    // - After the timer count goes to zero, the timer waiter thread remains active for a bounded amount
    //   of time to wait for additional timers to be set. 
    // - Timers are stored in an array-based priority queue to reduce the amount of time spent in updates, and
    //   to always provide O(1) access to the minimum timer (the first one that will expire). 
    // - The standard textbook priority queue data structure is extended to allow efficient Delete in addition to 
    //   DeleteMin for efficient handling of canceled timers.
    // - Timers that are typically set, then immediately canceled (such as a retry timer, 
    //   or a flush timer), are tracked separately from more stable timers, to avoid having
    //   to update the waitable timer in the typical case when a timer is canceled.  Whether
    //   a timer instance follows this pattern is specified when the timer is constructed.
    // - Extending a timer by a configurable time delta (maxSkew) does not involve updating the 
    //   waitable timer, or taking a lock.
    // - Timer instances are relatively cheap.  They share "heavy" resources like the waiter thread and 
    //   waitable timer handle. 
    // - Setting or canceling a timer does not typically involve any allocations.
    class IOThreadTimer 
    {
        static long systemTimeResolutionTicks = SafeNativeMethods.GetSystemTimeResolution();
        static bool tracedSystemTimeResolution;
 
        int index;
        long dueTime; 
        TimerGroup timerGroup; 
        WaitCallback callback;
        object callbackState; 
        long maxSkew;
        const int maxSkewInMillisecondsDefault = 100;

        public IOThreadTimer(WaitCallback callback, object callbackState, bool isTypicallyCanceledShortlyAfterBeingSet) 
            : this(callback, callbackState, isTypicallyCanceledShortlyAfterBeingSet, maxSkewInMillisecondsDefault)
        { 
        } 

        public IOThreadTimer(WaitCallback callback, object callbackState, bool isTypicallyCanceledShortlyAfterBeingSet, int maxSkewInMilliseconds) 
        {
            this.callback = callback;
            this.callbackState = callbackState;
            this.maxSkew = Ticks.FromMilliseconds(maxSkewInMilliseconds); 
            this.timerGroup = isTypicallyCanceledShortlyAfterBeingSet ?
                TimerManager.Value.VolatileTimerGroup : 
                TimerManager.Value.StableTimerGroup; 
        }
 
        public void Set(TimeSpan timeFromNow)
        {
            if (timeFromNow != TimeSpan.MaxValue)
            { 
                SetAt(Ticks.Add(Ticks.Now, Ticks.FromTimeSpan(timeFromNow)));
            } 
        } 

        public void Set(int millisecondsFromNow) 
        {
            SetAt(Ticks.Add(Ticks.Now, Ticks.FromMilliseconds(millisecondsFromNow)));
        }
 
        public void SetAt(long dueTime)
        { 
            TimerManager.Value.Set(this, dueTime); 
        }
 
        public bool Cancel()
        {
            return TimerManager.Value.Cancel(this);
        } 

        public static long SystemTimeResolutionTicks 
        { 
            get
            { 
                if (!IOThreadTimer.tracedSystemTimeResolution && DiagnosticUtility.ShouldTraceInformation)
                {
                    IOThreadTimer.tracedSystemTimeResolution = true;
                    DiagnosticUtility.DiagnosticTrace.TraceEvent( 
                        TraceEventType.Information,
                        TraceCode.SystemTimeResolution, 
                        SR.GetString( 
                            SR.TraceCodeSystemTimeResolution,
                            IOThreadTimer.systemTimeResolutionTicks, 
                            (IOThreadTimer.systemTimeResolutionTicks + TimeSpan.TicksPerMillisecond / 2) / TimeSpan.TicksPerMillisecond));
                }

                return IOThreadTimer.systemTimeResolutionTicks; 
            }
        } 
 
        class TimerManager
        { 
            TimerGroup volatileTimerGroup;
            TimerGroup stableTimerGroup;
            WaitableTimer[] waitableTimers;
            WaitCallback onWaitCallback; 
            bool waitScheduled;
            static TimerManager value = new TimerManager(); 
            const long maxTimeToWaitForMoreTimers = 1000 * TimeSpan.TicksPerMillisecond; 

            public TimerManager() 
            {
                this.volatileTimerGroup = new TimerGroup();
                this.stableTimerGroup = new TimerGroup();
                this.waitableTimers = new WaitableTimer[] { stableTimerGroup.WaitableTimer, volatileTimerGroup.WaitableTimer }; 
                this.onWaitCallback = this.OnWaitCallback;
            } 
 
            public static TimerManager Value
            { 
                get { return value; }
            }

            object ThisLock 
            {
                get { return this; } 
            } 

            public TimerGroup VolatileTimerGroup 
            {
                get { return volatileTimerGroup; }
            }
 
            public TimerGroup StableTimerGroup
            { 
                get { return stableTimerGroup; } 
            }
 
            public void Set(IOThreadTimer timer, long dueTime)
            {
                long timeDiff = dueTime - timer.dueTime;
                if (timeDiff < 0) 
                    timeDiff = -timeDiff;
                if (timeDiff > timer.maxSkew) 
                { 
                    lock (this.ThisLock)
                    { 
                        TimerGroup timerGroup = timer.timerGroup;
                        TimerQueue timerQueue = timerGroup.TimerQueue;

                        if (timer.index > 0) 
                        {
                            if (timerQueue.UpdateTimer(timer, dueTime)) 
                            { 
                                UpdateWaitableTimer(timerGroup);
                            } 
                        }
                        else
                        {
                            if (timerQueue.InsertTimer(timer, dueTime)) 
                            {
                                UpdateWaitableTimer(timerGroup); 
 
                                if (timerQueue.Count == 1)
                                { 
                                    EnsureWaitScheduled();
                                }
                            }
                        } 
                    }
                } 
            } 

            public bool Cancel(IOThreadTimer timer) 
            {
                lock (this.ThisLock)
                {
                    if (timer.index > 0) 
                    {
                        TimerGroup timerGroup = timer.timerGroup; 
                        TimerQueue timerQueue = timerGroup.TimerQueue; 

                        timerQueue.DeleteTimer(timer); 

                        if (timerQueue.Count > 0)
                        {
                            UpdateWaitableTimer(timerGroup); 
                        }
                        else 
                        { 
                            TimerGroup otherTimerGroup = GetOtherTimerGroup(timerGroup);
                            if (otherTimerGroup.TimerQueue.Count == 0) 
                            {
                                long now = Ticks.Now;
                                long thisGroupRemainingTime = timerGroup.WaitableTimer.DueTime - now;
                                long otherGroupRemainingTime = otherTimerGroup.WaitableTimer.DueTime - now; 
                                if (thisGroupRemainingTime > maxTimeToWaitForMoreTimers &&
                                    otherGroupRemainingTime > maxTimeToWaitForMoreTimers) 
                                { 
                                    timerGroup.WaitableTimer.Set(Ticks.Add(now, maxTimeToWaitForMoreTimers));
                                } 
                            }
                        }

                        return true; 
                    }
                    else 
                    { 
                        return false;
                    } 
                }
            }

            void UpdateWaitableTimer(TimerGroup timerGroup) 
            {
                WaitableTimer waitableTimer = timerGroup.WaitableTimer; 
 
                IOThreadTimer minTimer = timerGroup.TimerQueue.MinTimer;
 
                long timeDiff = waitableTimer.DueTime - minTimer.dueTime;
                if (timeDiff < 0)
                    timeDiff = -timeDiff;
                if (timeDiff > minTimer.maxSkew) 
                {
                    waitableTimer.Set(minTimer.dueTime); 
                } 
            }
 
            TimerGroup GetOtherTimerGroup(TimerGroup timerGroup)
            {
                if (object.ReferenceEquals(timerGroup, this.volatileTimerGroup))
                { 
                    return this.stableTimerGroup;
                } 
                else 
                {
                    return this.volatileTimerGroup; 
                }
            }

            void EnsureWaitScheduled() 
            {
                if (!this.waitScheduled) 
                { 
                    ScheduleWait();
                } 
            }

            void ScheduleWait()
            { 
                IOThreadScheduler.ScheduleCallback(this.onWaitCallback, null);
                this.waitScheduled = true; 
            } 

            void ScheduleWaitIfAnyTimersLeft() 
            {
                if (this.stableTimerGroup.TimerQueue.Count > 0 ||
                    this.volatileTimerGroup.TimerQueue.Count > 0)
                { 
                    ScheduleWait();
                } 
            } 

            void ReactivateWaitableTimers() 
            {
                ReactivateWaitableTimer(this.stableTimerGroup);
                ReactivateWaitableTimer(this.volatileTimerGroup);
            } 

            void ReactivateWaitableTimer(TimerGroup timerGroup) 
            { 
                TimerQueue timerQueue = timerGroup.TimerQueue;
 
                if (timerQueue.Count > 0)
                {
                    timerGroup.WaitableTimer.Set(timerQueue.MinTimer.dueTime);
                } 
                else
                { 
                    timerGroup.WaitableTimer.Set(long.MaxValue); 
                }
            } 

            void ScheduleElapsedTimers(long now)
            {
                ScheduleElapsedTimers(this.stableTimerGroup, now); 
                ScheduleElapsedTimers(this.volatileTimerGroup, now);
            } 
 
            void ScheduleElapsedTimers(TimerGroup timerGroup, long now)
            { 
                TimerQueue timerQueue = timerGroup.TimerQueue;

                while (timerQueue.Count > 0)
                { 
                    IOThreadTimer timer = timerQueue.MinTimer;
                    long timeDiff = timer.dueTime - now; 
                    if (timeDiff <= timer.maxSkew) 
                    {
                        timerQueue.DeleteMinTimer(); 
                        IOThreadScheduler.ScheduleCallback(timer.callback, timer.callbackState);
                    }
                    else
                    { 
                        break;
                    } 
                } 
            }
 
            void OnWaitCallback(object state)
            {
                WaitHandle.WaitAny(this.waitableTimers);
 
                long now = Ticks.Now;
                lock (this.ThisLock) 
                { 
                    this.waitScheduled = false;
                    ScheduleElapsedTimers(now); 
                    ReactivateWaitableTimers();
                    ScheduleWaitIfAnyTimersLeft();
                }
            } 
        }
 
        class TimerGroup 
        {
            WaitableTimer waitableTimer; 
            TimerQueue timerQueue;

            public TimerGroup()
            { 
                this.waitableTimer = new WaitableTimer();
                this.waitableTimer.Set(long.MaxValue); 
                this.timerQueue = new TimerQueue(); 
            }
 
            public WaitableTimer WaitableTimer
            {
                get { return waitableTimer; }
            } 

            public TimerQueue TimerQueue 
            { 
                get { return timerQueue; }
            } 
        }

        class TimerQueue
        { 
            int count;
            IOThreadTimer[] timers; 
 
            public TimerQueue()
            { 
                this.timers = new IOThreadTimer[4];
            }

            public int Count 
            {
                get { return count; } 
            } 

            public IOThreadTimer MinTimer 
            {
                get
                {
                    DiagnosticUtility.DebugAssert(this.count > 0, ""); 
                    return timers[1];
                } 
            } 

            public bool InsertTimer(IOThreadTimer timer, long dueTime) 
            {
                DiagnosticUtility.DebugAssert(timer.index == 0, "");

                IOThreadTimer[] timers = this.timers; 

                int index = this.count + 1; 
 
                if (index == timers.Length)
                { 
                    timers = new IOThreadTimer[timers.Length * 2];
                    Array.Copy(this.timers, timers, this.timers.Length);
                    this.timers = timers;
                } 

                this.count = index; 
 
                if (index > 1)
                { 
                    for (; ; )
                    {
                        int parentIndex = index / 2;
 
                        if (parentIndex == 0)
                        { 
                            break; 
                        }
 
                        IOThreadTimer parent = timers[parentIndex];

                        if (parent.dueTime > dueTime)
                        { 
                            timers[index] = parent;
                            parent.index = index; 
                            index = parentIndex; 
                        }
                        else 
                        {
                            break;
                        }
                    } 
                }
 
                timers[index] = timer; 
                timer.index = index;
                timer.dueTime = dueTime; 
                return index == 1;
            }

            public bool UpdateTimer(IOThreadTimer timer, long dueTime) 
            {
                int index = timer.index; 
 
                IOThreadTimer[] timers = this.timers;
                int count = this.count; 

                DiagnosticUtility.DebugAssert(index > 0, "");
                DiagnosticUtility.DebugAssert(index <= count, "");
 
                int parentIndex = index / 2;
                if (parentIndex == 0 || 
                    timers[parentIndex].dueTime <= dueTime) 
                {
                    int leftChildIndex = index * 2; 
                    if (leftChildIndex > count ||
                        timers[leftChildIndex].dueTime >= dueTime)
                    {
                        int rightChildIndex = leftChildIndex + 1; 
                        if (rightChildIndex > count ||
                            timers[rightChildIndex].dueTime >= dueTime) 
                        { 
                            timer.dueTime = dueTime;
                            return index == 1; 
                        }
                    }
                }
 
                DeleteTimer(timer);
                InsertTimer(timer, dueTime); 
                return true; 
            }
 
            public void DeleteTimer(IOThreadTimer timer)
            {
                int index = timer.index;
 
                DiagnosticUtility.DebugAssert(index > 0, "");
                DiagnosticUtility.DebugAssert(index <= this.count, ""); 
 
                IOThreadTimer[] timers = this.timers;
 
                for (; ; )
                {
                    int parentIndex = index / 2;
 
                    if (parentIndex >= 1)
                    { 
                        IOThreadTimer parentTimer = timers[parentIndex]; 
                        timers[index] = parentTimer;
                        parentTimer.index = index; 
                    }
                    else
                    {
                        break; 
                    }
 
                    index = parentIndex; 
                }
 
                timer.index = 0;
                timer.dueTime = 0;
                timers[1] = null;
                DeleteMinTimerCore(); 
            }
 
            public void DeleteMinTimer() 
            {
                IOThreadTimer minTimer = this.MinTimer; 
                DeleteMinTimerCore();
                minTimer.index = 0;
                minTimer.dueTime = 0;
            } 

            void DeleteMinTimerCore() 
            { 
                int count = this.count;
 
                if (count == 1)
                {
                    this.count = 0;
                    this.timers[1] = null; 
                }
                else 
                { 
                    IOThreadTimer[] timers = this.timers;
                    IOThreadTimer lastTimer = timers[count]; 
                    this.count = --count;

                    int index = 1;
                    for (; ; ) 
                    {
                        int leftChildIndex = index * 2; 
 
                        if (leftChildIndex > count)
                        { 
                            break;
                        }

                        int childIndex; 
                        IOThreadTimer child;
 
                        if (leftChildIndex < count) 
                        {
                            IOThreadTimer leftChild = timers[leftChildIndex]; 
                            int rightChildIndex = leftChildIndex + 1;
                            IOThreadTimer rightChild = timers[rightChildIndex];

                            if (rightChild.dueTime < leftChild.dueTime) 
                            {
                                child = rightChild; 
                                childIndex = rightChildIndex; 
                            }
                            else 
                            {
                                child = leftChild;
                                childIndex = leftChildIndex;
                            } 
                        }
                        else 
                        { 
                            childIndex = leftChildIndex;
                            child = timers[childIndex]; 
                        }

                        if (lastTimer.dueTime > child.dueTime)
                        { 
                            timers[index] = child;
                            child.index = index; 
                        } 
                        else
                        { 
                            break;
                        }

                        index = childIndex; 

                        if (leftChildIndex >= count) 
                        { 
                            break;
                        } 
                    }

                    timers[index] = lastTimer;
                    lastTimer.index = index; 
                    timers[count + 1] = null;
                } 
            } 
        }
 
        class WaitableTimer : WaitHandle
        {
            long dueTime;
 
            /// 
            /// Critical - calls several critical methods: CreateWaitableTimer, SetHandleAsInvalid, set_SafeWaitHandle 
            /// Safe - caller can't influence operations or touch results 
            /// 
            [SecurityCritical, SecurityTreatAsSafe] 
            public WaitableTimer()
            {
                SafeWaitHandle handle = UnsafeNativeMethods.CreateWaitableTimer(IntPtr.Zero, false, null);
                if (handle.IsInvalid) 
                {
                    Exception exception = new Win32Exception(); 
                    handle.SetHandleAsInvalid(); 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(exception);
                } 
                this.SafeWaitHandle = handle;
            }

            public long DueTime 
            {
                get { return this.dueTime; } 
            } 

            ///  
            /// Critical - calls critical methods: SetWaitableTimer, get_SafeWaitHandle
            /// Safe - caller can influence duration, but otherwise no flow in or out
            /// 
            [SecurityCritical, SecurityTreatAsSafe] 
            public void Set(long dueTime)
            { 
                if (!UnsafeNativeMethods.SetWaitableTimer(this.SafeWaitHandle, ref dueTime, 0, IntPtr.Zero, IntPtr.Zero, false)) 
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception()); 
                }
                this.dueTime = dueTime;
            }
        } 
    }
} 
 


// 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