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

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- NameTable.cs
- X509Extension.cs
- CodeCompileUnit.cs
- NoClickablePointException.cs
- TableLayoutPanelCellPosition.cs
- XmlArrayItemAttribute.cs
- DetailsViewDeleteEventArgs.cs
- CharacterString.cs
- FileLoadException.cs
- XmlCDATASection.cs
- ScrollChrome.cs
- SQLUtility.cs
- RegistrationProxy.cs
- URL.cs
- ApplicationInfo.cs
- ByteKeyFrameCollection.cs
- TextDecorationCollection.cs
- DateTimeValueSerializer.cs
- MenuCommand.cs
- Events.cs
- PrtTicket_Base.cs
- SQLBytesStorage.cs
- ToolStripArrowRenderEventArgs.cs
- DocumentEventArgs.cs
- DataSpaceManager.cs
- CorrelationActionMessageFilter.cs
- HtmlContainerControl.cs
- SqlRowUpdatingEvent.cs
- PropertyRef.cs
- StyleSelector.cs
- OrderedEnumerableRowCollection.cs
- OutOfMemoryException.cs
- ConfigurationException.cs
- PersonalizablePropertyEntry.cs
- SmiMetaData.cs
- TemplateManager.cs
- EntityCommandDefinition.cs
- PriorityQueue.cs
- CardSpaceShim.cs
- FtpWebRequest.cs
- AndCondition.cs
- AuthenticationConfig.cs
- GeneralTransformGroup.cs
- SystemIPInterfaceStatistics.cs
- RubberbandSelector.cs
- AppSettingsSection.cs
- DetailsViewCommandEventArgs.cs
- _KerberosClient.cs
- Char.cs
- AppDomainEvidenceFactory.cs
- SecurityPolicySection.cs
- FactoryRecord.cs
- DrawingImage.cs
- CompositeDataBoundControl.cs
- Pair.cs
- MetadataSet.cs
- NonVisualControlAttribute.cs
- ButtonBase.cs
- Cursor.cs
- EntityDataSourceWrapper.cs
- HealthMonitoringSectionHelper.cs
- TextRange.cs
- ActiveDesignSurfaceEvent.cs
- DirectoryRedirect.cs
- RoutedEventConverter.cs
- ResolvedKeyFrameEntry.cs
- DefaultProxySection.cs
- SqlParameter.cs
- PersonalizationProviderHelper.cs
- mactripleDES.cs
- EncryptedHeader.cs
- AlphabetConverter.cs
- SettingsBase.cs
- XmlSerializerFactory.cs
- MimeObjectFactory.cs
- HwndKeyboardInputProvider.cs
- CommandCollectionEditor.cs
- TagPrefixInfo.cs
- WindowsTitleBar.cs
- ExecutionContext.cs
- RuntimeHelpers.cs
- Matrix3DConverter.cs
- HtmlElementErrorEventArgs.cs
- Content.cs
- SqlCacheDependencyDatabaseCollection.cs
- UnsafeNativeMethods.cs
- remotingproxy.cs
- IdentitySection.cs
- ThaiBuddhistCalendar.cs
- ClientFormsAuthenticationCredentials.cs
- Crc32.cs
- FunctionUpdateCommand.cs
- ObjectIDGenerator.cs
- MultipartIdentifier.cs
- ListView.cs
- InvalidDataContractException.cs
- Decorator.cs
- PerformanceCounterPermission.cs
- TraceContextRecord.cs
- TemplatedWizardStep.cs