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
- PathGeometry.cs
- IgnoreDeviceFilterElementCollection.cs
- documentation.cs
- SmtpNegotiateAuthenticationModule.cs
- DataGridViewAutoSizeColumnModeEventArgs.cs
- SchemaNotation.cs
- PageDeviceFont.cs
- InvalidFilterCriteriaException.cs
- UriWriter.cs
- MergeFilterQuery.cs
- HebrewNumber.cs
- CodeIterationStatement.cs
- CalendarButtonAutomationPeer.cs
- SectionRecord.cs
- COM2ComponentEditor.cs
- Preprocessor.cs
- TokenBasedSet.cs
- StickyNoteContentControl.cs
- PropertyPushdownHelper.cs
- SpellerHighlightLayer.cs
- ExtenderProviderService.cs
- DPCustomTypeDescriptor.cs
- XmlDataProvider.cs
- MediaElementAutomationPeer.cs
- Rotation3D.cs
- ErrorWrapper.cs
- MultitargetUtil.cs
- ImpersonationContext.cs
- UshortList2.cs
- Mutex.cs
- XmlBinaryReader.cs
- Helpers.cs
- StreamWithDictionary.cs
- DataServiceProcessingPipeline.cs
- Keywords.cs
- Compiler.cs
- IIS7WorkerRequest.cs
- InitiatorSessionSymmetricTransportSecurityProtocol.cs
- TextBounds.cs
- TreeSet.cs
- LiteralDesigner.cs
- BigInt.cs
- Debugger.cs
- ObjectListShowCommandsEventArgs.cs
- SafeUserTokenHandle.cs
- PackageRelationshipSelector.cs
- RegexCharClass.cs
- ProviderManager.cs
- ImageCodecInfo.cs
- ICollection.cs
- SchemaImporter.cs
- ComponentResourceManager.cs
- XslTransform.cs
- Freezable.cs
- MultiByteCodec.cs
- FtpWebResponse.cs
- QilReplaceVisitor.cs
- GuidelineCollection.cs
- X509CertificateCollection.cs
- CommonRemoteMemoryBlock.cs
- XPathExpr.cs
- PartialList.cs
- OleDbMetaDataFactory.cs
- PropertyChangingEventArgs.cs
- GlobalAllocSafeHandle.cs
- Subset.cs
- Utils.cs
- UInt32Storage.cs
- Number.cs
- CommandBinding.cs
- OutputCacheModule.cs
- WorkflowViewService.cs
- XsltInput.cs
- SwitchAttribute.cs
- SystemIPGlobalProperties.cs
- FigureParaClient.cs
- ComponentRenameEvent.cs
- MouseActionValueSerializer.cs
- SoapExtensionTypeElement.cs
- ArcSegment.cs
- DataControlReference.cs
- TypeElement.cs
- ContextProperty.cs
- TeredoHelper.cs
- AutomationProperties.cs
- GetPageNumberCompletedEventArgs.cs
- TableDetailsRow.cs
- PersonalizationDictionary.cs
- SrgsText.cs
- XmlSchemaAnyAttribute.cs
- IndexedGlyphRun.cs
- DecimalAverageAggregationOperator.cs
- ResourceContainer.cs
- DetailsView.cs
- ScriptingProfileServiceSection.cs
- TextSerializer.cs
- SQLMoney.cs
- TheQuery.cs
- SqlGatherProducedAliases.cs
- ValueQuery.cs