Code:
/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / Channels / OverlappedContext.cs / 1 / OverlappedContext.cs
//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------- namespace System.ServiceModel.Channels { using System.Threading; using System.Diagnostics; using System.ServiceModel.Diagnostics; using System.Runtime.InteropServices; delegate void OverlappedIOCompleteCallback(bool haveResult, int error, int bytesRead); unsafe class OverlappedContext { const int HandleOffsetFromOverlapped32 = -4; const int HandleOffsetFromOverlapped64 = -3; static IOCompletionCallback completeCallback; static WaitOrTimerCallback eventCallback; static WaitOrTimerCallback cleanupCallback; static byte[] dummyBuffer = new byte[0]; object[] bufferHolder; byte* bufferPtr; NativeOverlapped* nativeOverlapped; GCHandle pinnedHandle; object pinnedTarget; Overlapped overlapped; RootedHolder rootedHolder; OverlappedIOCompleteCallback pendingCallback; // Null when no async I/O is pending. bool deferredFree; bool syncOperationPending; ManualResetEvent completionEvent; IntPtr eventHandle; // Only used by unbound I/O. RegisteredWaitHandle registration; #if DEBUG_EXPENSIVE StackTrace freeStack; #endif public OverlappedContext() { if (OverlappedContext.completeCallback == null) { OverlappedContext.completeCallback = DiagnosticUtility.Utility.ThunkCallback(new IOCompletionCallback(CompleteCallback)); } if (OverlappedContext.eventCallback == null) { OverlappedContext.eventCallback = DiagnosticUtility.Utility.ThunkCallback(new WaitOrTimerCallback(EventCallback)); } if (OverlappedContext.cleanupCallback == null) { OverlappedContext.cleanupCallback = DiagnosticUtility.Utility.ThunkCallback(new WaitOrTimerCallback(CleanupCallback)); } this.bufferHolder = new object[] { OverlappedContext.dummyBuffer }; this.overlapped = new Overlapped(); this.nativeOverlapped = this.overlapped.UnsafePack(OverlappedContext.completeCallback, this.bufferHolder); // When replacing the buffer, we need to provoke the CLR to fix up the handle of the pin. this.pinnedHandle = GCHandle.FromIntPtr(*((IntPtr*) nativeOverlapped + (IntPtr.Size == 4 ? HandleOffsetFromOverlapped32 : HandleOffsetFromOverlapped64))); this.pinnedTarget = this.pinnedHandle.Target; // Create the permanently rooted holder and put it in the Overlapped. this.rootedHolder = new RootedHolder(); this.overlapped.AsyncResult = rootedHolder; } ~OverlappedContext() { if (this.nativeOverlapped != null && !AppDomain.CurrentDomain.IsFinalizingForUnload() && !Environment.HasShutdownStarted) { if (this.syncOperationPending) { DiagnosticUtility.DebugAssert(this.rootedHolder != null, "rootedHolder null in Finalize."); DiagnosticUtility.DebugAssert(this.rootedHolder.EventHolder != null, "rootedHolder.EventHolder null in Finalize."); DiagnosticUtility.DebugAssert(OverlappedContext.cleanupCallback != null, "cleanupCallback null in Finalize."); // Can't free the overlapped. Register a callback to deal with this. // This will ressurect the OverlappedContext. // The completionEvent will still be alive (not finalized) since it's rooted by the pending Overlapped in the holder. // We own it now and will close it in the callback. ThreadPool.UnsafeRegisterWaitForSingleObject(this.rootedHolder.EventHolder, OverlappedContext.cleanupCallback, this, Timeout.Infinite, true); } else { Overlapped.Free(this.nativeOverlapped); } } } // None of the OverlappedContext methods are threadsafe. // Free or FreeOrDefer can only be called once. FreeIfDeferred can be called any number of times, as long as it's only // called once after FreeOrDefer. public void Free() { if (this.pendingCallback != null) { DiagnosticUtility.DebugAssert("OverlappedContext.Free called while async operation is pending."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } if (this.syncOperationPending) { DiagnosticUtility.DebugAssert("OverlappedContext.Free called while sync operation is pending."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } if (this.nativeOverlapped == null) { DiagnosticUtility.DebugAssert("OverlappedContext.Free called multiple times."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } #if DEBUG_EXPENSIVE this.freeStack = new StackTrace(); #endif NativeOverlapped* nativePtr = this.nativeOverlapped; this.nativeOverlapped = null; Overlapped.Free(nativePtr); if (this.completionEvent != null) { this.completionEvent.Close(); } GC.SuppressFinalize(this); } public void FreeOrDefer() { if (this.pendingCallback != null || this.syncOperationPending) { this.deferredFree = true; } else { Free(); } } public void FreeIfDeferred() { if (this.deferredFree) { FreeOrDefer(); } } public void StartAsyncOperation(byte[] buffer, OverlappedIOCompleteCallback callback, bool bound) { if (callback == null) { DiagnosticUtility.DebugAssert("StartAsyncOperation called with null callback."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } if (this.pendingCallback != null) { DiagnosticUtility.DebugAssert("StartAsyncOperation called while another is in progress."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } if (this.syncOperationPending) { DiagnosticUtility.DebugAssert("StartAsyncOperation called while a sync operation was already pending."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } if (this.nativeOverlapped == null) { DiagnosticUtility.DebugAssert("StartAsyncOperation called on freed OverlappedContext."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } this.pendingCallback = callback; if (buffer != null) { DiagnosticUtility.DebugAssert(object.ReferenceEquals(this.bufferHolder[0], OverlappedContext.dummyBuffer), "StartAsyncOperation: buffer holder corrupted."); this.bufferHolder[0] = buffer; this.pinnedHandle.Target = this.pinnedTarget; this.bufferPtr = (byte*) Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0); } if (bound) { this.overlapped.EventHandleIntPtr = IntPtr.Zero; // For completion ports, the back-reference is this member. this.rootedHolder.ThisHolder = this; } else { // Need to do this since we register the wait before posting the I/O. if (this.completionEvent != null) { this.completionEvent.Reset(); } this.overlapped.EventHandleIntPtr = EventHandle; // For unbound, the back-reference is this registration. this.registration = ThreadPool.UnsafeRegisterWaitForSingleObject(this.completionEvent, OverlappedContext.eventCallback, this, Timeout.Infinite, true); } } public void CancelAsyncOperation() { this.rootedHolder.ThisHolder = null; if (this.registration != null) { this.registration.Unregister(null); this.registration = null; } this.bufferPtr = null; this.bufferHolder[0] = OverlappedContext.dummyBuffer; this.pendingCallback = null; } // public void StartSyncOperation(byte[] buffer) // { // StartSyncOperation(buffer, ref this.bufferHolder[0], false); // } // The only holder allowed is Holder[0]. It can be passed in as a ref to prevent repeated expensive array lookups. public void StartSyncOperation(byte[] buffer, ref object holder) { if (this.syncOperationPending) { DiagnosticUtility.DebugAssert("StartSyncOperation called while an operation was already pending."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } if (this.pendingCallback != null) { DiagnosticUtility.DebugAssert("StartSyncOperation called while an async operation was already pending."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } if (this.nativeOverlapped == null) { DiagnosticUtility.DebugAssert("StartSyncOperation called on freed OverlappedContext."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } this.overlapped.EventHandleIntPtr = EventHandle; // Sync operations do NOT root this object. If it gets finalized, we need to know not to free the buffer. // We do root the event. this.rootedHolder.EventHolder = this.completionEvent; this.syncOperationPending = true; if (buffer != null) { DiagnosticUtility.DebugAssert(object.ReferenceEquals(holder, OverlappedContext.dummyBuffer), "StartSyncOperation: buffer holder corrupted."); holder = buffer; this.pinnedHandle.Target = this.pinnedTarget; this.bufferPtr = (byte*) Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0); } } // If this returns false, the OverlappedContext is no longer usable. It shouldn't be freed or anything. public bool WaitForSyncOperation(TimeSpan timeout) { return WaitForSyncOperation(timeout, ref this.bufferHolder[0]); } // The only holder allowed is Holder[0]. It can be passed in as a ref to prevent repeated expensive array lookups. public bool WaitForSyncOperation(TimeSpan timeout, ref object holder) { if (!this.syncOperationPending) { DiagnosticUtility.DebugAssert("WaitForSyncOperation called while no operation was pending."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } if (!UnsafeNativeMethods.HasOverlappedIoCompleted(this.nativeOverlapped)) { if (!TimeoutHelper.WaitOne(this.completionEvent, timeout, false)) { // We can't free ourselves until the operation is done. The only way to do that is register a callback. // This will root the object. No longer any need for the finalizer. This instance is unusable after this. GC.SuppressFinalize(this); ThreadPool.UnsafeRegisterWaitForSingleObject(this.completionEvent, OverlappedContext.cleanupCallback, this, Timeout.Infinite, true); return false; } } DiagnosticUtility.DebugAssert(this.bufferPtr == null || this.bufferPtr == (byte*) Marshal.UnsafeAddrOfPinnedArrayElement((byte[]) holder, 0), "The buffer moved during a sync call!"); CancelSyncOperation(ref holder); return true; } // public void CancelSyncOperation() // { // CancelSyncOperation(ref this.bufferHolder[0]); // } // The only holder allowed is Holder[0]. It can be passed in as a ref to prevent repeated expensive array lookups. public void CancelSyncOperation(ref object holder) { this.bufferPtr = null; holder = OverlappedContext.dummyBuffer; DiagnosticUtility.DebugAssert(object.ReferenceEquals(this.bufferHolder[0], OverlappedContext.dummyBuffer), "Bad holder passed to CancelSyncOperation."); this.syncOperationPending = false; this.rootedHolder.EventHolder = null; } // This should ONLY be used to make a 'ref object' parameter to the zeroth element, to prevent repeated expensive array lookups. public object[] Holder { get { return this.bufferHolder; } } public byte* BufferPtr { get { byte* ptr = this.bufferPtr; if (ptr == null) { DiagnosticUtility.DebugAssert("Pointer requested while no operation pending or no buffer provided."); #pragma warning suppress 56503 // [....], not a publicly accessible API throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } return ptr; } } public NativeOverlapped* NativeOverlapped { get { NativeOverlapped* ptr = this.nativeOverlapped; if (ptr == null) { DiagnosticUtility.DebugAssert("NativeOverlapped pointer requested after it was freed."); #pragma warning suppress 56503 // [....], not a publicly accessible API throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } return ptr; } } IntPtr EventHandle { get { if (this.completionEvent == null) { this.completionEvent = new ManualResetEvent(false); this.eventHandle = (IntPtr) (1 | (long) this.completionEvent.SafeWaitHandle.DangerousGetHandle()); } return this.eventHandle; } } static void CompleteCallback(uint error, uint numBytes, NativeOverlapped* nativeOverlapped) { // Empty out the AsyncResult ASAP to close the leak window. Overlapped overlapped = Overlapped.Unpack(nativeOverlapped); OverlappedContext pThis = ((RootedHolder) overlapped.AsyncResult).ThisHolder; DiagnosticUtility.DebugAssert(pThis != null, "Overlapped.AsyncResult not set. I/O completed multiple times, or cancelled I/O completed."); DiagnosticUtility.DebugAssert(object.ReferenceEquals(pThis.overlapped, overlapped), "CompleteCallback completed with corrupt OverlappedContext.overlapped."); DiagnosticUtility.DebugAssert(object.ReferenceEquals(pThis.rootedHolder, overlapped.AsyncResult), "CompleteCallback completed with corrupt OverlappedContext.rootedHolder."); pThis.rootedHolder.ThisHolder = null; DiagnosticUtility.DebugAssert(pThis.bufferPtr == null || pThis.bufferPtr == (byte*) Marshal.UnsafeAddrOfPinnedArrayElement((byte[]) pThis.bufferHolder[0], 0), "Buffer moved during bound async operation!"); // Release the pin. pThis.bufferPtr = null; pThis.bufferHolder[0] = OverlappedContext.dummyBuffer; OverlappedIOCompleteCallback callback = pThis.pendingCallback; pThis.pendingCallback = null; DiagnosticUtility.DebugAssert(callback != null, "PendingCallback not set. I/O completed multiple times, or cancelled I/O completed."); callback(true, (int) error, checked((int) numBytes)); } static void EventCallback(object state, bool timedOut) { OverlappedContext pThis = state as OverlappedContext; DiagnosticUtility.DebugAssert(pThis != null, "OverlappedContext.EventCallback registered wait doesn't have an OverlappedContext as state."); if (timedOut) { DiagnosticUtility.DebugAssert("OverlappedContext.EventCallback registered wait timed out."); // Turn this into a leak. Don't let ourselves get cleaned up - could scratch the heap. if (pThis == null || pThis.rootedHolder == null) { // We're doomed to do a wild write and corrupt the process. DiagnosticUtility.FailFast("Can't prevent heap corruption."); } pThis.rootedHolder.ThisHolder = pThis; return; } pThis.registration = null; DiagnosticUtility.DebugAssert(pThis.bufferPtr == null || pThis.bufferPtr == (byte*) Marshal.UnsafeAddrOfPinnedArrayElement((byte[]) pThis.bufferHolder[0], 0), "Buffer moved during unbound async operation!"); // Release the pin. pThis.bufferPtr = null; pThis.bufferHolder[0] = OverlappedContext.dummyBuffer; OverlappedIOCompleteCallback callback = pThis.pendingCallback; pThis.pendingCallback = null; DiagnosticUtility.DebugAssert(callback != null, "PendingCallback not set. I/O completed multiple times, or cancelled I/O completed."); callback(false, 0, 0); } static void CleanupCallback(object state, bool timedOut) { OverlappedContext pThis = state as OverlappedContext; DiagnosticUtility.DebugAssert(pThis != null, "OverlappedContext.CleanupCallback registered wait doesn't have an OverlappedContext as state."); if (timedOut) { DiagnosticUtility.DebugAssert("OverlappedContext.CleanupCallback registered wait timed out."); // Turn this into a leak. return; } DiagnosticUtility.DebugAssert(pThis.bufferPtr == null || pThis.bufferPtr == (byte*) Marshal.UnsafeAddrOfPinnedArrayElement((byte[]) pThis.bufferHolder[0], 0), "Buffer moved during synchronous deferred cleanup!"); DiagnosticUtility.DebugAssert(pThis.syncOperationPending, "OverlappedContext.CleanupCallback called with no sync operation pending."); pThis.rootedHolder.EventHolder.Close(); Overlapped.Free(pThis.nativeOverlapped); } // This class is always held onto (rooted) by the packed Overlapped. The OverlappedContext instance moves itself in and out of // this object to root itself. It's also used to root the ManualResetEvent during sync operations. // It needs to be an IAsyncResult since that's what Overlapped takes. class RootedHolder : IAsyncResult { OverlappedContext overlappedBuffer; ManualResetEvent eventHolder; public OverlappedContext ThisHolder { get { return this.overlappedBuffer; } set { this.overlappedBuffer = value; } } public ManualResetEvent EventHolder { get { return this.eventHolder; } set { this.eventHolder = value; } } // Unused IAsyncResult implementation. object IAsyncResult.AsyncState { get { DiagnosticUtility.DebugAssert("RootedHolder.AsyncState called."); #pragma warning suppress 56503 // [....], not a publicly accessible API throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } } WaitHandle IAsyncResult.AsyncWaitHandle { get { DiagnosticUtility.DebugAssert("RootedHolder.AsyncWaitHandle called."); #pragma warning suppress 56503 // [....], not a publicly accessible API throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } } bool IAsyncResult.CompletedSynchronously { get { DiagnosticUtility.DebugAssert("RootedHolder.CompletedSynchronously called."); #pragma warning suppress 56503 // [....], not a publicly accessible API throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } } bool IAsyncResult.IsCompleted { get { DiagnosticUtility.DebugAssert("RootedHolder.IsCompleted called."); #pragma warning suppress 56503 // [....], not a publicly accessible API throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } } } } } // 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
- PngBitmapEncoder.cs
- Range.cs
- PeerUnsafeNativeMethods.cs
- ContextMenuStrip.cs
- HttpCookie.cs
- Setter.cs
- DataStreams.cs
- UniformGrid.cs
- ExpressionConverter.cs
- KeyedCollection.cs
- FormattedText.cs
- WebPartConnectionCollection.cs
- DragDrop.cs
- JoinSymbol.cs
- Help.cs
- ItemList.cs
- EmptyStringExpandableObjectConverter.cs
- Types.cs
- ControlBuilderAttribute.cs
- GridViewColumnHeader.cs
- DetailsViewPagerRow.cs
- NodeFunctions.cs
- MarshalByRefObject.cs
- RbTree.cs
- itemelement.cs
- Form.cs
- _StreamFramer.cs
- GradientBrush.cs
- UnknownBitmapEncoder.cs
- SQLByteStorage.cs
- QuerySetOp.cs
- IndexerReference.cs
- XXXInfos.cs
- Pens.cs
- HttpListenerRequest.cs
- CompositeControl.cs
- XslCompiledTransform.cs
- SqlDataSourceEnumerator.cs
- FixedMaxHeap.cs
- Utils.cs
- WebCategoryAttribute.cs
- WebServiceHost.cs
- DbProviderFactory.cs
- SymLanguageVendor.cs
- AssemblyCache.cs
- ScriptingSectionGroup.cs
- Crypto.cs
- ActivityTypeDesigner.xaml.cs
- SymbolMethod.cs
- XamlGridLengthSerializer.cs
- MatrixAnimationBase.cs
- DBConnection.cs
- LabelAutomationPeer.cs
- ScaleTransform.cs
- EntityWrapperFactory.cs
- XamlStream.cs
- DispatcherSynchronizationContext.cs
- PinnedBufferMemoryStream.cs
- DataGridTextBox.cs
- PathGeometry.cs
- ToolStripItemCollection.cs
- IDispatchConstantAttribute.cs
- ItemsPresenter.cs
- WindowsAltTab.cs
- AsyncDataRequest.cs
- UnsafeNativeMethods.cs
- ReliableSession.cs
- Command.cs
- ServiceDiscoveryBehavior.cs
- ContextStaticAttribute.cs
- RuntimeCompatibilityAttribute.cs
- Base64Decoder.cs
- path.cs
- FixedSOMFixedBlock.cs
- XslException.cs
- Validator.cs
- CodeTypeReferenceCollection.cs
- EdmMember.cs
- ContravarianceAdapter.cs
- MSHTMLHost.cs
- ListBindableAttribute.cs
- FaultCallbackWrapper.cs
- TextClipboardData.cs
- SplashScreenNativeMethods.cs
- XslException.cs
- PostBackOptions.cs
- GifBitmapEncoder.cs
- GridSplitterAutomationPeer.cs
- _DigestClient.cs
- Options.cs
- rsa.cs
- Choices.cs
- SchemaImporter.cs
- VectorKeyFrameCollection.cs
- Header.cs
- PropertyEntry.cs
- PeerSecurityHelpers.cs
- InvalidBodyAccessException.cs
- Configuration.cs
- VirtualizingPanel.cs