Code:
/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / Channels / peernodestatemanager.cs / 1 / peernodestatemanager.cs
//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------- namespace System.ServiceModel.Channels { using System.Collections.Generic; using System.Diagnostics; using System.ServiceModel.Diagnostics; using System.Threading; partial class PeerNodeImplementation { // A simple state manager for the PeerNode. Unlike the state managers used for channels and other // classes, a PeerNode's Open/Close is counted, a PeerNode is re-openable, and Abort only // takes effect if the outstanding number of Opens is 1. // The PeerNode defers to this object for all state related operations. // // Whenever a call is made that may change the state of the object (openCount transitions between 0 and 1), // an operation is queued. When an operation is removed from the queue, if the target state is still the // same as the operation (e.g. openCount > 0 and operation == Open) and the object is not already in that // state, the operation is performed by calling back into the PeerNode // // Because each operation is pulled form the queue one at a time, the open and close of the // PeerNode is serialized class SimpleStateManager { internal enum State { NotOpened, Opening, Opened, Closing }; State currentState = State.NotOpened; object thisLock = new object(); Queuequeue = new Queue (); bool queueRunning; int openCount; PeerNodeImplementation peerNode; public SimpleStateManager(PeerNodeImplementation peerNode) { this.peerNode = peerNode; } object ThisLock { get { return thisLock; } } public void Abort() { lock (ThisLock) { bool runAbort = false; if (openCount <= 1 && currentState != State.NotOpened) { runAbort = true; } if (openCount > 0) { --openCount; } if(runAbort) { try { peerNode.OnAbort(); } finally { currentState = State.NotOpened; } } } } public IAsyncResult BeginClose(TimeSpan timeout, AsyncCallback callback, object state) { CloseOperation op = null; lock (ThisLock) { if (openCount > 0) { --openCount; } if (openCount > 0) { return new CompletedAsyncResult(callback, state); } else { op = new CloseOperation(this, peerNode, timeout, callback, state); queue.Enqueue(op); RunQueue(); } } return op; } public IAsyncResult BeginOpen(TimeSpan timeout, AsyncCallback callback, object state, bool waitForOnline) { bool completedSynchronously = false; OpenOperation op = null; lock (ThisLock) { openCount++; if (openCount > 1 && currentState == State.Opened) { completedSynchronously = true; } else { op = new OpenOperation(this, peerNode, timeout, callback, state, waitForOnline); queue.Enqueue(op); RunQueue(); } } if(completedSynchronously) { return new CompletedAsyncResult(callback, state); } return op; } public void Close(TimeSpan timeout) { EndClose(BeginClose(timeout, null, null)); } public static void EndOpen(IAsyncResult result) { // result can be either an OpenOperation or a CompletedAsyncResult if (result is CompletedAsyncResult) CompletedAsyncResult.End(result); else OpenOperation.End(result); } public static void EndClose(IAsyncResult result) { // result can be either an CloseOperation or a CompletedAsyncResult if (result is CompletedAsyncResult) CompletedAsyncResult.End(result); else CloseOperation.End(result); } // Process IP Address change event from IP helper public void OnIPAddressesChanged(object sender, EventArgs e) { IPAddressChangeOperation op = null; lock (ThisLock) { op = new IPAddressChangeOperation(peerNode); queue.Enqueue(op); RunQueue(); } } public void Open(TimeSpan timeout, bool waitForOnline) { EndOpen(BeginOpen(timeout, null, null, waitForOnline)); } // Start running operations from the queue (must be called within lock) void RunQueue() { if (queueRunning) return; queueRunning = true; IOThreadScheduler.ScheduleCallback(new WaitCallback(RunQueueCallback), null); } void RunQueueCallback(object state) { IOperation op; // remove an operation from the queue lock (ThisLock) { DiagnosticUtility.DebugAssert(queue.Count > 0, "queue should not be empty"); op = queue.Dequeue(); } try { // execute the operation op.Run(); } finally { lock (ThisLock) { // if there are still pending operations, schedule another thread if (queue.Count > 0) { try { IOThreadScheduler.ScheduleCallback(new WaitCallback(RunQueueCallback), null); } catch(Exception e) { if(DiagnosticUtility.IsFatal(e)) throw; DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); } } else { queueRunning = false; } } } } interface IOperation { void Run(); } class CloseOperation : OperationBase { PeerNodeImplementation peerNode; public CloseOperation(SimpleStateManager stateManager, PeerNodeImplementation peerNode, TimeSpan timeout, AsyncCallback callback, object state) : base(stateManager, timeout, callback, state) { this.peerNode = peerNode; } protected override void Run() { Exception lclException = null; try { lock (ThisLock) { if (stateManager.openCount > 0) { // the current target state is no longer Closed invokeOperation = false; } else if (stateManager.currentState == State.NotOpened) { // the state is already Closed invokeOperation = false; } else if(timeoutHelper.RemainingTime() <= TimeSpan.Zero) { // Time out has already happened complete will be taken care of in the // OperationBase class invokeOperation = false; throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException()); } else { // the PeerNode needs to be closed if (!(stateManager.currentState != State.Opening && stateManager.currentState != State.Closing)) { DiagnosticUtility.DebugAssert("Open and close are serialized by queue We should not be either in Closing or Opening state at this point"); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } if(stateManager.currentState != State.NotOpened) { stateManager.currentState = State.Closing; invokeOperation = true; } } } } catch(Exception e) { if(DiagnosticUtility.IsFatal(e)) throw; DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); lclException = e; } if (invokeOperation) { try { peerNode.OnClose(timeoutHelper.RemainingTime()); } catch (Exception e) { if(DiagnosticUtility.IsFatal(e)) throw; DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); lclException = e; } lock (ThisLock) { stateManager.currentState = State.NotOpened; } } Complete(lclException); } } class OpenOperation : OperationBase { PeerNodeImplementation peerNode; bool waitForOnline; public OpenOperation(SimpleStateManager stateManager, PeerNodeImplementation peerNode, TimeSpan timeout, AsyncCallback callback, object state, bool waitForOnline) : base(stateManager, timeout, callback, state) { this.peerNode = peerNode; this.waitForOnline = waitForOnline; } protected override void Run() { Exception lclException = null; try { lock (ThisLock) { if (stateManager.openCount < 1) { // the current target state is no longer Opened invokeOperation = false; } else if (stateManager.currentState == State.Opened) { // the state is already Opened invokeOperation = false; } else if(timeoutHelper.RemainingTime() <= TimeSpan.Zero) { // Time out has already happened complete will be taken care of in the // OperationBase class invokeOperation = false; throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException()); } else { // the PeerNode needs to be opened if (!(stateManager.currentState != State.Opening && stateManager.currentState != State.Closing)) { DiagnosticUtility.DebugAssert("Open and close are serialized by queue We should not be either in Closing or Opening state at this point"); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } if(stateManager.currentState != State.Opened) { stateManager.currentState = State.Opening; invokeOperation = true; } } } } catch(Exception e) { if(DiagnosticUtility.IsFatal(e)) throw; DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); lclException = e; } if (invokeOperation) { try { peerNode.OnOpen(timeoutHelper.RemainingTime(), waitForOnline); lock (ThisLock) { stateManager.currentState = State.Opened; } } catch(Exception e) { if(DiagnosticUtility.IsFatal(e)) throw; lock (ThisLock) { stateManager.currentState = State.NotOpened; // since Open is throwing, we roll back the openCount because a matching Close is not // expected stateManager.openCount--; } lclException = e; DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); } } Complete(lclException); } } // Base class for Open and Cose abstract class OperationBase : AsyncResult, IOperation { protected SimpleStateManager stateManager; protected TimeoutHelper timeoutHelper; AsyncCallback callback; protected bool invokeOperation; bool completed; public OperationBase(SimpleStateManager stateManager, TimeSpan timeout, AsyncCallback callback, object state) : base(callback, state) { this.stateManager = stateManager; timeoutHelper = new TimeoutHelper(timeout); this.callback = callback; invokeOperation = false; completed = false; } void AsyncComplete(object o) { try { base.Complete(false, (Exception)o); } catch(Exception e) { if(DiagnosticUtility.IsFatal(e)) throw; throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(SR.GetString(SR.AsyncCallbackException), e); } } protected abstract void Run(); void IOperation.Run() { Run(); } protected void Complete(Exception exception) { if(completed) { return; } lock(ThisLock) { if(completed) { return; } completed = true; } try { if (callback != null) { // complete the AsyncResult on a separate thread so that the queue can progress. // this prevents a deadlock when the callback attempts to call Close. // this may cause the callbacks to be called in a differnet order in which they completed, but that // is ok because each callback is associated with a different object (channel or listener factory) IOThreadScheduler.ScheduleCallback(new WaitCallback(AsyncComplete), exception); } else { AsyncComplete(exception); } } catch(Exception e) { if(DiagnosticUtility.IsFatal(e)) throw; throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(SR.GetString(SR.MessagePropagationException), e); } } protected object ThisLock { get { return stateManager.thisLock; } } static public void End(IAsyncResult result) { AsyncResult.End (result); } } // To serialize IP address change processing class IPAddressChangeOperation : IOperation { PeerNodeImplementation peerNode; public IPAddressChangeOperation(PeerNodeImplementation peerNode) { this.peerNode = peerNode; } void IOperation.Run() { peerNode.OnIPAddressChange(); } } } } } // 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
- listitem.cs
- CfgParser.cs
- XamlInterfaces.cs
- DocumentManager.cs
- SafeHandles.cs
- UpdatePanelControlTrigger.cs
- ConfigurationPropertyCollection.cs
- FunctionNode.cs
- NativeMethodsOther.cs
- DataError.cs
- CompositeActivityCodeGenerator.cs
- HandleCollector.cs
- BinaryObjectInfo.cs
- HttpPostProtocolImporter.cs
- AvTraceDetails.cs
- DataServiceContext.cs
- ClientCredentials.cs
- FontWeights.cs
- CompositeActivityMarkupSerializer.cs
- ZipIOZip64EndOfCentralDirectoryBlock.cs
- TextTreeObjectNode.cs
- ListBoxItemAutomationPeer.cs
- IPHostEntry.cs
- MulticastNotSupportedException.cs
- SafeProcessHandle.cs
- WebServiceErrorEvent.cs
- FixedSOMTextRun.cs
- DataGridHeaderBorder.cs
- Menu.cs
- ComAdminInterfaces.cs
- AnnotationResourceCollection.cs
- FrameAutomationPeer.cs
- FileEnumerator.cs
- PanelStyle.cs
- DispatcherExceptionEventArgs.cs
- QilUnary.cs
- TreeNode.cs
- DragDropHelper.cs
- SymbolEqualComparer.cs
- Accessible.cs
- X509Chain.cs
- SizeLimitedCache.cs
- RemotingSurrogateSelector.cs
- SqlPersonalizationProvider.cs
- LockedAssemblyCache.cs
- X509CertificateRecipientServiceCredential.cs
- ImmutableCommunicationTimeouts.cs
- WindowsSolidBrush.cs
- QueryOptionExpression.cs
- FontFaceLayoutInfo.cs
- ProcessModuleCollection.cs
- FamilyTypeface.cs
- Debug.cs
- ServiceDocumentFormatter.cs
- EventBuilder.cs
- BitmapInitialize.cs
- CodeEventReferenceExpression.cs
- TextParaLineResult.cs
- TileModeValidation.cs
- ProfessionalColors.cs
- DoubleConverter.cs
- FirstMatchCodeGroup.cs
- StateChangeEvent.cs
- UIElement3D.cs
- PackWebResponse.cs
- XmlObjectSerializerWriteContextComplex.cs
- TreeView.cs
- DerivedKeyCachingSecurityTokenSerializer.cs
- DataObjectFieldAttribute.cs
- WindowsToolbar.cs
- IndexedGlyphRun.cs
- ToolStripRenderer.cs
- DesignerDataView.cs
- PtsHost.cs
- MatcherBuilder.cs
- DataServiceResponse.cs
- ByteStack.cs
- InputBuffer.cs
- UshortList2.cs
- ComplexLine.cs
- ExcludePathInfo.cs
- RecordsAffectedEventArgs.cs
- PrintSchema.cs
- _TransmitFileOverlappedAsyncResult.cs
- Currency.cs
- PublishLicense.cs
- SmtpDateTime.cs
- ProxyWebPartManager.cs
- MimeTypeAttribute.cs
- WebConfigurationHost.cs
- GridViewItemAutomationPeer.cs
- DataGridViewRowStateChangedEventArgs.cs
- CompareValidator.cs
- GridViewEditEventArgs.cs
- ToolStripDesignerAvailabilityAttribute.cs
- XmlNamespaceDeclarationsAttribute.cs
- RelationshipConverter.cs
- DispatcherSynchronizationContext.cs
- AlphabeticalEnumConverter.cs
- DefaultWorkflowTransactionService.cs