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
- UnknownWrapper.cs
- LocatorGroup.cs
- DbProviderFactories.cs
- ICollection.cs
- SqlConnectionFactory.cs
- StrokeNodeOperations.cs
- AutoResizedEvent.cs
- FlowDocumentView.cs
- GorillaCodec.cs
- DocumentDesigner.cs
- ILGen.cs
- pingexception.cs
- LinqDataSourceEditData.cs
- ExpressionHelper.cs
- WebPart.cs
- ToolConsole.cs
- cookieexception.cs
- XsltCompileContext.cs
- WsdlInspector.cs
- HelpProvider.cs
- XmlSchemaObject.cs
- DbDataReader.cs
- BitmapDownload.cs
- ReadWriteObjectLock.cs
- Size3D.cs
- OleDbParameter.cs
- XmlAggregates.cs
- AlignmentYValidation.cs
- WebPartZoneAutoFormat.cs
- StickyNoteAnnotations.cs
- XmlWhitespace.cs
- InvalidDataException.cs
- PenLineCapValidation.cs
- Point4DConverter.cs
- Validator.cs
- XmlEncoding.cs
- ExpanderAutomationPeer.cs
- PeerNameRecord.cs
- HtmlTable.cs
- IDataContractSurrogate.cs
- FreeFormPanel.cs
- XmlIlTypeHelper.cs
- References.cs
- SymLanguageType.cs
- FilterElement.cs
- AsyncStreamReader.cs
- DataSourceControlBuilder.cs
- AssociatedControlConverter.cs
- PersonalizationProviderCollection.cs
- MetadataItemEmitter.cs
- DefaultBinder.cs
- XmlQueryOutput.cs
- LinkDescriptor.cs
- PipeSecurity.cs
- TextEffectResolver.cs
- RelatedPropertyManager.cs
- ScriptManager.cs
- NGCPageContentSerializerAsync.cs
- SerializationObjectManager.cs
- DataBoundControlHelper.cs
- RunClient.cs
- FormsAuthenticationConfiguration.cs
- TypedElement.cs
- GestureRecognizer.cs
- EmptyReadOnlyDictionaryInternal.cs
- SqlParameter.cs
- MetadataStore.cs
- ControlEvent.cs
- OdbcStatementHandle.cs
- SocketConnection.cs
- Point4DConverter.cs
- SiteMapProvider.cs
- ReadOnlyHierarchicalDataSourceView.cs
- TextEditorSelection.cs
- AttachedPropertiesService.cs
- PipelineModuleStepContainer.cs
- MorphHelper.cs
- SatelliteContractVersionAttribute.cs
- RewritingValidator.cs
- ScriptingSectionGroup.cs
- InstanceData.cs
- WebEvents.cs
- AutomationElement.cs
- WindowsTooltip.cs
- RegexMatchCollection.cs
- MediaTimeline.cs
- SecurityElement.cs
- SocketPermission.cs
- StdValidatorsAndConverters.cs
- CachingHintValidation.cs
- glyphs.cs
- BitmapCache.cs
- TypeUtil.cs
- ConditionalBranch.cs
- JoinCqlBlock.cs
- XmlNodeList.cs
- HttpHandlerAction.cs
- ConfigXmlText.cs
- RadioButtonBaseAdapter.cs
- PersistenceTypeAttribute.cs