From 532698abd3b8b8bc471d24291b930c64af50ed59 Mon Sep 17 00:00:00 2001 From: Chris R Date: Tue, 2 Jun 2015 10:16:15 -0700 Subject: [PATCH] React to CoreCLR Overlapped changes. --- .../AsyncAcceptContext.cs | 6 +- .../NativeInterop/SafeNativeOverlapped.cs | 21 ++- .../Overlapped/DeferredDisposableLifetime.cs | 85 +++++++++++ .../Overlapped/IDeferredDisposable.cs | 10 ++ .../Overlapped/PreAllocatedOverlapped.cs | 51 +++++++ .../Overlapped/ThreadPoolBoundHandle.cs | 143 ++++++++++++++++++ .../ThreadPoolBoundHandleOverlapped.cs | 38 +++++ .../RequestProcessing/ClientCertLoader.cs | 10 +- .../RequestProcessing/NativeRequestContext.cs | 9 +- .../RequestProcessing/RequestStream.cs | 5 + .../RequestStreamAsyncResult.cs | 10 +- .../RequestProcessing/ResponseStream.cs | 5 + .../ResponseStreamAsyncResult.cs | 22 +-- src/Microsoft.Net.Http.Server/WebListener.cs | 17 ++- .../NativeInterop/SafeNativeOverlapped.cs | 97 ------------ src/Microsoft.Net.WebSockets/project.json | 1 - 16 files changed, 385 insertions(+), 145 deletions(-) create mode 100644 src/Microsoft.Net.Http.Server/Overlapped/DeferredDisposableLifetime.cs create mode 100644 src/Microsoft.Net.Http.Server/Overlapped/IDeferredDisposable.cs create mode 100644 src/Microsoft.Net.Http.Server/Overlapped/PreAllocatedOverlapped.cs create mode 100644 src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandle.cs create mode 100644 src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandleOverlapped.cs delete mode 100644 src/Microsoft.Net.WebSockets/NativeInterop/SafeNativeOverlapped.cs diff --git a/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs b/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs index 08edc569ac..a03a65a047 100644 --- a/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs +++ b/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs @@ -60,7 +60,7 @@ namespace Microsoft.Net.Http.Server } } - private WebListener Server + internal WebListener Server { get { @@ -152,9 +152,7 @@ namespace Microsoft.Net.Http.Server private static unsafe void IOWaitCallback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped) { // take the ListenerAsyncResult object from the state - Overlapped callbackOverlapped = Overlapped.Unpack(nativeOverlapped); - AsyncAcceptContext asyncResult = (AsyncAcceptContext)callbackOverlapped.AsyncResult; - + var asyncResult = (AsyncAcceptContext)ThreadPoolBoundHandle.GetNativeOverlappedState(nativeOverlapped); IOCompleted(asyncResult, errorCode, numBytes); } diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/SafeNativeOverlapped.cs b/src/Microsoft.Net.Http.Server/NativeInterop/SafeNativeOverlapped.cs index cf8d1f38e4..e1c2709a3e 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/SafeNativeOverlapped.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/SafeNativeOverlapped.cs @@ -30,21 +30,18 @@ namespace Microsoft.Net.Http.Server internal class SafeNativeOverlapped : SafeHandle { internal static readonly SafeNativeOverlapped Zero = new SafeNativeOverlapped(); + private ThreadPoolBoundHandle _boundHandle; internal SafeNativeOverlapped() - : this(IntPtr.Zero) - { - } - - internal unsafe SafeNativeOverlapped(NativeOverlapped* handle) - : this((IntPtr)handle) - { - } - - internal SafeNativeOverlapped(IntPtr handle) : base(IntPtr.Zero, true) { - SetHandle(handle); + } + + internal unsafe SafeNativeOverlapped(ThreadPoolBoundHandle boundHandle, NativeOverlapped* handle) + : base(IntPtr.Zero, true) + { + SetHandle((IntPtr)handle); + _boundHandle = boundHandle; } public override bool IsInvalid @@ -76,7 +73,7 @@ namespace Microsoft.Net.Http.Server { unsafe { - Overlapped.Free((NativeOverlapped*)oldHandle); + _boundHandle.FreeNativeOverlapped((NativeOverlapped*)oldHandle); } } return true; diff --git a/src/Microsoft.Net.Http.Server/Overlapped/DeferredDisposableLifetime.cs b/src/Microsoft.Net.Http.Server/Overlapped/DeferredDisposableLifetime.cs new file mode 100644 index 0000000000..724741009a --- /dev/null +++ b/src/Microsoft.Net.Http.Server/Overlapped/DeferredDisposableLifetime.cs @@ -0,0 +1,85 @@ +#if !DNXCORE50 // TODO: Temp copy. Remove once we target net46. +using System; +namespace System.Threading +{ + internal struct DeferredDisposableLifetime where T : class, IDeferredDisposable + { + private int _count; + public bool AddRef(T obj) + { + while (true) + { + int num = Volatile.Read(ref this._count); + if (num < 0) + { + break; + } + int num2 = checked(num + 1); + if (Interlocked.CompareExchange(ref this._count, num2, num) == num) + { + return true; + } + } + throw new ObjectDisposedException(typeof(T).ToString()); + } + public void Release(T obj) + { + int num2; + int num3; + while (true) + { + int num = Volatile.Read(ref this._count); + if (num > 0) + { + num2 = num - 1; + if (Interlocked.CompareExchange(ref this._count, num2, num) == num) + { + break; + } + } + else + { + num3 = num + 1; + if (Interlocked.CompareExchange(ref this._count, num3, num) == num) + { + goto Block_3; + } + } + } + if (num2 == 0) + { + obj.OnFinalRelease(false); + } + return; + Block_3: + if (num3 == -1) + { + obj.OnFinalRelease(true); + } + } + public void Dispose(T obj) + { + int num2; + while (true) + { + int num = Volatile.Read(ref this._count); + if (num < 0) + { + break; + } + num2 = -1 - num; + if (Interlocked.CompareExchange(ref this._count, num2, num) == num) + { + goto Block_1; + } + } + return; + Block_1: + if (num2 == -1) + { + obj.OnFinalRelease(true); + } + } + } +} +#endif \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/Overlapped/IDeferredDisposable.cs b/src/Microsoft.Net.Http.Server/Overlapped/IDeferredDisposable.cs new file mode 100644 index 0000000000..7b6395b588 --- /dev/null +++ b/src/Microsoft.Net.Http.Server/Overlapped/IDeferredDisposable.cs @@ -0,0 +1,10 @@ +#if !DNXCORE50 // TODO: Temp copy. Remove once we target net46. +using System; +namespace System.Threading +{ + internal interface IDeferredDisposable + { + void OnFinalRelease(bool disposed); + } +} +#endif \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/Overlapped/PreAllocatedOverlapped.cs b/src/Microsoft.Net.Http.Server/Overlapped/PreAllocatedOverlapped.cs new file mode 100644 index 0000000000..c4c7b468af --- /dev/null +++ b/src/Microsoft.Net.Http.Server/Overlapped/PreAllocatedOverlapped.cs @@ -0,0 +1,51 @@ +#if !DNXCORE50 // TODO: Temp copy. Remove once we target net46. +using System; +namespace System.Threading +{ + public sealed class PreAllocatedOverlapped : IDisposable, IDeferredDisposable + { + internal readonly ThreadPoolBoundHandleOverlapped _overlapped; + private DeferredDisposableLifetime _lifetime; + [CLSCompliant(false)] + public PreAllocatedOverlapped(IOCompletionCallback callback, object state, object pinData) + { + if (callback == null) + { + throw new ArgumentNullException("callback"); + } + this._overlapped = new ThreadPoolBoundHandleOverlapped(callback, state, pinData, this); + } + internal bool AddRef() + { + return this._lifetime.AddRef(this); + } + internal void Release() + { + this._lifetime.Release(this); + } + public void Dispose() + { + this._lifetime.Dispose(this); + GC.SuppressFinalize(this); + } + ~PreAllocatedOverlapped() + { + if (!Environment.HasShutdownStarted) + { + this.Dispose(); + } + } + unsafe void IDeferredDisposable.OnFinalRelease(bool disposed) + { + if (disposed) + { + Overlapped.Free(this._overlapped._nativeOverlapped); + return; + } + this._overlapped._boundHandle = null; + this._overlapped._completed = false; + *this._overlapped._nativeOverlapped = default(NativeOverlapped); + } + } +} +#endif \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandle.cs b/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandle.cs new file mode 100644 index 0000000000..2e3234c206 --- /dev/null +++ b/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandle.cs @@ -0,0 +1,143 @@ +#if !DNXCORE50 // TODO: Temp copy. Remove once we target net46. +using System; +using System.Runtime.InteropServices; +namespace System.Threading +{ + public sealed class ThreadPoolBoundHandle : IDisposable + { + private readonly SafeHandle _handle; + private bool _isDisposed; + public SafeHandle Handle + { + get + { + return this._handle; + } + } + private ThreadPoolBoundHandle(SafeHandle handle) + { + this._handle = handle; + } + public static ThreadPoolBoundHandle BindHandle(SafeHandle handle) + { + if (handle == null) + { + throw new ArgumentNullException("handle"); + } + if (handle.IsClosed || handle.IsInvalid) + { + throw new ArgumentException("Invalid Handle", "handle"); + } + try + { + ThreadPool.BindHandle(handle); + } + catch (Exception expr_38) + { + if (expr_38.HResult == -2147024890) + { + throw new ArgumentException("Invalid Handle", "handle"); + } + if (expr_38.HResult == -2147024809) + { + throw new ArgumentException("Already Bound", "handle"); + } + throw; + } + return new ThreadPoolBoundHandle(handle); + } + [CLSCompliant(false)] + public unsafe NativeOverlapped* AllocateNativeOverlapped(IOCompletionCallback callback, object state, object pinData) + { + if (callback == null) + { + throw new ArgumentNullException("callback"); + } + this.EnsureNotDisposed(); + return new ThreadPoolBoundHandleOverlapped(callback, state, pinData, null) + { + _boundHandle = this + }._nativeOverlapped; + } + [CLSCompliant(false)] + public unsafe NativeOverlapped* AllocateNativeOverlapped(PreAllocatedOverlapped preAllocated) + { + if (preAllocated == null) + { + throw new ArgumentNullException("preAllocated"); + } + this.EnsureNotDisposed(); + preAllocated.AddRef(); + NativeOverlapped* nativeOverlapped; + try + { + ThreadPoolBoundHandleOverlapped expr_21 = preAllocated._overlapped; + if (expr_21._boundHandle != null) + { + throw new ArgumentException("Already Allocated", "preAllocated"); + } + expr_21._boundHandle = this; + nativeOverlapped = expr_21._nativeOverlapped; + } + catch + { + preAllocated.Release(); + throw; + } + return nativeOverlapped; + } + [CLSCompliant(false)] + public unsafe void FreeNativeOverlapped(NativeOverlapped* overlapped) + { + if (overlapped == null) + { + throw new ArgumentNullException("overlapped"); + } + ThreadPoolBoundHandleOverlapped overlappedWrapper = ThreadPoolBoundHandle.GetOverlappedWrapper(overlapped, this); + if (overlappedWrapper._boundHandle != this) + { + throw new ArgumentException("Wrong bound handle", "overlapped"); + } + if (overlappedWrapper._preAllocated != null) + { + overlappedWrapper._preAllocated.Release(); + return; + } + Overlapped.Free(overlapped); + } + [CLSCompliant(false)] + public unsafe static object GetNativeOverlappedState(NativeOverlapped* overlapped) + { + if (overlapped == null) + { + throw new ArgumentNullException("overlapped"); + } + return ThreadPoolBoundHandle.GetOverlappedWrapper(overlapped, null)._userState; + } + private unsafe static ThreadPoolBoundHandleOverlapped GetOverlappedWrapper(NativeOverlapped* overlapped, ThreadPoolBoundHandle expectedBoundHandle) + { + ThreadPoolBoundHandleOverlapped result; + try + { + result = (ThreadPoolBoundHandleOverlapped)Overlapped.Unpack(overlapped); + } + catch (NullReferenceException ex) + { + throw new ArgumentException("Already freed", "overlapped", ex); + } + return result; + } + public void Dispose() + { + this._isDisposed = true; + } + private void EnsureNotDisposed() + { + if (this._isDisposed) + { + throw new ObjectDisposedException(base.GetType().ToString()); + } + } + } +} +#endif \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandleOverlapped.cs b/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandleOverlapped.cs new file mode 100644 index 0000000000..7020223dba --- /dev/null +++ b/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandleOverlapped.cs @@ -0,0 +1,38 @@ +#if !DNXCORE50 // TODO: Temp copy. Remove once we target net46. +using System; +namespace System.Threading +{ + internal sealed class ThreadPoolBoundHandleOverlapped : Overlapped + { + private readonly IOCompletionCallback _userCallback; + internal readonly object _userState; + internal PreAllocatedOverlapped _preAllocated; + internal unsafe NativeOverlapped* _nativeOverlapped; + internal ThreadPoolBoundHandle _boundHandle; + internal bool _completed; + public unsafe ThreadPoolBoundHandleOverlapped(IOCompletionCallback callback, object state, object pinData, PreAllocatedOverlapped preAllocated) + { + this._userCallback = callback; + this._userState = state; + this._preAllocated = preAllocated; + this._nativeOverlapped = base.Pack(new IOCompletionCallback(ThreadPoolBoundHandleOverlapped.CompletionCallback), pinData); + this._nativeOverlapped->OffsetLow = 0; + this._nativeOverlapped->OffsetHigh = 0; + } + private unsafe static void CompletionCallback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped) + { + ThreadPoolBoundHandleOverlapped expr_0B = (ThreadPoolBoundHandleOverlapped)Overlapped.Unpack(nativeOverlapped); + if (expr_0B._completed) + { + throw new InvalidOperationException("Native Overlapped reused"); + } + expr_0B._completed = true; + if (expr_0B._boundHandle == null) + { + throw new InvalidOperationException("Already freed"); + } + expr_0B._userCallback.Invoke(errorCode, numBytes, nativeOverlapped); + } + } +} +#endif \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs index 5e9d078df6..e859c97964 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs @@ -138,9 +138,9 @@ namespace Microsoft.Net.Http.Server return; } _backingBuffer = new byte[checked((int)size)]; - Overlapped overlapped = new Overlapped(); - overlapped.AsyncResult = this; - _overlapped = new SafeNativeOverlapped(overlapped.Pack(IOCallback, _backingBuffer)); + var boundHandle = RequestContext.Server.BoundHandle; + _overlapped = new SafeNativeOverlapped(boundHandle, + boundHandle.AllocateNativeOverlapped(IOCallback, this, _backingBuffer)); _memoryBlob = (UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO*)Marshal.UnsafeAddrOfPinnedArrayElement(_backingBuffer, 0); } @@ -315,9 +315,7 @@ namespace Microsoft.Net.Http.Server private static unsafe void WaitCallback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped) { - Overlapped callbackOverlapped = Overlapped.Unpack(nativeOverlapped); - ClientCertLoader asyncResult = (ClientCertLoader)callbackOverlapped.AsyncResult; - + var asyncResult = (ClientCertLoader)ThreadPoolBoundHandle.GetNativeOverlappedState(nativeOverlapped); IOCompleted(asyncResult, errorCode, numBytes); } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs index 61f81ebe8c..30ada89d29 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs @@ -161,7 +161,8 @@ namespace Microsoft.Net.Http.Server private UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* Allocate(uint size) { uint newSize = size != 0 ? size : RequestBuffer == null ? DefaultBufferSize : Size; - if (_nativeOverlapped != null && newSize != RequestBuffer.Length) + // We can't reuse overlapped objects + if (_nativeOverlapped != null) { SafeNativeOverlapped nativeOverlapped = _nativeOverlapped; _nativeOverlapped = null; @@ -170,9 +171,9 @@ namespace Microsoft.Net.Http.Server if (_nativeOverlapped == null) { SetBuffer(checked((int)newSize)); - Overlapped overlapped = new Overlapped(); - overlapped.AsyncResult = _acceptResult; - _nativeOverlapped = new SafeNativeOverlapped(overlapped.Pack(AsyncAcceptContext.IOCallback, RequestBuffer)); + var boundHandle = _acceptResult.Server.BoundHandle; + _nativeOverlapped = new SafeNativeOverlapped(boundHandle, + boundHandle.AllocateNativeOverlapped(AsyncAcceptContext.IOCallback, _acceptResult, RequestBuffer)); return (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST*)Marshal.UnsafeAddrOfPinnedArrayElement(RequestBuffer, 0); } return RequestBlob; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs index d32cb546be..1ef325a151 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs @@ -43,6 +43,11 @@ namespace Microsoft.Net.Http.Server _requestContext = httpContext; } + internal RequestContext RequestContext + { + get { return _requestContext; } + } + public override bool CanSeek { get diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs index 6976d21725..93ad2980bc 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs @@ -64,9 +64,9 @@ namespace Microsoft.Net.Http.Server : this(requestStream, userState, callback) { _dataAlreadyRead = dataAlreadyRead; - Overlapped overlapped = new Overlapped(); - overlapped.AsyncResult = this; - _overlapped = new SafeNativeOverlapped(overlapped.Pack(IOCallback, buffer)); + var boundHandle = requestStream.RequestContext.Server.BoundHandle; + _overlapped = new SafeNativeOverlapped(boundHandle, + boundHandle.AllocateNativeOverlapped(IOCallback, this, buffer)); _pinnedBuffer = (Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset)); _cancellationRegistration = cancellationRegistration; } @@ -126,9 +126,7 @@ namespace Microsoft.Net.Http.Server private static unsafe void Callback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped) { - Overlapped callbackOverlapped = Overlapped.Unpack(nativeOverlapped); - RequestStreamAsyncResult asyncResult = callbackOverlapped.AsyncResult as RequestStreamAsyncResult; - + var asyncResult = (RequestStreamAsyncResult)ThreadPoolBoundHandle.GetNativeOverlappedState(nativeOverlapped); IOCompleted(asyncResult, errorCode, numBytes); } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs index 2ce897c414..c7df4fdff7 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs @@ -47,6 +47,11 @@ namespace Microsoft.Net.Http.Server _requestContext = requestContext; } + internal RequestContext RequestContext + { + get { return _requestContext; } + } + public override bool CanSeek { get diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs index 16c2e2128c..95f09b4052 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs @@ -65,13 +65,13 @@ namespace Microsoft.Net.Http.Server { _sentHeaders = sentHeaders; _cancellationRegistration = cancellationRegistration; - Overlapped overlapped = new Overlapped(); - overlapped.AsyncResult = this; + var boundHandle = _responseStream.RequestContext.Server.BoundHandle; if (size == 0) { _dataChunks = null; - _overlapped = new SafeNativeOverlapped(overlapped.Pack(IOCallback, null)); + _overlapped = new SafeNativeOverlapped(boundHandle, + boundHandle.AllocateNativeOverlapped(IOCallback, this, null)); } else { @@ -114,7 +114,8 @@ namespace Microsoft.Net.Http.Server } // This call will pin needed memory - _overlapped = new SafeNativeOverlapped(overlapped.Pack(IOCallback, objectsToPin)); + _overlapped = new SafeNativeOverlapped(boundHandle, + boundHandle.AllocateNativeOverlapped(IOCallback, this, objectsToPin)); if (chunked) { @@ -136,8 +137,7 @@ namespace Microsoft.Net.Http.Server { _sentHeaders = sentHeaders; _cancellationRegistration = cancellationRegistration; - Overlapped overlapped = new Overlapped(); - overlapped.AsyncResult = this; + var boundHandle = ResponseStream.RequestContext.Server.BoundHandle; int bufferSize = 1024 * 64; // TODO: Validate buffer size choice. #if DNXCORE50 @@ -162,7 +162,8 @@ namespace Microsoft.Net.Http.Server if (size == 0 || (!size.HasValue && _fileStream.Length == 0)) { _dataChunks = null; - _overlapped = new SafeNativeOverlapped(overlapped.Pack(IOCallback, null)); + _overlapped = new SafeNativeOverlapped(boundHandle, + boundHandle.AllocateNativeOverlapped(IOCallback, this, null)); } else { @@ -206,7 +207,8 @@ namespace Microsoft.Net.Http.Server } // This call will pin needed memory - _overlapped = new SafeNativeOverlapped(overlapped.Pack(IOCallback, objectsToPin)); + _overlapped = new SafeNativeOverlapped(boundHandle, + boundHandle.AllocateNativeOverlapped(IOCallback, this, objectsToPin)); if (chunked) { @@ -318,9 +320,7 @@ namespace Microsoft.Net.Http.Server private static unsafe void Callback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped) { - Overlapped callbackOverlapped = Overlapped.Unpack(nativeOverlapped); - ResponseStreamAsyncResult asyncResult = callbackOverlapped.AsyncResult as ResponseStreamAsyncResult; - + var asyncResult = (ResponseStreamAsyncResult)ThreadPoolBoundHandle.GetNativeOverlappedState(nativeOverlapped); IOCompleted(asyncResult, errorCode, numBytes); } diff --git a/src/Microsoft.Net.Http.Server/WebListener.cs b/src/Microsoft.Net.Http.Server/WebListener.cs index 727001dc81..018058abe9 100644 --- a/src/Microsoft.Net.Http.Server/WebListener.cs +++ b/src/Microsoft.Net.Http.Server/WebListener.cs @@ -74,6 +74,7 @@ namespace Microsoft.Net.Http.Server private ILogger _logger; private SafeHandle _requestQueueHandle; + private ThreadPoolBoundHandle _boundHandle; private volatile State _state; // m_State is set only within lock blocks, but often read outside locks. private bool _ignoreWriteExceptions; @@ -141,6 +142,11 @@ namespace Microsoft.Net.Http.Server } } + internal ThreadPoolBoundHandle BoundHandle + { + get { return _boundHandle; } + } + internal ulong UrlGroupId { get { return _urlGroupId; } @@ -523,7 +529,7 @@ namespace Microsoft.Net.Http.Server } _requestQueueHandle = requestQueueHandle; - ThreadPool.BindHandle(_requestQueueHandle); + _boundHandle = ThreadPoolBoundHandle.BindHandle(_requestQueueHandle); } private unsafe void CloseRequestQueueHandle() @@ -532,6 +538,10 @@ namespace Microsoft.Net.Http.Server { _requestQueueHandle.Dispose(); } + if (_boundHandle != null) + { + _boundHandle.Dispose(); + } } /// @@ -667,11 +677,10 @@ namespace Microsoft.Net.Http.Server // Debug.WriteLine("Server: Registering connection for disconnect for connection ID: " + connectionId); // Create a nativeOverlapped callback so we can register for disconnect callback - var overlapped = new Overlapped(); var cts = new CancellationTokenSource(); SafeNativeOverlapped nativeOverlapped = null; - nativeOverlapped = new SafeNativeOverlapped(overlapped.UnsafePack( + nativeOverlapped = new SafeNativeOverlapped(_boundHandle, _boundHandle.AllocateNativeOverlapped( (errorCode, numBytes, overlappedPtr) => { // Debug.WriteLine("Server: http.sys disconnect callback fired for connection ID: " + connectionId); @@ -693,7 +702,7 @@ namespace Microsoft.Net.Http.Server cts.Dispose(); }, - null)); + null, null)); uint statusCode; try diff --git a/src/Microsoft.Net.WebSockets/NativeInterop/SafeNativeOverlapped.cs b/src/Microsoft.Net.WebSockets/NativeInterop/SafeNativeOverlapped.cs deleted file mode 100644 index b5501b0d38..0000000000 --- a/src/Microsoft.Net.WebSockets/NativeInterop/SafeNativeOverlapped.cs +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -using System; -using System.Runtime.InteropServices; -using System.Threading; - -namespace Microsoft.Net.WebSockets -{ - internal class SafeNativeOverlapped : SafeHandle - { - internal static readonly SafeNativeOverlapped Zero = new SafeNativeOverlapped(); - - internal SafeNativeOverlapped() - : this(IntPtr.Zero) - { - } - - internal unsafe SafeNativeOverlapped(NativeOverlapped* handle) - : this((IntPtr)handle) - { - } - - internal SafeNativeOverlapped(IntPtr handle) - : base(IntPtr.Zero, true) - { - SetHandle(handle); - } - - public override bool IsInvalid - { - get { return handle == IntPtr.Zero; } - } - - public void ReinitializeNativeOverlapped() - { - IntPtr handleSnapshot = handle; - - if (handleSnapshot != IntPtr.Zero) - { - unsafe - { - ((NativeOverlapped*)handleSnapshot)->InternalHigh = IntPtr.Zero; - ((NativeOverlapped*)handleSnapshot)->InternalLow = IntPtr.Zero; - ((NativeOverlapped*)handleSnapshot)->EventHandle = IntPtr.Zero; - } - } - } - - protected override bool ReleaseHandle() - { - IntPtr oldHandle = Interlocked.Exchange(ref handle, IntPtr.Zero); - // Do not call free durring AppDomain shutdown, there may be an outstanding operation. - // Overlapped will take care calling free when the native callback completes. - if (oldHandle != IntPtr.Zero && !HasShutdownStarted) - { - unsafe - { - Overlapped.Free((NativeOverlapped*)oldHandle); - } - } - return true; - } - - internal static bool HasShutdownStarted - { - get - { - return Environment.HasShutdownStarted -#if !DNXCORE50 - || AppDomain.CurrentDomain.IsFinalizingForUnload() -#endif - ; - } - } - } -} diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json index d78a9994f2..9c05f0f4b9 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets/project.json @@ -20,7 +20,6 @@ "System.Security.Cryptography.Hashing.Algorithms": "4.0.0-beta-*", "System.Text.Encoding.Extensions": "4.0.10-beta-*", "System.Threading": "4.0.10-beta-*", - "System.Threading.Overlapped": "4.0.0-beta-*", "System.Threading.Tasks": "4.0.10-beta-*", "System.Threading.Timer": "4.0.0-beta-*", "System.Threading.ThreadPool": "4.0.10-beta-*"