[PlatformSpecific(TestPlatforms.Windows)] // ThreadPoolBoundHandle.BindHandle is not supported on Unix public unsafe void AllocateNativeOverlapped_PreAllocated_WhenAlreadyAllocated_ThrowsArgumentException(bool useUnsafe) { using (ThreadPoolBoundHandle handle = CreateThreadPoolBoundHandle()) { using PreAllocatedOverlapped preAlloc = useUnsafe ? PreAllocatedOverlapped.UnsafeCreate(delegate { }, null, null) : new PreAllocatedOverlapped(delegate { }, null, null); NativeOverlapped *overlapped = handle.AllocateNativeOverlapped(preAlloc); AssertExtensions.Throws <ArgumentException>("preAllocated", () => handle.AllocateNativeOverlapped(preAlloc)); handle.FreeNativeOverlapped(overlapped); } }
public unsafe void AllocateNativeOverlapped_ObjectArrayWithNonBlittableTypeAsPinData_Throws() { object[] array = new object[] { new NonBlittableType() { s = "foo" }, new byte[5], }; using (ThreadPoolBoundHandle handle = CreateThreadPoolBoundHandle()) { Assert.Throws <ArgumentException>(() => handle.AllocateNativeOverlapped((_, __, ___) => { }, new object(), array)); } }
[PlatformSpecific(TestPlatforms.Windows)] // ThreadPoolBoundHandle.BindHandle is not supported on Unix public unsafe void AllocateNativeOverlapped_ReturnedNativeOverlapped_AllFieldsZero() { using (ThreadPoolBoundHandle handle = CreateThreadPoolBoundHandle()) { NativeOverlapped *overlapped = handle.AllocateNativeOverlapped((_, __, ___) => { }, new object(), new byte[256]); Assert.Equal(IntPtr.Zero, overlapped->InternalLow); Assert.Equal(IntPtr.Zero, overlapped->InternalHigh); Assert.Equal(0, overlapped->OffsetLow); Assert.Equal(0, overlapped->OffsetHigh); Assert.Equal(IntPtr.Zero, overlapped->EventHandle); handle.FreeNativeOverlapped(overlapped); } }
[PlatformSpecific(TestPlatforms.Windows)] // ThreadPoolBoundHandle.BindHandle is not supported on Unix public unsafe void FlowsAsyncLocalsToCallback(bool shouldFlow) { // Makes sure that we flow async locals to callback const int DATA_SIZE = 2; SafeHandle handle = HandleFactory.CreateAsyncFileHandleForWrite(Path.Combine(TestDirectory, @"AsyncLocal.tmp")); ThreadPoolBoundHandle boundHandle = ThreadPoolBoundHandle.BindHandle(handle); OverlappedContext context = new OverlappedContext(); byte[] data = new byte[DATA_SIZE]; AsyncLocal <int> asyncLocal = new AsyncLocal <int>(); asyncLocal.Value = 10; int?result = null; IOCompletionCallback callback = (_, __, ___) => { result = asyncLocal.Value; OnOverlappedOperationCompleted(_, __, ___); }; NativeOverlapped *overlapped = shouldFlow ? boundHandle.AllocateNativeOverlapped(callback, context, data) : boundHandle.UnsafeAllocateNativeOverlapped(callback, context, data); fixed(byte *p = data) { int retval = DllImport.WriteFile(boundHandle.Handle, p, DATA_SIZE, IntPtr.Zero, overlapped); if (retval == 0) { Assert.Equal(DllImport.ERROR_IO_PENDING, Marshal.GetLastPInvokeError()); } // Wait for overlapped operation to complete context.Event.WaitOne(); } boundHandle.FreeNativeOverlapped(overlapped); boundHandle.Dispose(); handle.Dispose(); Assert.Equal( shouldFlow ? 10 : 0, result); }
// When doing IO asynchronously (i.e. _isAsync==true), this callback is // called by a free thread in the threadpool when the IO operation // completes. internal static void IOCallback(uint errorCode, uint numBytes, NativeOverlapped *pOverlapped) { // Extract the completion source from the overlapped. The state in the overlapped // will either be a FileStreamStrategy (in the case where the preallocated overlapped was used), // in which case the operation being completed is its _currentOverlappedOwner, or it'll // be directly the FileStreamCompletionSource that's completing (in the case where the preallocated // overlapped was already in use by another operation). object?state = ThreadPoolBoundHandle.GetNativeOverlappedState(pOverlapped); Debug.Assert(state is Net5CompatFileStreamStrategy || state is CompletionSource); CompletionSource completionSource = state switch { Net5CompatFileStreamStrategy strategy => strategy._currentOverlappedOwner !, // must be owned _ => (CompletionSource)state }; Debug.Assert(completionSource != null); Debug.Assert(completionSource._overlapped == pOverlapped, "Overlaps don't match"); // Handle reading from & writing to closed pipes. While I'm not sure // this is entirely necessary anymore, maybe it's possible for // an async read on a pipe to be issued and then the pipe is closed, // returning this error. This may very well be necessary. ulong packedResult; if (errorCode != 0 && errorCode != Interop.Errors.ERROR_BROKEN_PIPE && errorCode != Interop.Errors.ERROR_NO_DATA) { packedResult = ((ulong)TaskSourceCodes.ResultError | errorCode); } else { packedResult = ((ulong)TaskSourceCodes.ResultSuccess | numBytes); } // Stow the result so that other threads can observe it // And, if no other thread is registering cancellation, continue if (TaskSourceCodes.NoResult == Interlocked.Exchange(ref completionSource._result, (long)packedResult)) { // Successfully set the state, attempt to take back the callback if (Interlocked.Exchange(ref completionSource._result, TaskSourceCodes.CompletedCallback) != TaskSourceCodes.NoResult) { // Successfully got the callback, finish the callback completionSource.CompleteCallback(packedResult); } // else: Some other thread stole the result, so now it is responsible to finish the callback } // else: Some other thread is registering a cancellation, so it *must* finish the callback }
[PlatformSpecific(TestPlatforms.Windows)] // ThreadPoolBoundHandle.BindHandle is not supported on Unix public unsafe void GetNativeOverlappedState_WhenUnderlyingStateIsNull_ReturnsNull() { using (SafeHandle handle = HandleFactory.CreateAsyncFileHandleForWrite(GetTestFilePath())) { using (ThreadPoolBoundHandle boundHandle = ThreadPoolBoundHandle.BindHandle(handle)) { NativeOverlapped *overlapped = boundHandle.AllocateNativeOverlapped((_, __, ___) => { }, (object)null, new byte[0]); object result = ThreadPoolBoundHandle.GetNativeOverlappedState(overlapped); Assert.Null(result); boundHandle.FreeNativeOverlapped(overlapped); } } }
// Using RunContinuationsAsynchronously for compat reasons (old API used ThreadPool.QueueUserWorkItem for continuations) protected PipeCompletionSource(ThreadPoolBoundHandle handle, CancellationToken cancellationToken, object pinData) : base(TaskCreationOptions.RunContinuationsAsynchronously) { Debug.Assert(handle != null, "handle is null"); _threadPoolBinding = handle; _cancellationToken = cancellationToken; _state = NoResult; _overlapped = _threadPoolBinding.AllocateNativeOverlapped((errorCode, numBytes, pOverlapped) => { var completionSource = (PipeCompletionSource <TResult>)ThreadPoolBoundHandle.GetNativeOverlappedState(pOverlapped); Debug.Assert(completionSource.Overlapped == pOverlapped); completionSource.AsyncCallback(errorCode, numBytes); }, this, pinData); }
// Using RunContinuationsAsynchronously for compat reasons (old API used ThreadPool.QueueUserWorkItem for continuations) protected PipeCompletionSource(ThreadPoolBoundHandle handle, ReadOnlyMemory <byte> bufferToPin) : base(TaskCreationOptions.RunContinuationsAsynchronously) { Debug.Assert(handle != null, "handle is null"); _threadPoolBinding = handle; _state = NoResult; _pinnedMemory = bufferToPin.Pin(); _overlapped = _threadPoolBinding.AllocateNativeOverlapped((errorCode, numBytes, pOverlapped) => { var completionSource = (PipeCompletionSource <TResult>)ThreadPoolBoundHandle.GetNativeOverlappedState(pOverlapped); Debug.Assert(completionSource.Overlapped == pOverlapped); completionSource.AsyncCallback(errorCode, numBytes); }, this, null); }
public unsafe void AllocateNativeOverlapped_PreAllocated_WhenAlreadyAllocated_ThrowsArgumentException() { using (ThreadPoolBoundHandle handle = CreateThreadPoolBoundHandle()) { using (PreAllocatedOverlapped preAlloc = new PreAllocatedOverlapped(delegate { }, null, null)) { NativeOverlapped *overlapped = handle.AllocateNativeOverlapped(preAlloc); Assert.Throws <ArgumentException>(() => { handle.AllocateNativeOverlapped(preAlloc); }); handle.FreeNativeOverlapped(overlapped); } } }
[PlatformSpecific(TestPlatforms.Windows)] // ThreadPoolBoundHandle.BindHandle is not supported on Unix public unsafe void FreeNativeOverlapped_WithWrongHandle_ThrowsArgumentException() { using (ThreadPoolBoundHandle handle = CreateThreadPoolBoundHandle()) { NativeOverlapped *overlapped = handle.AllocateNativeOverlapped((_, __, ___) => { }, (object)null, (byte[])null); using (ThreadPoolBoundHandle handle2 = CreateThreadPoolBoundHandle()) { Assert.Throws <ArgumentException>(() => { handle2.FreeNativeOverlapped(overlapped); }); } handle.FreeNativeOverlapped(overlapped); } }
// Win32 file channel impl // TODO: Other platforms public unsafe void OpenReadFile(string path) { var fileHandle = CreateFile(path, FileAccess.Read, FileShare.Read, IntPtr.Zero, FileMode.Open, EFileAttributes.Overlapped, IntPtr.Zero); var handle = ThreadPoolBoundHandle.BindHandle(fileHandle); var readOperation = new ReadOperation { Channel = _channel, FileHandle = fileHandle, Handle = handle, IOCallback = IOCallback }; _channel.OnStartReading(readOperation.Read); _channel.OnDispose(fileHandle.Dispose); }
internal RequestQueue(UrlGroup urlGroup) { _urlGroup = urlGroup; var queueName = "IISConsole"; HttpRequestQueueV2Handle requestQueueHandle = null; var statusCode = HttpApi.HttpCreateRequestQueue( HttpApi.Version, queueName, null, HttpApiTypes.HTTP_CREATE_REQUEST_QUEUE_FLAGS.HTTP_CREATE_REQUEST_QUEUE_FLAG_CONTROLLER, out requestQueueHandle); if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) { throw new HttpSysException((int)statusCode); } Handle = requestQueueHandle; BoundHandle = ThreadPoolBoundHandle.BindHandle(Handle); }
public unsafe void GetNativeOverlappedState_WhenUnderlyingStateIsObject_ReturnsObject() { object context = new object(); using (SafeHandle handle = HandleFactory.CreateAsyncFileHandleForWrite()) { using (ThreadPoolBoundHandle boundHandle = ThreadPoolBoundHandle.BindHandle(handle)) { NativeOverlapped *overlapped = boundHandle.AllocateNativeOverlapped((_, __, ___) => { }, context, new byte[0]); object result = ThreadPoolBoundHandle.GetNativeOverlappedState(overlapped); Assert.Same(context, result); boundHandle.FreeNativeOverlapped(overlapped); } } }
// Binds the Socket Win32 Handle to the ThreadPool's CompletionPort. public ThreadPoolBoundHandle GetOrAllocateThreadPoolBoundHandle() { if (_released) { // Keep the exception message pointing at the external type. throw new ObjectDisposedException(typeof(Socket).FullName); } // Check to see if the socket native _handle is already // bound to the ThreadPool's completion port. if (_iocpBoundHandle == null) { lock (_iocpBindingLock) { if (_iocpBoundHandle == null) { // Bind the socket native _handle to the ThreadPool. if (GlobalLog.IsEnabled) { GlobalLog.Print("SafeCloseSocket#" + LoggingHash.HashString(this) + "::BindToCompletionPort() calling ThreadPool.BindHandle()"); } try { // The handle (this) may have been already released: // E.g.: The socket has been disposed in the main thread. A completion callback may // attempt starting another operation. _iocpBoundHandle = ThreadPoolBoundHandle.BindHandle(this); } catch (Exception exception) { if (ExceptionCheck.IsFatal(exception)) { throw; } CloseAsIs(); throw; } } } } return(_iocpBoundHandle); }
[PlatformSpecific(TestPlatforms.Windows)] // ThreadPoolBoundHandle.BindHandle is not supported on Unix public unsafe void AllocateNativeOverlapped_BlittableTypeAsPinData_DoesNotThrow() { using (ThreadPoolBoundHandle handle = CreateThreadPoolBoundHandle()) { NativeOverlapped *result = handle.AllocateNativeOverlapped((_, __, ___) => { }, new object(), new BlittableType() { i = 42 }); Assert.True(result != null); handle.FreeNativeOverlapped(result); result = handle.UnsafeAllocateNativeOverlapped((_, __, ___) => { }, new object(), new BlittableType() { i = 42 }); Assert.True(result != null); handle.FreeNativeOverlapped(result); } }
public unsafe void AllocateNativeOverlapped_ObjectArrayAsPinData_DoesNotThrow() { object[] array = new object[] { new BlittableType() { i = 1 }, new byte[5], }; using (ThreadPoolBoundHandle handle = CreateThreadPoolBoundHandle()) { NativeOverlapped *result = handle.AllocateNativeOverlapped((_, __, ___) => { }, new object(), array); Assert.True(result != null); handle.FreeNativeOverlapped(result); } }
// Using RunContinuationsAsynchronously for compat reasons (old API used Task.Factory.StartNew for continuations) internal FileStreamCompletionSource(int numBufferedBytes, byte[] bytes, ThreadPoolBoundHandle handle, CancellationToken cancellationToken) : base(TaskCreationOptions.RunContinuationsAsynchronously) { _numBufferedBytes = numBufferedBytes; _handle = handle; _result = NoResult; _cancellationToken = cancellationToken; // Create a managed overlapped class // We will set the file offsets later var ioCallback = s_IOCallback; // cached static delegate; delay initialized due to it being SecurityCritical if (ioCallback == null) { s_IOCallback = ioCallback = new IOCompletionCallback(AsyncFSCallback); } _overlapped = handle.AllocateNativeOverlapped(ioCallback, this, bytes); Debug.Assert(_overlapped != null, "Did Overlapped.Pack or Overlapped.UnsafePack just return a null?"); }
private Interop.HttpApi.HTTP_REQUEST *Allocate(ThreadPoolBoundHandle boundHandle, uint size) { uint newSize = size != 0 ? size : RequestBuffer == null ? 4096 : Size; if (_nativeOverlapped != null && newSize != RequestBuffer.Length) { NativeOverlapped *nativeOverlapped = _nativeOverlapped; _nativeOverlapped = null; _boundHandle.FreeNativeOverlapped(nativeOverlapped); } if (_nativeOverlapped == null) { SetBuffer(checked ((int)newSize)); _boundHandle = boundHandle; _nativeOverlapped = boundHandle.AllocateNativeOverlapped(ListenerAsyncResult.IOCallback, state: _result, pinData: RequestBuffer); return((Interop.HttpApi.HTTP_REQUEST *)Marshal.UnsafeAddrOfPinnedArrayElement(RequestBuffer, 0)); } return(RequestBlob); }
[PlatformSpecific(TestPlatforms.Windows)] // ThreadPoolBoundHandle.BindHandle is not supported on Unix public unsafe void GetNativeOverlappedState_WhenUnderlyingStateIsIAsyncResult_ReturnsIAsyncResult() { // CoreCLR/Desktop CLR version of overlapped sits on top of Overlapped class // and treats IAsyncResult specially, which is why we special case this case. AsyncResult context = new AsyncResult(); using (SafeHandle handle = HandleFactory.CreateAsyncFileHandleForWrite(GetTestFilePath())) { using (ThreadPoolBoundHandle boundHandle = ThreadPoolBoundHandle.BindHandle(handle)) { NativeOverlapped *overlapped = boundHandle.AllocateNativeOverlapped((_, __, ___) => { }, context, new byte[0]); object result = ThreadPoolBoundHandle.GetNativeOverlappedState(overlapped); Assert.Same(context, result); boundHandle.FreeNativeOverlapped(overlapped); } } }
private void FreeNativeOverlapped() { // Do not call free during AppDomain shutdown, there may be an outstanding operation. // Overlapped will take care calling free when the native callback completes. IntPtr oldHandle = Interlocked.Exchange(ref handle, IntPtr.Zero); if (oldHandle != IntPtr.Zero && !Environment.HasShutdownStarted) { unsafe { Debug.Assert(_socketHandle != null, "_socketHandle is null."); ThreadPoolBoundHandle boundHandle = _socketHandle.IOCPBoundHandle; Debug.Assert(boundHandle != null, "SafeNativeOverlapped::FreeNativeOverlapped - boundHandle is null"); // FreeNativeOverlapped will be called even if boundHandle was previously disposed. boundHandle?.FreeNativeOverlapped((NativeOverlapped *)oldHandle); } } }
// Using RunContinuationsAsynchronously for compat reasons (old API used ThreadPool.QueueUserWorkItem for continuations) internal ConnectionCompletionSource(NamedPipeServerStream server, CancellationToken cancellationToken) : base(TaskCreationOptions.RunContinuationsAsynchronously) { Debug.Assert(server != null, "server is null"); Debug.Assert(server._threadPoolBinding != null, "server._threadPoolBinding is null"); _threadPoolBinding = server._threadPoolBinding; _serverStream = server; _cancellationToken = cancellationToken; _overlapped = _threadPoolBinding.AllocateNativeOverlapped((errorCode, numBytes, pOverlapped) => { var completionSource = (ConnectionCompletionSource)ThreadPoolBoundHandle.GetNativeOverlappedState(pOverlapped); Debug.Assert(completionSource.Overlapped == pOverlapped); completionSource.AsyncCallback(errorCode, numBytes); }, this, null); _state = NoResult; }
public unsafe void AllocateNativeOverlapped_PossibleReusedReturnedNativeOverlapped_OffsetLowAndOffsetHighSetToZero() { // The CLR reuses NativeOverlapped underneath, check to make sure that they reset fields back to zero using (ThreadPoolBoundHandle handle = CreateThreadPoolBoundHandle()) { NativeOverlapped *overlapped = handle.AllocateNativeOverlapped((_, __, ___) => { }, new object(), new byte[256]); overlapped->OffsetHigh = 1; overlapped->OffsetLow = 1; handle.FreeNativeOverlapped(overlapped); overlapped = handle.AllocateNativeOverlapped((errorCode, numBytes, overlap) => { }, new object(), new byte[256]); Assert.Equal(IntPtr.Zero, overlapped->InternalLow); Assert.Equal(IntPtr.Zero, overlapped->InternalHigh); Assert.Equal(0, overlapped->OffsetLow); Assert.Equal(0, overlapped->OffsetHigh); Assert.Equal(IntPtr.Zero, overlapped->EventHandle); handle.FreeNativeOverlapped(overlapped); } }
public unsafe static void IOCallback(uint errorCode, uint numBytes, NativeOverlapped *pOverlapped) { var state = ThreadPoolBoundHandle.GetNativeOverlappedState(pOverlapped); var operation = (ReadOperation)state; operation.Offset += (int)numBytes; var iterator = operation.Iterator.Value; iterator.UpdateEnd((int)numBytes); operation.Channel.EndWriteAsync(iterator); if (numBytes == 0) { operation.Channel.CompleteWriting(); } else { operation.Read(); } }
private void StartRaisingEvents() { // If we're attached, don't do anything. if (!IsHandleInvalid) { return; } // Create handle to directory being monitored _directoryHandle = NativeMethods.CreateFile(_directory, // Directory name UnsafeNativeMethods.FILE_LIST_DIRECTORY, // access (read-write) mode UnsafeNativeMethods.FILE_SHARE_READ | UnsafeNativeMethods.FILE_SHARE_DELETE | UnsafeNativeMethods.FILE_SHARE_WRITE, // share mode null, // security descriptor UnsafeNativeMethods.OPEN_EXISTING, // how to create UnsafeNativeMethods.FILE_FLAG_BACKUP_SEMANTICS | UnsafeNativeMethods.FILE_FLAG_OVERLAPPED, // file attributes new SafeFileHandle(IntPtr.Zero, false) // file with attributes to copy ); if (IsHandleInvalid) { throw new FileNotFoundException(SR.Format(SR.FSW_IOError, _directory)); } _stopListening = false; // Start ignoring all events that were initiated before this. Interlocked.Increment(ref _currentSession); // Attach handle to thread pool _threadPoolBinding = ThreadPoolBoundHandle.BindHandle(_directoryHandle); _enabled = true; // Setup IO completion port Monitor(null); }
public unsafe static void IOCallback(uint errorCode, uint numBytes, NativeOverlapped *pOverlapped) { var state = ThreadPoolBoundHandle.GetNativeOverlappedState(pOverlapped); var operation = (ReadOperation)state; operation.ThreadPoolBoundHandle.FreeNativeOverlapped(operation.Overlapped); operation.Offset += (int)numBytes; var buffer = operation.BoxedBuffer.Value; buffer.CommitBytes((int)numBytes); operation.Channel.WriteAsync(buffer); if (numBytes == 0) { operation.Channel.CompleteWriting(); } else { operation.Read(); } }
// Win32 file channel impl // TODO: Other platforms public unsafe void OpenReadFile(string path) { var fileHandle = CreateFile(path, FileAccess.Read, FileShare.Read, IntPtr.Zero, FileMode.Open, EFileAttributes.Overlapped, IntPtr.Zero); var handle = ThreadPoolBoundHandle.BindHandle(fileHandle); var readOperation = new ReadOperation { Channel = _channel, FileHandle = fileHandle, ThreadPoolBoundHandle = handle, IOCallback = IOCallback }; var overlapped = new PreAllocatedOverlapped(IOCallback, readOperation, null); readOperation.PreAllocatedOverlapped = overlapped; _channel.ReadingStarted.ContinueWith((t, state) => { ((ReadOperation)state).Read(); }, readOperation); }
// Win32 file impl // TODO: Other platforms public unsafe void OpenReadFile(string path) { var fileHandle = CreateFile(path, FileAccess.Read, FileShare.Read, IntPtr.Zero, FileMode.Open, EFileAttributes.Overlapped, IntPtr.Zero); var handle = ThreadPoolBoundHandle.BindHandle(fileHandle); var readOperation = new ReadOperation { Writer = _writer, FileHandle = fileHandle, ThreadPoolBoundHandle = handle, IOCallback = IOCallback }; var overlapped = new PreAllocatedOverlapped(IOCallback, readOperation, null); readOperation.PreAllocatedOverlapped = overlapped; Task.Factory.StartNew(state => { ((ReadOperation)state).Read(); }, readOperation); }
private Interop.HttpApi.HTTP_REQUEST *Allocate(ThreadPoolBoundHandle boundHandle, uint size) { uint newSize = size != 0 ? size : RequestBuffer == IntPtr.Zero ? 4096 : Size; if (_nativeOverlapped != null) { #if DEBUG DebugRefCountReleaseNativeOverlapped(); #endif NativeOverlapped *nativeOverlapped = _nativeOverlapped; _nativeOverlapped = null; _boundHandle !.FreeNativeOverlapped(nativeOverlapped); } #if DEBUG DebugRefCountAllocNativeOverlapped(); #endif SetBuffer(checked ((int)newSize)); _boundHandle = boundHandle; _nativeOverlapped = boundHandle.AllocateNativeOverlapped(ListenerAsyncResult.IOCallback, state: _result, pinData: RequestBuffer); return((Interop.HttpApi.HTTP_REQUEST *)RequestBuffer.ToPointer()); }
public void BindHandle_ValidHandle_ThrowsPlatformNotSupportedException() { Assert.Throws <PlatformNotSupportedException>(() => ThreadPoolBoundHandle.BindHandle(new Win32Handle(new IntPtr(1)))); }
private static unsafe void Callback(uint errorCode, uint numBytes, NativeOverlapped *nativeOverlapped) { var asyncResult = (RequestStreamAsyncResult)ThreadPoolBoundHandle.GetNativeOverlappedState(nativeOverlapped); IOCompleted(asyncResult, errorCode, numBytes); }