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
- SessionIDManager.cs
- BindingExpressionUncommonField.cs
- BamlTreeUpdater.cs
- UntypedNullExpression.cs
- ListViewItem.cs
- MetabaseServerConfig.cs
- MsmqInputSessionChannelListener.cs
- CompatibleIComparer.cs
- TreeView.cs
- SqlErrorCollection.cs
- ProviderIncompatibleException.cs
- AttachmentService.cs
- WbemException.cs
- RangeValidator.cs
- SQLDoubleStorage.cs
- ExceptionRoutedEventArgs.cs
- DataContractSet.cs
- DataSysAttribute.cs
- EndpointAddressProcessor.cs
- SerialPort.cs
- StrongNameIdentityPermission.cs
- UpdatableWrapper.cs
- _SingleItemRequestCache.cs
- ArrayConverter.cs
- XsdDataContractImporter.cs
- IndicShape.cs
- TemplateKey.cs
- ExecutionProperties.cs
- ArgumentValue.cs
- ParallelEnumerableWrapper.cs
- DataFormat.cs
- EmbeddedMailObjectsCollection.cs
- DataGridAutomationPeer.cs
- Double.cs
- LinkLabel.cs
- DES.cs
- XmlRootAttribute.cs
- DataGridViewCellFormattingEventArgs.cs
- EntityObject.cs
- DecimalAnimation.cs
- XmlSchemaGroupRef.cs
- LockRecoveryTask.cs
- Brush.cs
- DataSourceControlBuilder.cs
- NetworkAddressChange.cs
- SafeArrayRankMismatchException.cs
- DomNameTable.cs
- OperationResponse.cs
- QilInvokeLateBound.cs
- VBIdentifierName.cs
- Propagator.JoinPropagator.cs
- DesignerLoader.cs
- ClassHandlersStore.cs
- SerialPort.cs
- base64Transforms.cs
- ListSourceHelper.cs
- ConfigXmlElement.cs
- ForAllOperator.cs
- UInt16Converter.cs
- LicenseProviderAttribute.cs
- ValidationEventArgs.cs
- XmlSchemaComplexContentExtension.cs
- SrgsElementList.cs
- MatrixConverter.cs
- SiteMap.cs
- DecoderFallback.cs
- EnumType.cs
- ConstNode.cs
- Exceptions.cs
- EventArgs.cs
- SystemDropShadowChrome.cs
- CapabilitiesPattern.cs
- PropertyFilterAttribute.cs
- HuffmanTree.cs
- URIFormatException.cs
- EntityDataSourceView.cs
- StateMachine.cs
- StyleBamlRecordReader.cs
- ForEachAction.cs
- CacheDependency.cs
- ExtentCqlBlock.cs
- IgnoreDataMemberAttribute.cs
- SystemEvents.cs
- TraceHandlerErrorFormatter.cs
- Keyboard.cs
- PrivateFontCollection.cs
- WebBrowserDocumentCompletedEventHandler.cs
- WeakReference.cs
- ControlParameter.cs
- XmlQualifiedName.cs
- ViewCellSlot.cs
- RadialGradientBrush.cs
- CanExecuteRoutedEventArgs.cs
- XmlSchemaFacet.cs
- CommonXSendMessage.cs
- ClientBuildManagerCallback.cs
- WebPartConnectVerb.cs
- QuinticEase.cs
- QueryAccessibilityHelpEvent.cs
- HMACSHA256.cs