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
- DelayedRegex.cs
- TextEmbeddedObject.cs
- TextHidden.cs
- EntityDesignerBuildProvider.cs
- ErrorFormatterPage.cs
- VoiceInfo.cs
- ViewEventArgs.cs
- RegexStringValidator.cs
- AddDataControlFieldDialog.cs
- CurrentChangingEventManager.cs
- ChannelDemuxer.cs
- XPathNavigator.cs
- SafeNativeMethodsOther.cs
- _IPv6Address.cs
- ApplyImportsAction.cs
- SocketStream.cs
- SingleTagSectionHandler.cs
- ChooseAction.cs
- Registry.cs
- MenuItemBindingCollection.cs
- WebBrowsableAttribute.cs
- PasswordBoxAutomationPeer.cs
- VisualStyleRenderer.cs
- assertwrapper.cs
- PriorityQueue.cs
- OutputCacheModule.cs
- MulticastDelegate.cs
- CustomGrammar.cs
- CompensationHandlingFilter.cs
- StylusPointPropertyUnit.cs
- CodeVariableReferenceExpression.cs
- DataRowChangeEvent.cs
- ToolStripProgressBar.cs
- Matrix3D.cs
- DecimalStorage.cs
- XPathBuilder.cs
- DigestComparer.cs
- ListItem.cs
- BindingOperations.cs
- SerializationAttributes.cs
- HttpVersion.cs
- HttpCacheVaryByContentEncodings.cs
- AuthenticationService.cs
- Ops.cs
- IteratorFilter.cs
- TypeDescriptionProviderAttribute.cs
- PolicyStatement.cs
- InputElement.cs
- MaskedTextBox.cs
- DefaultBinder.cs
- ADMembershipUser.cs
- NavigateEvent.cs
- AttributeCollection.cs
- CssClassPropertyAttribute.cs
- LateBoundBitmapDecoder.cs
- LayoutSettings.cs
- BaseDataBoundControl.cs
- BaseTemplateParser.cs
- ContentElement.cs
- GeneralTransform.cs
- SmtpReplyReaderFactory.cs
- SiteMapHierarchicalDataSourceView.cs
- Animatable.cs
- InitializerFacet.cs
- SystemException.cs
- StreamResourceInfo.cs
- IntermediatePolicyValidator.cs
- CallbackTimeoutsElement.cs
- WSMessageEncoding.cs
- PropertyCollection.cs
- ReliableChannelFactory.cs
- Int16Storage.cs
- EnumUnknown.cs
- StrokeIntersection.cs
- PersonalizationStateInfoCollection.cs
- MsmqIntegrationChannelFactory.cs
- CultureTableRecord.cs
- SafeCertificateStore.cs
- QilTypeChecker.cs
- QuestionEventArgs.cs
- TypeAccessException.cs
- XsltLoader.cs
- WebPartZoneCollection.cs
- AdornerDecorator.cs
- OleDbParameter.cs
- TypeRestriction.cs
- FontStretch.cs
- SettingsSavedEventArgs.cs
- SspiWrapper.cs
- SqlMethodAttribute.cs
- HttpFileCollection.cs
- ConfigXmlAttribute.cs
- TrackingValidationObjectDictionary.cs
- Quad.cs
- EntityChangedParams.cs
- XPathAxisIterator.cs
- RayMeshGeometry3DHitTestResult.cs
- ObjRef.cs
- FormViewUpdatedEventArgs.cs
- UpdateTracker.cs