public unsafe NativeOverlapped* AllocateNativeOverlapped(PreAllocatedOverlapped preAllocated) { if (preAllocated == null) throw new ArgumentNullException("preAllocated"); bool addedRefToThis = false; bool addedRefToPreAllocated = false; try { addedRefToThis = AddRef(); addedRefToPreAllocated = preAllocated.AddRef(); Win32ThreadPoolNativeOverlapped.OverlappedData data = preAllocated._overlapped->Data; if (data._boundHandle != null) throw new ArgumentException(SR.Argument_PreAllocatedAlreadyAllocated, "preAllocated"); data._boundHandle = this; Interop.mincore.StartThreadpoolIo(_threadPoolHandle); return Win32ThreadPoolNativeOverlapped.ToNativeOverlapped(preAllocated._overlapped); } catch { if (addedRefToPreAllocated) preAllocated.Release(); if (addedRefToThis) Release(); throw; } }
internal unsafe static Win32ThreadPoolNativeOverlapped* Allocate(IOCompletionCallback callback, object state, object pinData, PreAllocatedOverlapped preAllocated) { Win32ThreadPoolNativeOverlapped* overlapped = AllocateNew(); try { overlapped->SetData(callback, state, pinData, preAllocated); } catch { Free(overlapped); throw; } return overlapped; }
internal void Reset() { Debug.Assert(_boundHandle == null); //not in use if (_pinnedData != null) { for (int i = 0; i < _pinnedData.Length; i++) { if (_pinnedData[i].IsAllocated && _pinnedData[i].Target != null) _pinnedData[i].Target = null; } } _callback = null; _state = null; _executionContext = null; _completed = false; _preAllocated = null; }
// 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 = _input, FileHandle = fileHandle, ThreadPoolBoundHandle = handle, IOCallback = IOCallback }; var overlapped = new PreAllocatedOverlapped(IOCallback, readOperation, null); readOperation.PreAllocatedOverlapped = overlapped; _input.ReadingStarted.ContinueWith((t, state) => { ((ReadOperation)state).Read(); }, readOperation); }
partial void OnBufferAllocated() { Debug.Assert(_buffer != null); Debug.Assert(_preallocatedOverlapped == null); if (_useAsyncIO) _preallocatedOverlapped = new PreAllocatedOverlapped(s_ioCallback, this, _buffer); }
private async Task AsyncModeCopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken) { Debug.Assert(_useAsyncIO, "This implementation is for async mode only"); Debug.Assert(!_fileHandle.IsClosed, "!_handle.IsClosed"); Debug.Assert(CanRead, "_parent.CanRead"); // Make sure any pending writes have been flushed before we do a read. if (_writePos > 0) { await FlushWriteAsync(cancellationToken).ConfigureAwait(false); } // Typically CopyToAsync would be invoked as the only "read" on the stream, but it's possible some reading is // done and then the CopyToAsync is issued. For that case, see if we have any data available in the buffer. if (GetBuffer() != null) { int bufferedBytes = _readLength - _readPos; if (bufferedBytes > 0) { await destination.WriteAsync(GetBuffer(), _readPos, bufferedBytes, cancellationToken).ConfigureAwait(false); _readPos = _readLength = 0; } } // For efficiency, we avoid creating a new task and associated state for each asynchronous read. // Instead, we create a single reusable awaitable object that will be triggered when an await completes // and reset before going again. var readAwaitable = new AsyncCopyToAwaitable(this); // Make sure we are reading from the position that we think we are. // Only set the position in the awaitable if we can seek (e.g. not for pipes). bool canSeek = CanSeek; if (canSeek) { VerifyOSHandlePosition(); readAwaitable._position = _filePosition; } // Get the buffer to use for the copy operation, as the base CopyToAsync does. We don't try to use // _buffer here, even if it's not null, as concurrent operations are allowed, and another operation may // actually be using the buffer already. Plus, it'll be rare for _buffer to be non-null, as typically // CopyToAsync is used as the only operation performed on the stream, and the buffer is lazily initialized. // Further, typically the CopyToAsync buffer size will be larger than that used by the FileStream, such that // we'd likely be unable to use it anyway. Instead, we rent the buffer from a pool. byte[] copyBuffer = ArrayPool<byte>.Shared.Rent(bufferSize); bufferSize = 0; // repurpose bufferSize to be the high water mark for the buffer, to avoid an extra field in the state machine // Allocate an Overlapped we can use repeatedly for all operations var awaitableOverlapped = new PreAllocatedOverlapped(AsyncCopyToAwaitable.s_callback, readAwaitable, copyBuffer); var cancellationReg = default(CancellationTokenRegistration); try { // Register for cancellation. We do this once for the whole copy operation, and just try to cancel // whatever read operation may currently be in progress, if there is one. It's possible the cancellation // request could come in between operations, in which case we flag that with explicit calls to ThrowIfCancellationRequested // in the read/write copy loop. if (cancellationToken.CanBeCanceled) { cancellationReg = cancellationToken.Register(s => { var innerAwaitable = (AsyncCopyToAwaitable)s; unsafe { lock (innerAwaitable.CancellationLock) // synchronize with cleanup of the overlapped { if (innerAwaitable._nativeOverlapped != null) { // Try to cancel the I/O. We ignore the return value, as cancellation is opportunistic and we // don't want to fail the operation because we couldn't cancel it. Interop.Kernel32.CancelIoEx(innerAwaitable._fileStream._fileHandle, innerAwaitable._nativeOverlapped); } } } }, readAwaitable); } // Repeatedly read from this FileStream and write the results to the destination stream. while (true) { cancellationToken.ThrowIfCancellationRequested(); readAwaitable.ResetForNextOperation(); try { bool synchronousSuccess; int errorCode; unsafe { // Allocate a native overlapped for our reusable overlapped, and set position to read based on the next // desired address stored in the awaitable. (This position may be 0, if either we're at the beginning or // if the stream isn't seekable.) readAwaitable._nativeOverlapped = _fileHandle.ThreadPoolBinding.AllocateNativeOverlapped(awaitableOverlapped); if (canSeek) { readAwaitable._nativeOverlapped->OffsetLow = unchecked((int)readAwaitable._position); readAwaitable._nativeOverlapped->OffsetHigh = (int)(readAwaitable._position >> 32); } // Kick off the read. synchronousSuccess = ReadFileNative(_fileHandle, copyBuffer, 0, copyBuffer.Length, readAwaitable._nativeOverlapped, out errorCode) >= 0; } // If the operation did not synchronously succeed, it either failed or initiated the asynchronous operation. if (!synchronousSuccess) { switch (errorCode) { case ERROR_IO_PENDING: // Async operation in progress. break; case ERROR_BROKEN_PIPE: case ERROR_HANDLE_EOF: // We're at or past the end of the file, and the overlapped callback // won't be raised in these cases. Mark it as completed so that the await // below will see it as such. readAwaitable.MarkCompleted(); break; default: // Everything else is an error (and there won't be a callback). throw Win32Marshal.GetExceptionForWin32Error(errorCode); } } // Wait for the async operation (which may or may not have already completed), then throw if it failed. await readAwaitable; switch (readAwaitable._errorCode) { case 0: // success Debug.Assert(readAwaitable._numBytes >= 0, $"Expected non-negative numBytes, got {readAwaitable._numBytes}"); break; case ERROR_BROKEN_PIPE: // logically success with 0 bytes read (write end of pipe closed) case ERROR_HANDLE_EOF: // logically success with 0 bytes read (read at end of file) Debug.Assert(readAwaitable._numBytes == 0, $"Expected 0 bytes read, got {readAwaitable._numBytes}"); break; case Interop.Errors.ERROR_OPERATION_ABORTED: // canceled throw new OperationCanceledException(cancellationToken.IsCancellationRequested ? cancellationToken : new CancellationToken(true)); default: // error throw Win32Marshal.GetExceptionForWin32Error((int)readAwaitable._errorCode); } // Successful operation. If we got zero bytes, we're done: exit the read/write loop. int numBytesRead = (int)readAwaitable._numBytes; if (numBytesRead == 0) { break; } // Otherwise, update the read position for next time accordingly. if (canSeek) { readAwaitable._position += numBytesRead; } // (and keep track of the maximum number of bytes in the buffer we used, to avoid excessive and unnecessary // clearing of the buffer before we return it to the pool) if (numBytesRead > bufferSize) { bufferSize = numBytesRead; } } finally { // Free the resources for this read operation unsafe { NativeOverlapped* overlapped; lock (readAwaitable.CancellationLock) // just an Exchange, but we need this to be synchronized with cancellation, so using the same lock { overlapped = readAwaitable._nativeOverlapped; readAwaitable._nativeOverlapped = null; } if (overlapped != null) { _fileHandle.ThreadPoolBinding.FreeNativeOverlapped(overlapped); } } } // Write out the read data. await destination.WriteAsync(copyBuffer, 0, (int)readAwaitable._numBytes, cancellationToken).ConfigureAwait(false); } } finally { // Cleanup from the whole copy operation cancellationReg.Dispose(); awaitableOverlapped.Dispose(); Array.Clear(copyBuffer, 0, bufferSize); ArrayPool<byte>.Shared.Return(copyBuffer, clearArray: false); // Make sure the stream's current position reflects where we ended up if (!_fileHandle.IsClosed && CanSeek) { SeekCore(0, SeekOrigin.End); } } }
private void AllocateBuffer() { Debug.Assert(_buffer == null); Debug.Assert(_preallocatedOverlapped == null); _buffer = new byte[_bufferSize]; if (_isAsync) { _preallocatedOverlapped = new PreAllocatedOverlapped(s_ioCallback, this, _buffer); } }
public unsafe void AllocateNativeOverlapped_PreAllocated_ReturnedNativeOverlapped_AllFieldsZero() { using(ThreadPoolBoundHandle handle = CreateThreadPoolBoundHandle()) { using(PreAllocatedOverlapped preAlloc = new PreAllocatedOverlapped((_, __, ___) => { }, new object(), new byte[256])) { NativeOverlapped* 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); } } }
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); }); }
private void SetData(IOCompletionCallback callback, object state, object pinData, PreAllocatedOverlapped preAllocated) { Debug.Assert(callback != null); OverlappedData data = Data; data._callback = callback; data._state = state; data._executionContext = ExecutionContext.Capture(); data._preAllocated = preAllocated; // // pinData can be any blittable type to be pinned, *or* an instance of object[] each element of which refers to // an instance of a blittable type to be pinned. // if (pinData != null) { object[] objArray = pinData as object[]; if (objArray != null && objArray.GetType() == typeof(object[])) { if (data._pinnedData == null || data._pinnedData.Length < objArray.Length) Array.Resize(ref data._pinnedData, objArray.Length); for (int i = 0; i < objArray.Length; i++) { if (!data._pinnedData[i].IsAllocated) data._pinnedData[i] = GCHandle.Alloc(objArray[i], GCHandleType.Pinned); else data._pinnedData[i].Target = objArray[i]; } } else { if (data._pinnedData == null) data._pinnedData = new GCHandle[1]; if (!data._pinnedData[0].IsAllocated) data._pinnedData[0] = GCHandle.Alloc(pinData, GCHandleType.Pinned); else data._pinnedData[0].Target = pinData; } } }
public unsafe NativeOverlapped* AllocateNativeOverlapped(PreAllocatedOverlapped preAllocated) { if (preAllocated == null) throw new ArgumentNullException("preAllocated"); EnsureNotDisposed(); preAllocated.AddRef(); try { ThreadPoolBoundHandleOverlapped overlapped = preAllocated._overlapped; if (overlapped._boundHandle != null) throw new ArgumentException(SR.Argument_PreAllocatedAlreadyAllocated, "preAllocated"); overlapped._boundHandle = this; return overlapped._nativeOverlapped; } catch { preAllocated.Release(); throw; } }
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; }
internal static unsafe Win32ThreadPoolNativeOverlapped *Allocate(IOCompletionCallback callback, object state, object pinData, PreAllocatedOverlapped preAllocated) { Win32ThreadPoolNativeOverlapped *overlapped = AllocateNew(); try { overlapped->SetData(callback, state, pinData, preAllocated); } catch { Free(overlapped); throw; } return(overlapped); }
private void SetData(IOCompletionCallback callback, object state, object pinData, PreAllocatedOverlapped preAllocated) { Debug.Assert(callback != null); OverlappedData data = Data; data._callback = callback; data._state = state; data._executionContext = ExecutionContext.Capture(); data._preAllocated = preAllocated; // // pinData can be any blittable type to be pinned, *or* an instance of object[] each element of which refers to // an instance of a blittable type to be pinned. // if (pinData != null) { object[] objArray = pinData as object[]; if (objArray != null && objArray.GetType() == typeof(object[])) { if (data._pinnedData == null || data._pinnedData.Length < objArray.Length) { Array.Resize(ref data._pinnedData, objArray.Length); } for (int i = 0; i < objArray.Length; i++) { if (!data._pinnedData[i].IsAllocated) { data._pinnedData[i] = GCHandle.Alloc(objArray[i], GCHandleType.Pinned); } else { data._pinnedData[i].Target = objArray[i]; } } } else { if (data._pinnedData == null) { data._pinnedData = new GCHandle[1]; } if (!data._pinnedData[0].IsAllocated) { data._pinnedData[0] = GCHandle.Alloc(pinData, GCHandleType.Pinned); } else { data._pinnedData[0].Target = pinData; } } } }
public unsafe ThreadPoolBoundHandleOverlapped(IOCompletionCallback callback, object state, object pinData, PreAllocatedOverlapped preAllocated) { _userCallback = callback; _userState = state; _preAllocated = preAllocated; _nativeOverlapped = Pack(s_completionCallback, pinData); _nativeOverlapped->OffsetLow = 0; // CLR reuses NativeOverlapped instances and does not reset these _nativeOverlapped->OffsetHigh = 0; }
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); } } }
private void AllocateBuffer() { Debug.Assert(_buffer == null); Debug.Assert(_preallocatedOverlapped == null); _buffer = new byte[_bufferSize]; // TODO: Issue #5598: Use ArrayPool. if (_isAsync) { _preallocatedOverlapped = new PreAllocatedOverlapped(s_ioCallback, this, _buffer); } }
// Cleans up any existing Overlapped object and related state variables. private void FreeOverlapped(bool checkForShutdown) { if (!checkForShutdown || !Environment.HasShutdownStarted) { // Free the overlapped object. if (_ptrNativeOverlapped != null && !_ptrNativeOverlapped.IsInvalid) { _ptrNativeOverlapped.Dispose(); _ptrNativeOverlapped = null; } // Free the preallocated overlapped object. This in turn will unpin // any pinned buffers. if (_preAllocatedOverlapped != null) { _preAllocatedOverlapped.Dispose(); _preAllocatedOverlapped = null; _pinState = PinState.None; _pinnedAcceptBuffer = null; _pinnedSingleBuffer = null; _pinnedSingleBufferOffset = 0; _pinnedSingleBufferCount = 0; } // Free any allocated GCHandles. if (_socketAddressGCHandle.IsAllocated) { _socketAddressGCHandle.Free(); _pinnedSocketAddress = null; } if (_wsaMessageBufferGCHandle.IsAllocated) { _wsaMessageBufferGCHandle.Free(); _ptrWSAMessageBuffer = IntPtr.Zero; } if (_wsaRecvMsgWSABufferArrayGCHandle.IsAllocated) { _wsaRecvMsgWSABufferArrayGCHandle.Free(); _ptrWSARecvMsgWSABufferArray = IntPtr.Zero; } if (_controlBufferGCHandle.IsAllocated) { _controlBufferGCHandle.Free(); _ptrControlBuffer = IntPtr.Zero; } } }
public unsafe System.Threading.NativeOverlapped *AllocateNativeOverlapped(System.Threading.PreAllocatedOverlapped preAllocated) { throw null; }
// Sets up an Overlapped object with with multiple buffers pinned. unsafe private void SetupOverlappedMultiple() { ArraySegment<byte>[] tempList = new ArraySegment<byte>[_bufferList.Count]; _bufferList.CopyTo(tempList, 0); // Number of things to pin is number of buffers. // Ensure we have properly sized object array. if (_objectsToPin == null || (_objectsToPin.Length != tempList.Length)) { _objectsToPin = new object[tempList.Length]; } // Fill in object array. for (int i = 0; i < (tempList.Length); i++) { _objectsToPin[i] = tempList[i].Array; } if (_wsaBufferArray == null || _wsaBufferArray.Length != tempList.Length) { _wsaBufferArray = new WSABuffer[tempList.Length]; } // Pin buffers and fill in WSABuffer descriptor pointers and lengths. _preAllocatedOverlapped = new PreAllocatedOverlapped(CompletionPortCallback, this, _objectsToPin); if (GlobalLog.IsEnabled) { GlobalLog.Print( "SocketAsyncEventArgs#" + LoggingHash.HashString(this) + "::SetupOverlappedMultiple: new PreAllocatedOverlapped." + LoggingHash.HashString(_preAllocatedOverlapped)); } for (int i = 0; i < tempList.Length; i++) { ArraySegment<byte> localCopy = tempList[i]; RangeValidationHelpers.ValidateSegment(localCopy); _wsaBufferArray[i].Pointer = Marshal.UnsafeAddrOfPinnedArrayElement(localCopy.Array, localCopy.Offset); _wsaBufferArray[i].Length = localCopy.Count; } _pinState = PinState.MultipleBuffer; }
// Sets up an Overlapped object with either _buffer or _acceptBuffer pinned. unsafe private void SetupOverlappedSingle(bool pinSingleBuffer) { // Pin buffer, get native pointers, and fill in WSABuffer descriptor. if (pinSingleBuffer) { if (_buffer != null) { _preAllocatedOverlapped = new PreAllocatedOverlapped(CompletionPortCallback, this, _buffer); if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"new PreAllocatedOverlapped pinSingleBuffer=true, non-null buffer:{_preAllocatedOverlapped}"); _pinnedSingleBuffer = _buffer; _pinnedSingleBufferOffset = _offset; _pinnedSingleBufferCount = _count; _ptrSingleBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(_buffer, _offset); _ptrAcceptBuffer = IntPtr.Zero; _wsaBuffer.Pointer = _ptrSingleBuffer; _wsaBuffer.Length = _count; _pinState = PinState.SingleBuffer; } else { _preAllocatedOverlapped = new PreAllocatedOverlapped(CompletionPortCallback, this, null); if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"new PreAllocatedOverlapped pinSingleBuffer=true, null buffer: {_preAllocatedOverlapped}"); _pinnedSingleBuffer = null; _pinnedSingleBufferOffset = 0; _pinnedSingleBufferCount = 0; _ptrSingleBuffer = IntPtr.Zero; _ptrAcceptBuffer = IntPtr.Zero; _wsaBuffer.Pointer = _ptrSingleBuffer; _wsaBuffer.Length = _count; _pinState = PinState.NoBuffer; } } else { _preAllocatedOverlapped = new PreAllocatedOverlapped(CompletionPortCallback, this, _acceptBuffer); if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"new PreAllocatedOverlapped pinSingleBuffer=false:{_preAllocatedOverlapped}"); _pinnedAcceptBuffer = _acceptBuffer; _ptrAcceptBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(_acceptBuffer, 0); _ptrSingleBuffer = IntPtr.Zero; _pinState = PinState.SingleAcceptBuffer; } }
public unsafe void AllocateNativeOverlapped_PreAllocated_ReusedReturnedNativeOverlapped_OffsetLowAndOffsetHighSetToZero() { // The CLR reuses NativeOverlapped underneath, check to make sure that they reset fields back to zero using(ThreadPoolBoundHandle handle = CreateThreadPoolBoundHandle()) { PreAllocatedOverlapped preAlloc = 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); } }
// Sets up an Overlapped object with either _buffer or _acceptBuffer pinned. unsafe private void SetupOverlappedSingle(bool pinSingleBuffer) { // Pin buffer, get native pointers, and fill in WSABuffer descriptor. if (pinSingleBuffer) { if (_buffer != null) { _preAllocatedOverlapped = new PreAllocatedOverlapped(CompletionPortCallback, this, _buffer); if (GlobalLog.IsEnabled) { GlobalLog.Print( "SocketAsyncEventArgs#" + LoggingHash.HashString(this) + "::SetupOverlappedSingle: new PreAllocatedOverlapped pinSingleBuffer=true, non-null buffer: " + LoggingHash.HashString(_preAllocatedOverlapped)); } _pinnedSingleBuffer = _buffer; _pinnedSingleBufferOffset = _offset; _pinnedSingleBufferCount = _count; _ptrSingleBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(_buffer, _offset); _ptrAcceptBuffer = IntPtr.Zero; _wsaBuffer.Pointer = _ptrSingleBuffer; _wsaBuffer.Length = _count; _pinState = PinState.SingleBuffer; } else { _preAllocatedOverlapped = new PreAllocatedOverlapped(CompletionPortCallback, this, null); if (GlobalLog.IsEnabled) { GlobalLog.Print( "SocketAsyncEventArgs#" + LoggingHash.HashString(this) + "::SetupOverlappedSingle: new PreAllocatedOverlapped pinSingleBuffer=true, null buffer: " + LoggingHash.HashString(_preAllocatedOverlapped)); } _pinnedSingleBuffer = null; _pinnedSingleBufferOffset = 0; _pinnedSingleBufferCount = 0; _ptrSingleBuffer = IntPtr.Zero; _ptrAcceptBuffer = IntPtr.Zero; _wsaBuffer.Pointer = _ptrSingleBuffer; _wsaBuffer.Length = _count; _pinState = PinState.NoBuffer; } } else { _preAllocatedOverlapped = new PreAllocatedOverlapped(CompletionPortCallback, this, _acceptBuffer); if (GlobalLog.IsEnabled) { GlobalLog.Print( "SocketAsyncEventArgs#" + LoggingHash.HashString(this) + "::SetupOverlappedSingle: new PreAllocatedOverlapped pinSingleBuffer=false: " + LoggingHash.HashString(_preAllocatedOverlapped)); } _pinnedAcceptBuffer = _acceptBuffer; _ptrAcceptBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(_acceptBuffer, 0); _ptrSingleBuffer = IntPtr.Zero; _pinState = PinState.SingleAcceptBuffer; } }
public unsafe void MultipleOperationsOverMultipleHandles() { const int DATA_SIZE = 2; SafeHandle handle1 = HandleFactory.CreateAsyncFileHandleForWrite(@"MultipleOperationsOverMultipleHandle1.tmp"); SafeHandle handle2 = HandleFactory.CreateAsyncFileHandleForWrite(@"MultipleOperationsOverMultipleHandle2.tmp"); ThreadPoolBoundHandle boundHandle1 = ThreadPoolBoundHandle.BindHandle(handle1); ThreadPoolBoundHandle boundHandle2 = ThreadPoolBoundHandle.BindHandle(handle2); 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'; PreAllocatedOverlapped preAlloc1 = new PreAllocatedOverlapped(OnOverlappedOperationCompleted, result1, data1); PreAllocatedOverlapped preAlloc2 = new PreAllocatedOverlapped(OnOverlappedOperationCompleted, result2, data2); for (int i = 0; i < 10; i++) { NativeOverlapped* overlapped1 = boundHandle1.AllocateNativeOverlapped(preAlloc1); NativeOverlapped* overlapped2 = boundHandle2.AllocateNativeOverlapped(preAlloc2); fixed (byte* p1 = data1, p2 = data2) { int retval = DllImport.WriteFile(boundHandle1.Handle, p1, DATA_SIZE, IntPtr.Zero, overlapped1); if (retval == 0) { Assert.Equal(DllImport.ERROR_IO_PENDING, Marshal.GetLastWin32Error()); } retval = DllImport.WriteFile(boundHandle2.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 }); } boundHandle1.FreeNativeOverlapped(overlapped1); boundHandle2.FreeNativeOverlapped(overlapped2); result1.Event.Reset(); result2.Event.Reset(); Assert.Equal(0, result1.ErrorCode); Assert.Equal(0, result2.ErrorCode); Assert.Equal(DATA_SIZE, result1.BytesWritten); Assert.Equal(DATA_SIZE, result2.BytesWritten); } boundHandle1.Dispose(); boundHandle2.Dispose(); preAlloc1.Dispose(); preAlloc2.Dispose(); handle1.Dispose(); handle2.Dispose(); }
// Sets up an Overlapped object for SendPacketsAsync. unsafe private void SetupOverlappedSendPackets() { int index; // Alloc native descriptor. _sendPacketsDescriptor = new Interop.Winsock.TransmitPacketsElement[_sendPacketsElementsFileCount + _sendPacketsElementsBufferCount]; // Number of things to pin is number of buffers + 1 (native descriptor). // Ensure we have properly sized object array. if (_objectsToPin == null || (_objectsToPin.Length != _sendPacketsElementsBufferCount + 1)) { _objectsToPin = new object[_sendPacketsElementsBufferCount + 1]; } // Fill in objects to pin array. Native descriptor buffer first and then user specified buffers. _objectsToPin[0] = _sendPacketsDescriptor; index = 1; foreach (SendPacketsElement spe in _sendPacketsElementsInternal) { if (spe != null && spe._buffer != null && spe._count > 0) { _objectsToPin[index] = spe._buffer; index++; } } // Pin buffers. _preAllocatedOverlapped = new PreAllocatedOverlapped(CompletionPortCallback, this, _objectsToPin); if (GlobalLog.IsEnabled) { GlobalLog.Print( "SocketAsyncEventArgs#" + LoggingHash.HashString(this) + "::SetupOverlappedSendPackets: new PreAllocatedOverlapped: " + LoggingHash.HashString(_preAllocatedOverlapped)); } // Get pointer to native descriptor. _ptrSendPacketsDescriptor = Marshal.UnsafeAddrOfPinnedArrayElement(_sendPacketsDescriptor, 0); // Fill in native descriptor. int descriptorIndex = 0; int fileIndex = 0; foreach (SendPacketsElement spe in _sendPacketsElementsInternal) { if (spe != null) { if (spe._buffer != null && spe._count > 0) { // This element is a buffer. _sendPacketsDescriptor[descriptorIndex].buffer = Marshal.UnsafeAddrOfPinnedArrayElement(spe._buffer, spe._offset); _sendPacketsDescriptor[descriptorIndex].length = (uint)spe._count; _sendPacketsDescriptor[descriptorIndex].flags = (Interop.Winsock.TransmitPacketsElementFlags)spe._flags; descriptorIndex++; } else if (spe._filePath != null) { // This element is a file. _sendPacketsDescriptor[descriptorIndex].fileHandle = _sendPacketsFileHandles[fileIndex].DangerousGetHandle(); _sendPacketsDescriptor[descriptorIndex].fileOffset = spe._offset; _sendPacketsDescriptor[descriptorIndex].length = (uint)spe._count; _sendPacketsDescriptor[descriptorIndex].flags = (Interop.Winsock.TransmitPacketsElementFlags)spe._flags; fileIndex++; descriptorIndex++; } } } _pinState = PinState.SendPackets; }
public unsafe NativeOverlapped *AllocateNativeOverlapped(PreAllocatedOverlapped preAllocated) { ArgumentNullException.ThrowIfNull(preAllocated); throw new PlatformNotSupportedException(SR.PlatformNotSupported_OverlappedIO); }