[PlatformSpecific(TestPlatforms.Windows)] // ThreadPoolBoundHandle.BindHandle is not supported on Unix public unsafe void AllocateNativeOverlapped_PreAllocated_ReusedReturnedNativeOverlapped_OffsetLowAndOffsetHighSetToZero(bool useUnsafe) { // The CLR reuses NativeOverlapped underneath, check to make sure that they reset fields back to zero using (ThreadPoolBoundHandle handle = CreateThreadPoolBoundHandle()) { PreAllocatedOverlapped preAlloc = useUnsafe ? PreAllocatedOverlapped.UnsafeCreate((_, __, ___) => { }, new object(), new byte[256]) : new PreAllocatedOverlapped((_, __, ___) => { }, new object(), new byte[256]); NativeOverlapped *overlapped = handle.AllocateNativeOverlapped(preAlloc); overlapped->OffsetHigh = 1; overlapped->OffsetLow = 1; handle.FreeNativeOverlapped(overlapped); overlapped = handle.AllocateNativeOverlapped(preAlloc); 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 MultipleOperationsOverSingleHandle() { const int DATA_SIZE = 2; SafeHandle handle = HandleFactory.CreateAsyncFileHandleForWrite(Path.Combine(TestDirectory, @"MultipleOperationsOverSingleHandle.tmp")); ThreadPoolBoundHandle boundHandle = ThreadPoolBoundHandle.BindHandle(handle); OverlappedContext result1 = new OverlappedContext(); OverlappedContext result2 = new OverlappedContext(); byte[] data1 = new byte[DATA_SIZE]; data1[0] = (byte)'A'; data1[1] = (byte)'B'; byte[] data2 = new byte[DATA_SIZE]; data2[0] = (byte)'C'; data2[1] = (byte)'D'; NativeOverlapped *overlapped1 = boundHandle.AllocateNativeOverlapped(OnOverlappedOperationCompleted, result1, data1); NativeOverlapped *overlapped2 = boundHandle.AllocateNativeOverlapped(OnOverlappedOperationCompleted, result2, data2); fixed(byte *p1 = data1, p2 = data2) { int retval = DllImport.WriteFile(boundHandle.Handle, p1, DATA_SIZE, IntPtr.Zero, overlapped1); if (retval == 0) { Assert.Equal(DllImport.ERROR_IO_PENDING, Marshal.GetLastWin32Error()); } // Start the offset after the above write, so that it doesn't overwrite the previous write overlapped2->OffsetLow = DATA_SIZE; retval = DllImport.WriteFile(boundHandle.Handle, p2, DATA_SIZE, IntPtr.Zero, overlapped2); if (retval == 0) { Assert.Equal(DllImport.ERROR_IO_PENDING, Marshal.GetLastWin32Error()); } // Wait for overlapped operations to complete WaitHandle.WaitAll(new WaitHandle[] { result1.Event, result2.Event }); } boundHandle.FreeNativeOverlapped(overlapped1); boundHandle.FreeNativeOverlapped(overlapped2); boundHandle.Dispose(); handle.Dispose(); Assert.Equal(0, result1.ErrorCode); Assert.Equal(0, result2.ErrorCode); Assert.Equal(DATA_SIZE, result1.BytesWritten); Assert.Equal(DATA_SIZE, result2.BytesWritten); }
[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); } }
[PlatformSpecific(TestPlatforms.Windows)] // ThreadPoolBoundHandle.BindHandle is not supported on Unix public unsafe void AllocateNativeOverlapped_PreAllocated_ThrowsArgumentNullException() { using (ThreadPoolBoundHandle handle = CreateThreadPoolBoundHandle()) { AssertExtensions.Throws <ArgumentNullException>("preAllocated", () => handle.AllocateNativeOverlapped((PreAllocatedOverlapped)null)); } }
public unsafe void Read() { var buffer = Writer.GetMemory(2048); fixed(byte *source = &MemoryMarshal.GetReference(buffer.Span)) { var count = buffer.Length; var overlapped = ThreadPoolBoundHandle.AllocateNativeOverlapped(PreAllocatedOverlapped); overlapped->OffsetLow = Offset; Overlapped = overlapped; int r = ReadFile(FileHandle, (IntPtr)source, count, IntPtr.Zero, overlapped); // TODO: Error handling // 997 int hr = Marshal.GetLastWin32Error(); if (hr != 997) { Writer.Complete(Marshal.GetExceptionForHR(hr)); } } }
private Interop.HttpApi.HTTP_REQUEST *Allocate(ThreadPoolBoundHandle boundHandle, uint size) { uint newSize = size != 0 ? size : RequestBuffer == null ? 4096 : Size; if (_nativeOverlapped != null) { #if DEBUG DebugRefCountReleaseNativeOverlapped(); #endif NativeOverlapped *nativeOverlapped = _nativeOverlapped; _nativeOverlapped = null; _boundHandle.FreeNativeOverlapped(nativeOverlapped); } if (_nativeOverlapped == null) { #if DEBUG DebugRefCountAllocNativeOverlapped(); #endif 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); }
public unsafe void Read() { var buffer = Writer.GetMemory(_bufferSize); var count = buffer.Length; int r; var overlapped = ThreadPoolBoundHandle.AllocateNativeOverlapped(PreAllocatedOverlapped); overlapped->OffsetLow = Offset; Overlapped = overlapped; fixed(byte *source = &MemoryMarshal.GetReference(buffer.Span)) { r = ReadFile(FileHandle, (IntPtr)source, count, IntPtr.Zero, overlapped); } // TODO: Error handling if (r == 0) { } // 997 // Note The GetLastError code ERROR_IO_PENDING is not a failure; it designates the read operation // is pending completion asynchronously. For more information, see Remarks. // https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-readfile int hr = Marshal.GetLastWin32Error(); if (hr != 997) { Writer.Complete(Marshal.GetExceptionForHR(hr)); } }
[PlatformSpecific(TestPlatforms.Windows)] // ThreadPoolBoundHandle.BindHandle is not supported on Unix public unsafe void SingleOperationOverSingleHandle() { const int DATA_SIZE = 2; SafeHandle handle = HandleFactory.CreateAsyncFileHandleForWrite(Path.Combine(TestDirectory, @"SingleOverlappedOverSingleHandle.tmp")); ThreadPoolBoundHandle boundHandle = ThreadPoolBoundHandle.BindHandle(handle); OverlappedContext result = new OverlappedContext(); byte[] data = new byte[DATA_SIZE]; data[0] = (byte)'A'; data[1] = (byte)'B'; NativeOverlapped *overlapped = boundHandle.AllocateNativeOverlapped(OnOverlappedOperationCompleted, result, 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.GetLastWin32Error()); } // Wait for overlapped operation to complete result.Event.WaitOne(); } boundHandle.FreeNativeOverlapped(overlapped); boundHandle.Dispose(); handle.Dispose(); Assert.Equal(0, result.ErrorCode); Assert.Equal(DATA_SIZE, result.BytesWritten); }
// SetUnmanagedStructures // // This needs to be called for overlapped IO to function properly. // // Fills in overlapped Structures used in an async overlapped Winsock call. // These calls are outside the runtime and are unmanaged code, so we need // to prepare specific structures and ints that lie in unmanaged memory // since the overlapped calls may complete asynchronously. internal void SetUnmanagedStructures(object objectsToPin) { Socket s = (Socket)AsyncObject; // Bind the Win32 Socket Handle to the ThreadPool Debug.Assert(s != null, "m_CurrentSocket is null"); Debug.Assert(s.SafeHandle != null, "m_CurrentSocket.SafeHandle is null"); if (s.SafeHandle.IsInvalid) { throw new ObjectDisposedException(s.GetType().FullName); } ThreadPoolBoundHandle boundHandle = s.SafeHandle.GetOrAllocateThreadPoolBoundHandle(); unsafe { NativeOverlapped *overlapped = boundHandle.AllocateNativeOverlapped(s_ioCallback, this, objectsToPin); _nativeOverlapped = new SafeNativeOverlapped(s.SafeHandle, overlapped); if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"{boundHandle}::AllocateNativeOverlapped. return={_nativeOverlapped}"); } } }
// SetUnmanagedStructures // // This needs to be called for overlapped IO to function properly. // // Fills in overlapped Structures used in an async overlapped Winsock call. // These calls are outside the runtime and are unmanaged code, so we need // to prepare specific structures and ints that lie in unmanaged memory // since the overlapped calls may complete asynchronously. internal void SetUnmanagedStructures(object objectsToPin) { Socket s = (Socket)AsyncObject; // Bind the Win32 Socket Handle to the ThreadPool Debug.Assert(s != null, "m_CurrentSocket is null"); Debug.Assert(s.SafeHandle != null, "m_CurrentSocket.SafeHandle is null"); if (s.SafeHandle.IsInvalid) { throw new ObjectDisposedException(s.GetType().FullName); } ThreadPoolBoundHandle boundHandle = s.SafeHandle.GetOrAllocateThreadPoolBoundHandle(); unsafe { NativeOverlapped *overlapped = boundHandle.AllocateNativeOverlapped(s_ioCallback, this, objectsToPin); _nativeOverlapped = new SafeNativeOverlapped(s.SafeHandle, overlapped); if (GlobalLog.IsEnabled) { GlobalLog.Print( "BaseOverlappedAsyncResult#" + LoggingHash.HashString(this) + "::boundHandle#" + LoggingHash.HashString(boundHandle) + "::AllocateNativeOverlapped. Return=" + _nativeOverlapped.DangerousGetHandle().ToString("x")); } } }
public unsafe void Read() { var buffer = Writer.Alloc(2048); fixed(byte *source = &buffer.Memory.Span.DangerousGetPinnableReference()) { var count = buffer.Memory.Length; var overlapped = ThreadPoolBoundHandle.AllocateNativeOverlapped(PreAllocatedOverlapped); overlapped->OffsetLow = Offset; Overlapped = overlapped; BoxedBuffer = new StrongBox <WritableBuffer>(buffer); int r = ReadFile(FileHandle, (IntPtr)source, count, IntPtr.Zero, overlapped); // TODO: Error handling // 997 int hr = Marshal.GetLastWin32Error(); if (hr != 997) { Writer.Complete(Marshal.GetExceptionForHR(hr)); } } }
public unsafe void Read() { var buffer = Channel.Alloc(2048); void *pointer; if (!buffer.Memory.TryGetPointer(out pointer)) { throw new InvalidOperationException("Memory needs to be pinned"); } var data = (IntPtr)pointer; var count = buffer.Memory.Length; var overlapped = ThreadPoolBoundHandle.AllocateNativeOverlapped(PreAllocatedOverlapped); overlapped->OffsetLow = Offset; Overlapped = overlapped; BoxedBuffer = new Box <WritableBuffer>(buffer); int r = ReadFile(FileHandle, data, count, IntPtr.Zero, overlapped); // TODO: Error handling // 997 int hr = Marshal.GetLastWin32Error(); if (hr != 997) { Channel.CompleteWriter(Marshal.GetExceptionForHR(hr)); } }
public unsafe void Read() { var buffer = Channel.Alloc(2048); var data = buffer.Memory.BufferPtr; var count = buffer.Memory.Length; var overlapped = ThreadPoolBoundHandle.AllocateNativeOverlapped(PreAllocatedOverlapped); overlapped->OffsetLow = Offset; Overlapped = overlapped; BoxedBuffer = new Box <WritableBuffer>(buffer); int r = ReadFile(FileHandle, data, count, IntPtr.Zero, overlapped); // TODO: Error handling // 997 int hr = Marshal.GetLastWin32Error(); if (hr != 997) { Channel.CompleteWriting(Marshal.GetExceptionForHR(hr)); } }
internal HttpRequestStreamAsyncResult(ThreadPoolBoundHandle boundHandle, object asyncObject, object userState, AsyncCallback callback, byte[] buffer, int offset, uint size, uint dataAlreadyRead) : base(asyncObject, userState, callback) { _dataAlreadyRead = dataAlreadyRead; _boundHandle = boundHandle; _pOverlapped = boundHandle.AllocateNativeOverlapped(s_IOCallback, state: this, pinData: buffer); _pPinnedBuffer = (void *)(Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset)); }
[PlatformSpecific(TestPlatforms.Windows)] // ThreadPoolBoundHandle.BindHandle is not supported on Unix public unsafe void FreeNativeOverlapped_WhenDisposed_DoesNotThrow() { ThreadPoolBoundHandle boundHandle = CreateThreadPoolBoundHandle(); NativeOverlapped * overlapped = boundHandle.AllocateNativeOverlapped((_, __, ___) => { }, new object(), new byte[256]); boundHandle.Dispose(); boundHandle.FreeNativeOverlapped(overlapped); }
[PlatformSpecific(TestPlatforms.Windows)] // ThreadPoolBoundHandle.BindHandle is not supported on Unix public unsafe void AllocateNativeOverlapped_NullAsCallback_ThrowsArgumentNullException() { using (ThreadPoolBoundHandle handle = CreateThreadPoolBoundHandle()) { AssertExtensions.Throws <ArgumentNullException>("callback", () => handle.AllocateNativeOverlapped(null, new object(), new byte[256])); AssertExtensions.Throws <ArgumentNullException>("callback", () => handle.UnsafeAllocateNativeOverlapped(null, new object(), new byte[256])); } }
private unsafe void InitializeOverlapped(ThreadPoolBoundHandle boundHandle) { #if DEBUG DebugRefCountAllocNativeOverlapped(); #endif _boundHandle = boundHandle; _ptrNativeOverlapped = boundHandle.AllocateNativeOverlapped(CompletionPortCallback, null, 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); } } }
public unsafe void Dispose_WithoutFreeingNativeOverlapped_DoesNotThrow() { ThreadPoolBoundHandle boundHandle = CreateThreadPoolBoundHandle(); NativeOverlapped *overlapped = boundHandle.AllocateNativeOverlapped((_, __, ___) => { }, new object(), new byte[1024]); boundHandle.Dispose(); }
[PlatformSpecific(TestPlatforms.Windows)] // ThreadPoolBoundHandle.BindHandle is not supported on Unix public unsafe void AllocateNativeOverlapped_WhenDisposed_ThrowsObjectDisposedException() { ThreadPoolBoundHandle handle = CreateThreadPoolBoundHandle(); handle.Dispose(); Assert.Throws <ObjectDisposedException>(() => handle.AllocateNativeOverlapped((_, __, ___) => { }, new object(), new byte[256])); Assert.Throws <ObjectDisposedException>(() => handle.UnsafeAllocateNativeOverlapped((_, __, ___) => { }, new object(), new byte[256])); }
public unsafe void AllocateNativeOverlapped_NonBlittableTypeAsPinData_Throws() { using (ThreadPoolBoundHandle handle = CreateThreadPoolBoundHandle()) { Assert.Throws <ArgumentException>(() => handle.AllocateNativeOverlapped((_, __, ___) => { }, new object(), new NonBlittableType() { s = "foo" })); } }
public unsafe void AllocateNativeOverlapped_EmptyArrayAsPinData_DoesNotThrow() { using (ThreadPoolBoundHandle handle = CreateThreadPoolBoundHandle()) { NativeOverlapped *result = handle.AllocateNativeOverlapped((_, __, ___) => { }, new object(), new byte[0]); Assert.True(result != null); handle.FreeNativeOverlapped(result); } }
public unsafe void AllocateNativeOverlapped_NullAsContext_DoesNotThrow() { using (ThreadPoolBoundHandle handle = CreateThreadPoolBoundHandle()) { NativeOverlapped *result = handle.AllocateNativeOverlapped((_, __, ___) => { }, (object)null, new byte[256]); Assert.True(result != null); handle.FreeNativeOverlapped(result); } }
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); } }
[PlatformSpecific(TestPlatforms.Windows)] // ThreadPoolBoundHandle.BindHandle is not supported on Unix public unsafe void AllocateNativeOverlapped_PreAllocated_WhenDisposed_ThrowsObjectDisposedException(bool useUnsafe) { using (ThreadPoolBoundHandle handle = CreateThreadPoolBoundHandle()) { PreAllocatedOverlapped preAlloc = useUnsafe ? PreAllocatedOverlapped.UnsafeCreate(delegate { }, null, null) : new PreAllocatedOverlapped(delegate { }, null, null); preAlloc.Dispose(); Assert.Throws <ObjectDisposedException>(() => handle.AllocateNativeOverlapped(preAlloc)); } }
[PlatformSpecific(TestPlatforms.Windows)] // ThreadPoolBoundHandle.BindHandle is not supported on Unix public unsafe void FlowsAsyncLocalsToCallback_PreAllocatedOverlapped(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(_, __, ___); }; using (PreAllocatedOverlapped preAlloc = shouldFlow ? new PreAllocatedOverlapped(callback, context, data) : PreAllocatedOverlapped.UnsafeCreate(callback, context, data)) { NativeOverlapped *overlapped = boundHandle.AllocateNativeOverlapped(preAlloc); 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); }
public unsafe void AllocateNativeOverlapped_PreAllocated_WhenHandleDisposed_ThrowsObjectDisposedException() { ThreadPoolBoundHandle handle = CreateThreadPoolBoundHandle(); handle.Dispose(); PreAllocatedOverlapped preAlloc = new PreAllocatedOverlapped(delegate { }, null, null); Assert.Throws <ObjectDisposedException>(() => { handle.AllocateNativeOverlapped(preAlloc); }); }
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); } }
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)); } }
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); } }