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
- ValidationVisibilityAttribute.cs
- InputBindingCollection.cs
- InterleavedZipPartStream.cs
- InfoCardArgumentException.cs
- UInt32Converter.cs
- COM2ICategorizePropertiesHandler.cs
- TextEmbeddedObject.cs
- WmlImageAdapter.cs
- SessionEndedEventArgs.cs
- followingquery.cs
- ListBindingConverter.cs
- CompilationUtil.cs
- GridViewRow.cs
- CombinedHttpChannel.cs
- DataGridCommandEventArgs.cs
- FlowDocumentReader.cs
- XmlnsCache.cs
- DbMetaDataCollectionNames.cs
- String.cs
- Closure.cs
- ApplicationActivator.cs
- InternalDuplexBindingElement.cs
- StateValidator.cs
- DescendantQuery.cs
- Viewport3DVisual.cs
- XmlName.cs
- InfiniteIntConverter.cs
- SqlDelegatedTransaction.cs
- WebServiceReceiveDesigner.cs
- Int16Storage.cs
- DelayedRegex.cs
- ModelUIElement3D.cs
- FilterQuery.cs
- XmlSchemaAnyAttribute.cs
- EntityDataSourceReferenceGroup.cs
- ImageField.cs
- GuidTagList.cs
- ServiceProviders.cs
- safelinkcollection.cs
- MetadataCollection.cs
- InvalidCommandTreeException.cs
- SqlFacetAttribute.cs
- MultipartContentParser.cs
- QueryOptionExpression.cs
- CallbackValidator.cs
- Lease.cs
- CollectionChangedEventManager.cs
- DataList.cs
- StateMachineWorkflowDesigner.cs
- EventLogEntryCollection.cs
- StackSpiller.Generated.cs
- StringComparer.cs
- ComponentGuaranteesAttribute.cs
- dbdatarecord.cs
- ReferencedAssembly.cs
- ValidationErrorInfo.cs
- UTF32Encoding.cs
- AsymmetricSecurityProtocolFactory.cs
- CatalogPartCollection.cs
- GenericXmlSecurityToken.cs
- OrderPreservingPipeliningSpoolingTask.cs
- HandlerBase.cs
- CriticalFinalizerObject.cs
- DataGridViewRowEventArgs.cs
- Pen.cs
- WeakReferenceKey.cs
- RegexParser.cs
- GenericEnumerator.cs
- GenerateHelper.cs
- storepermissionattribute.cs
- PrincipalPermissionMode.cs
- WebEventTraceProvider.cs
- HtmlInputPassword.cs
- QueryAccessibilityHelpEvent.cs
- EmptyElement.cs
- ObjectSet.cs
- CqlQuery.cs
- SQLResource.cs
- NgenServicingAttributes.cs
- EventEntry.cs
- LinqDataSourceHelper.cs
- HyperLinkField.cs
- Hyperlink.cs
- DataControlCommands.cs
- StringComparer.cs
- RuleSetBrowserDialog.cs
- MessageQueueAccessControlEntry.cs
- EditingScope.cs
- SystemTcpConnection.cs
- ModuleElement.cs
- ButtonRenderer.cs
- TreeNodeBindingCollection.cs
- PropertyFilterAttribute.cs
- EmptyCollection.cs
- DragCompletedEventArgs.cs
- _DomainName.cs
- MediaSystem.cs
- XMLSyntaxException.cs
- MetadataCacheItem.cs
- TextViewSelectionProcessor.cs