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
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- EdmComplexPropertyAttribute.cs
- BulletChrome.cs
- HostingEnvironmentSection.cs
- PrintingPermission.cs
- Thread.cs
- WebBodyFormatMessageProperty.cs
- DataGridViewRowPrePaintEventArgs.cs
- LookupNode.cs
- MSHTMLHost.cs
- XmlUrlEditor.cs
- IssuanceLicense.cs
- PolicyLevel.cs
- TextTreeDeleteContentUndoUnit.cs
- ConnectionManagementSection.cs
- BamlLocalizerErrorNotifyEventArgs.cs
- SQLBinary.cs
- XmlIlTypeHelper.cs
- Type.cs
- ToolStripSystemRenderer.cs
- recordstatefactory.cs
- ValidatingPropertiesEventArgs.cs
- RangeValidator.cs
- QueryCacheManager.cs
- ComponentResourceKey.cs
- SemanticBasicElement.cs
- ProgressChangedEventArgs.cs
- HtmlInputReset.cs
- WebBrowserHelper.cs
- ErrorProvider.cs
- GroupBoxDesigner.cs
- Schema.cs
- TextAnchor.cs
- MetadataCacheItem.cs
- BinaryConverter.cs
- DataTablePropertyDescriptor.cs
- HttpInputStream.cs
- ComEventsInfo.cs
- EventProxy.cs
- HttpRequest.cs
- StrokeRenderer.cs
- IdentityValidationException.cs
- itemelement.cs
- TypefaceCollection.cs
- MethodExpr.cs
- XmlObjectSerializerWriteContextComplex.cs
- DataGridViewCheckBoxColumn.cs
- CustomWebEventKey.cs
- CodeDomConfigurationHandler.cs
- WebPartTransformerCollection.cs
- CapabilitiesState.cs
- DataGridDesigner.cs
- FamilyMap.cs
- SHA512Cng.cs
- RootBrowserWindowAutomationPeer.cs
- TransformerInfo.cs
- AlphaSortedEnumConverter.cs
- PrimitiveSchema.cs
- ConfigurationSectionGroupCollection.cs
- UrlMappingCollection.cs
- Int64.cs
- TextRangeBase.cs
- EditorPartChrome.cs
- EdmFunctionAttribute.cs
- NotFiniteNumberException.cs
- PixelFormat.cs
- Filter.cs
- AutoCompleteStringCollection.cs
- WindowsFont.cs
- InternalConfigHost.cs
- ExternalDataExchangeService.cs
- SharedPerformanceCounter.cs
- LayoutExceptionEventArgs.cs
- GcSettings.cs
- SrgsItemList.cs
- SQLInt16Storage.cs
- QueryTaskGroupState.cs
- TextElementAutomationPeer.cs
- RawContentTypeMapper.cs
- HttpSessionStateBase.cs
- ObjectFactoryCodeDomTreeGenerator.cs
- SymmetricAlgorithm.cs
- ResumeStoryboard.cs
- StaticFileHandler.cs
- DataControlPagerLinkButton.cs
- ProjectedSlot.cs
- PriorityQueue.cs
- EdmToObjectNamespaceMap.cs
- DataListItemEventArgs.cs
- WindowsScrollBarBits.cs
- XhtmlBasicLiteralTextAdapter.cs
- LinkButton.cs
- CopyAction.cs
- AQNBuilder.cs
- PeerNameRegistration.cs
- DecodeHelper.cs
- SerializerWriterEventHandlers.cs
- DataFormats.cs
- filewebresponse.cs
- BindingNavigator.cs
- PolicyStatement.cs