private CancellationToken CreateToken(ulong connectionId) { 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(); var nativeOverlapped = overlapped.UnsafePack((errorCode, numBytes, pOVERLAP) => { Debug.WriteLine("Server: http.sys disconnect callback fired for connection ID: " + connectionId); // Free the overlapped Overlapped.Free(pOVERLAP); // Pull the token out of the list and Cancel it. Lazy <CancellationToken> token; _connectionCancellationTokens.TryRemove(connectionId, out token); cts.Cancel(); }, null); uint hr = NativeMethods.HttpWaitForDisconnect(_requestQueueHandle, connectionId, nativeOverlapped); if (hr != NativeMethods.HttpErrors.ERROR_IO_PENDING && hr != NativeMethods.HttpErrors.NO_ERROR) { // We got an unknown result so return a None Debug.WriteLine("Unable to register disconnect callback"); return(CancellationToken.None); } return(cts.Token); }
public unsafe void Execute(UdpSocketSendResult target) { target.Pin(buffer.Data); Overlapped overlapped = new Overlapped { AsyncResult = target }; NativeOverlapped *native = overlapped.UnsafePack(null, null); IntPtr reference = Marshal.UnsafeAddrOfPinnedArrayElement(buffer.Data, buffer.Offset); TcpSocketInterop.WSABuffer data = new TcpSocketInterop.WSABuffer { length = buffer.Count, buffer = reference }; byte[] address = endpoint.Address.GetAddressBytes(); byte[] addressData = { 0x02, 0x00, (byte)(endpoint.Port / 256), (byte)(endpoint.Port % 256), address[0], address[1], address[2], address[3], 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; IntPtr addressBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(addressData, 0); target.Pin(addressData); int written; uint result = UdpSocketInterop.WSASendTo(handle, &data, 1, out written, 0, addressBuffer, addressData.Length, native, IntPtr.Zero); uint error = TcpSocketInterop.WSAGetLastError(); if (result != 0 && error != 997) { target.Fail(error); } }
public unsafe void Execute(TcpSocketDisconnectResult target) { int sent; IntPtr ptr = IntPtr.Zero; Guid guid = new Guid("{0x7fda2e11,0x8630,0x436f,{0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}} "); int result = TcpSocketInterop.WSAIoctl(handle, unchecked ((int)0xC8000006), ref guid, sizeof(Guid), out ptr, sizeof(IntPtr), out sent, IntPtr.Zero, IntPtr.Zero); if (result != 0) { throw new Exception(); } TcpSocketInterop.DisconnectExDelegate disconnect = (TcpSocketInterop.DisconnectExDelegate)Marshal.GetDelegateForFunctionPointer(ptr, typeof(TcpSocketInterop.DisconnectExDelegate)); Overlapped overlapped = new Overlapped { AsyncResult = target }; NativeOverlapped *native = overlapped.UnsafePack(null, null); result = disconnect.Invoke(handle, native, 0x02, 0); uint error = TcpSocketInterop.GetLastError(); if (result == 0 && error != 997) { target.Fail(error); } }
/// <summary> /// <see cref="IDevice.ReadAsync(int, ulong, IntPtr, uint, IOCompletionCallback, IAsyncResult)">Inherited</see> /// </summary> public override unsafe void ReadAsync(int segmentId, ulong sourceAddress, IntPtr destinationAddress, uint readLength, IOCompletionCallback callback, IAsyncResult asyncResult) { // It is up to the allocator to make sure no reads are issued to segments before they are written if (!blobs.TryGetValue(segmentId, out BlobEntry blobEntry)) { throw new InvalidOperationException("Attempting to read non-existent segments"); } // Even though Azure Page Blob does not make use of Overlapped, we populate one to conform to the callback API Overlapped ov = new Overlapped(0, 0, IntPtr.Zero, asyncResult); NativeOverlapped *ovNative = ov.UnsafePack(callback, IntPtr.Zero); UnmanagedMemoryStream stream = new UnmanagedMemoryStream((byte *)destinationAddress, readLength, readLength, FileAccess.Write); CloudPageBlob pageBlob = blobEntry.GetPageBlob(); pageBlob.BeginDownloadRangeToStream(stream, (Int64)sourceAddress, readLength, ar => { try { pageBlob.EndDownloadRangeToStream(ar); } // I don't think I can be more specific in catch here because no documentation on exception behavior is provided catch (Exception e) { Trace.TraceError(e.Message); // Is there any documentation on the meaning of error codes here? The handler suggests that any non-zero value is an error // but does not distinguish between them. callback(2, readLength, ovNative); } callback(0, readLength, ovNative); }, asyncResult); }
internal void Pack(object pinnedObjects) { if (this.nativeOverlapped != null) { // If we reach this condition, we have a bug in a derived AsyncResult class. // It attempted to initiate a new async I/O operation before the previous // one completed. This is a fatal condition, so we cannot continue execution. DiagnosticUtility.FailFast("Must allow previous I/O to complete before packing"); } GC.ReRegisterForFinalize(this); Overlapped overlapped = new Overlapped(0, 0, IntPtr.Zero, this); if (this.callback == null) { this.nativeOverlapped = overlapped.UnsafePack( IOCompletionCallback, pinnedObjects); } else { this.nativeOverlapped = overlapped.Pack( IOCompletionCallback, pinnedObjects); } }
public unsafe void Execute(FileWriteResult target) { target.Pin(buffer.Data); Overlapped overlapped = new Overlapped { AsyncResult = target, OffsetLow = (int)(target.Position & 0xffffffff), OffsetHigh = (int)((target.Position >> 32) & 0xffffffff) }; NativeOverlapped *native = overlapped.UnsafePack(null, null); IntPtr array = Marshal.UnsafeAddrOfPinnedArrayElement(buffer.Data, buffer.Offset); int read; int result = FileInterop.WriteFile(handle, array, buffer.Count, out read, native); uint error = FileInterop.GetLastError(); if (result == 0 && error != 997) { target.Fail(error); } if (result == 1) { target.Complete(native, read); } }
private unsafe void SignalWorkerThreadsToStop() { Observable.Interval(TimeSpan.FromMilliseconds(25)) .TakeWhile(_ => _runningThreads > 0) .Select(_ => { var result = new SwatcherAsyncResult { Buffer = new byte[0] }; var overlapped = new Overlapped { AsyncResult = result }; //the first parameter is null because we're not using IO completion callbacks; they're too slow. //we're taking the byte array from our empty byte array and passing that as user data to the overlapped. var overlappedPointer = overlapped.UnsafePack(null, result.Buffer); //when using IOCPs, we can send our own custom messages to the GetQueuedCompletionStatus //method by call PostQueuedCompletionStatus. In this case, we want to stop the threads that are //waiting on change events, so we will send a custom completion key "StopIocpThreads". WindowsFacade.PostQueuedCompletionStatus(CompletionPortHandle, 0, StopIocpThreads, overlappedPointer); return(Unit.Default); }) .AsCompletion() .Where(_ => Config.LoggingEnabled) .Subscribe(_ => { Disposables.Dispose(); Logger.Info("Swatcher has stopped"); }); }
public unsafe void Execute(UdpSocketReceiveResult target) { target.Pin(buffer.Data); IntPtr array = Marshal.UnsafeAddrOfPinnedArrayElement(buffer.Data, buffer.Offset); Overlapped overlapped = new Overlapped { AsyncResult = target }; NativeOverlapped *native = overlapped.UnsafePack(null, null); TcpSocketInterop.WSABuffer data = new TcpSocketInterop.WSABuffer { length = buffer.Count, buffer = array }; byte[] addressData = new byte[16]; IntPtr addressPointer = Marshal.UnsafeAddrOfPinnedArrayElement(addressData, 0); target.Address = addressData; target.Pin(addressData); int read, flags = 0, size = addressData.Length; int result = UdpSocketInterop.WSARecvFrom(handle, &data, 1, out read, ref flags, addressPointer, ref size, native, IntPtr.Zero); uint error = TcpSocketInterop.GetLastError(); if (result == -1 && error != 997) { target.Fail(error); } }
public unsafe void Callback(IAsyncResult result) { memory.Return(); Overlapped ov = new Overlapped(0, 0, IntPtr.Zero, asyncResult); callback(0, 0, ov.UnsafePack(callback, IntPtr.Zero)); }
public unsafe OverlappedIOCallback(WaitCallback callback, ExceptionCallback exceptionCallback) { Overlapped overlapped = new Overlapped(0, 0, IntPtr.Zero, null); this.nativeOverlapped = overlapped.UnsafePack(new IOCompletionThunk(this.IOCallback, exceptionCallback).ThunkFrame, null); this.callback = callback; }
//---- the overridden methods represent the interface for a generic storage device /// <summary> /// <see cref="IDevice.ReadAsync(int, ulong, IntPtr, uint, IOCompletionCallback, IAsyncResult)">Inherited</see> /// </summary> public override unsafe void ReadAsync(int segmentId, ulong sourceAddress, IntPtr destinationAddress, uint readLength, IOCompletionCallback callback, IAsyncResult asyncResult) { Debug.WriteLine($"AzureStorageDevice.ReadAsync Called segmentId={segmentId} sourceAddress={sourceAddress} readLength={readLength}"); // It is up to the allocator to make sure no reads are issued to segments before they are written if (!blobs.TryGetValue(segmentId, out BlobEntry blobEntry)) { var nonLoadedBlob = this.blobDirectory.GetPageBlobReference(GetSegmentBlobName(segmentId)); var exception = new InvalidOperationException("Attempt to read a non-loaded segment"); this.BlobManager?.HandleBlobError(nameof(ReadAsync), exception.Message, nonLoadedBlob?.Name, exception, true); throw exception; } // Even though Azure Page Blob does not make use of Overlapped, we populate one to conform to the callback API Overlapped ov = new Overlapped(0, 0, IntPtr.Zero, asyncResult); NativeOverlapped *ovNative = ov.UnsafePack(callback, IntPtr.Zero); this.ReadFromBlobUnsafeAsync(blobEntry.PageBlob, (long)sourceAddress, (long)destinationAddress, readLength) .ContinueWith((Task t) => { if (t.IsFaulted) { Debug.WriteLine("AzureStorageDevice.ReadAsync Returned (Failure)"); callback(uint.MaxValue, readLength, ovNative); } else { Debug.WriteLine("AzureStorageDevice.ReadAsync Returned"); callback(0, readLength, ovNative); } }); }
public void ReadAsync(ulong alignedSourceAddress, IntPtr alignedDestinationAddress, uint aligned_read_length, IOCompletionCallback callback, IAsyncResult asyncResult) { long logicalAddress = (long)alignedSourceAddress; long page = logicalAddress >> PageSizeBits; int pageIndex = (int)(page % BufferSize); Debug.Assert(page == pageIndex); Overlapped ov = new Overlapped(0, 0, IntPtr.Zero, asyncResult); NativeOverlapped *ov_native = ov.UnsafePack(callback, IntPtr.Zero); ov_native->OffsetLow = unchecked ((int)(alignedSourceAddress & 0xFFFFFFFF)); ov_native->OffsetHigh = unchecked ((int)((alignedSourceAddress >> 32) & 0xFFFFFFFF)); if (values[pageIndex] == null) { callback(2, 0, ov_native); } else { long physicalAddress = GetPhysicalAddress(logicalAddress); Utility.Copy((byte *)physicalAddress, (byte *)alignedDestinationAddress, (int)aligned_read_length); callback(0, aligned_read_length, ov_native); } }
public unsafe void Execute(TcpSocketSendResult target) { target.Pin(buffer.Data); Overlapped overlapped = new Overlapped { AsyncResult = target }; NativeOverlapped *native = overlapped.UnsafePack(null, null); IntPtr reference = Marshal.UnsafeAddrOfPinnedArrayElement(buffer.Data, buffer.Offset); TcpSocketInterop.WSABuffer data = new TcpSocketInterop.WSABuffer { length = buffer.Count, buffer = reference }; int written; uint result = TcpSocketInterop.WSASend(handle, &data, 1, out written, 0, native, IntPtr.Zero); uint error = TcpSocketInterop.WSAGetLastError(); if (result != 0 && error != 997) { target.Fail(error); } }
public void WriteAsync(IntPtr alignedSourceAddress, ulong alignedDestinationAddress, uint numBytesToWrite, IOCompletionCallback callback, IAsyncResult asyncResult) { long logicalAddress = (long)alignedDestinationAddress; long page = logicalAddress >> PageSizeBits; int pageIndex = (int)(page % BufferSize); Debug.Assert(page == pageIndex); if (values[pageIndex] == null) { // Allocate a new page AllocatePage(pageIndex); } else { //Clear an old used page Array.Clear(values[pageIndex], 0, values[pageIndex].Length); } long physicalAddress = GetPhysicalAddress(logicalAddress); Utility.Copy((byte *)alignedSourceAddress, (byte *)physicalAddress, (int)numBytesToWrite); Overlapped ov = new Overlapped(0, 0, IntPtr.Zero, asyncResult); NativeOverlapped *ov_native = ov.UnsafePack(callback, IntPtr.Zero); ov_native->OffsetLow = unchecked ((int)(alignedDestinationAddress & 0xFFFFFFFF)); ov_native->OffsetHigh = unchecked ((int)((alignedDestinationAddress >> 32) & 0xFFFFFFFF)); callback(0, numBytesToWrite, ov_native); }
public unsafe void Callback(IAsyncResult result) { if (errorCode == 0) { try { logHandle.EndRead(result); fixed(void *source = memory.buffer) { Buffer.MemoryCopy(source, (void *)destinationAddress, readLength, readLength); } } catch (IOException e) { errorCode = (uint)(e.HResult & 0x0000FFFF); } catch { // Non-IO exception; assign error code of max value errorCode = uint.MaxValue; } } memory.Return(); Overlapped ov = new Overlapped(0, 0, IntPtr.Zero, asyncResult); callback(errorCode, 0, ov.UnsafePack(callback, IntPtr.Zero)); }
public unsafe void Execute(TcpSocketConnectResult target) { int sent; IntPtr ptr = IntPtr.Zero; Guid guid = new Guid("{0x25a207b9,0x0ddf3,0x4660,{0x8e,0xe9,0x76,0xe5,0x8c,0x74,0x06,0x3e}}"); int result = TcpSocketInterop.WSAIoctl(handle, unchecked ((int)0xC8000006), ref guid, sizeof(Guid), out ptr, sizeof(IntPtr), out sent, IntPtr.Zero, IntPtr.Zero); if (result != 0) { throw new Exception(); } byte[] address = endpoint.Address.GetAddressBytes(); byte[] data = { 0x02, 0x00, (byte)(endpoint.Port / 256), (byte)(endpoint.Port % 256), address[0], address[1], address[2], address[3], 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; TcpSocketInterop.ConnectExDelegate connectex = (TcpSocketInterop.ConnectExDelegate)Marshal.GetDelegateForFunctionPointer(ptr, typeof(TcpSocketInterop.ConnectExDelegate)); Overlapped overlapped = new Overlapped { AsyncResult = target }; NativeOverlapped *native = overlapped.UnsafePack(null, null); target.Pin(data); worker.Add(handle); IntPtr buffer = Marshal.UnsafeAddrOfPinnedArrayElement(data, 0); result = connectex.Invoke(handle, buffer, data.Length, IntPtr.Zero, 0, out sent, native); uint error = TcpSocketInterop.GetLastError(); if (result == 0 && error != 997) { target.Fail(error); } }
/// <summary> /// /// </summary> /// <param name="sourceAddress"></param> /// <param name="segmentId"></param> /// <param name="destinationAddress"></param> /// <param name="numBytesToWrite"></param> /// <param name="callback"></param> /// <param name="asyncResult"></param> public override unsafe void WriteAsync(IntPtr sourceAddress, int segmentId, ulong destinationAddress, uint numBytesToWrite, IOCompletionCallback callback, IAsyncResult asyncResult) { var logHandle = GetOrAddHandle(segmentId); Overlapped ov = new Overlapped(0, 0, IntPtr.Zero, asyncResult); NativeOverlapped *ovNative = ov.UnsafePack(callback, IntPtr.Zero); ovNative->OffsetLow = unchecked ((int)(destinationAddress & 0xFFFFFFFF)); ovNative->OffsetHigh = unchecked ((int)((destinationAddress >> 32) & 0xFFFFFFFF)); bool result = Native32.WriteFile(logHandle, sourceAddress, numBytesToWrite, out uint bytesWritten, ovNative); if (!result) { int error = Marshal.GetLastWin32Error(); if (error != Native32.ERROR_IO_PENDING) { Overlapped.Unpack(ovNative); Overlapped.Free(ovNative); throw new Exception("Error writing to log file: " + error); } } }
/// <summary> /// /// </summary> /// <param name="segmentId"></param> /// <param name="sourceAddress"></param> /// <param name="destinationAddress"></param> /// <param name="readLength"></param> /// <param name="callback"></param> /// <param name="asyncResult"></param> public override unsafe void ReadAsync(int segmentId, ulong sourceAddress, IntPtr destinationAddress, uint readLength, IOCompletionCallback callback, IAsyncResult asyncResult) { var logHandle = GetOrAddHandle(segmentId); Overlapped ov = new Overlapped(0, 0, IntPtr.Zero, asyncResult); NativeOverlapped *ovNative = ov.UnsafePack(callback, IntPtr.Zero); ovNative->OffsetLow = unchecked ((int)((ulong)sourceAddress & 0xFFFFFFFF)); ovNative->OffsetHigh = unchecked ((int)(((ulong)sourceAddress >> 32) & 0xFFFFFFFF)); bool result = Native32.ReadFile(logHandle, destinationAddress, readLength, out uint bytesRead, ovNative); if (!result) { int error = Marshal.GetLastWin32Error(); if (error != Native32.ERROR_IO_PENDING) { Overlapped.Unpack(ovNative); Overlapped.Free(ovNative); throw new Exception("Error reading from log file: " + error); } } }
/// <summary> /// Create instance, automatically allocates NativeOverlapped structure /// </summary> /// <param name="callback">User specified callback</param> /// <param name="state">User specified state</param> /// <param name="fileOffset">Start position</param> /// <param name="userData">An object or array of objects representing the input or output buffer for the operation. Buffer is pinned until object is disposed.</param> public AsyncJob(AsyncCallback callback, object state, UInt64 fileOffset, object userData) { _callback = callback; _state = state; Overlapped ov = new Overlapped(unchecked ((int)(fileOffset & 0xFFFFFFFF)), unchecked ((int)((fileOffset >> 32) & 0xFFFFFFFF)), IntPtr.Zero, this); unsafe { _nativeOverlapped = ov.UnsafePack(completionCallback, userData); } }
public unsafe LogWriterWindows(string fileName, uint chunkSize, uint maxChunksPerWrite, bool appendOpen = false) { //Console.WriteLine("64-bitness: " + Environment.Is64BitProcess); _lastError = 0; _allocationUnit = 1024 * 1024 * 512; _allocations = 0; _writesFinished = 1; _writesFinishedQ = new AsyncQueue <int>(); _bufSize = maxChunksPerWrite * chunkSize + sectorSize; _buf = new BytePtrWrapper(); var tempBuf = new byte[_bufSize]; _buf._handle = GCHandle.Alloc(tempBuf, GCHandleType.Pinned); _buf._ptr = (byte *)_buf._handle.AddrOfPinnedObject(); _IOThreadInfo = new IOThreadState[maxChunksPerWrite]; _IOThreadInfoAsync = new IOThreadState[maxChunksPerWrite]; var filePointer = new LocalStorageDevice(fileName, true, false, true); for (int i = 0; i < maxChunksPerWrite; i++) { var job = new AsyncJob(); var jobAsync = new AsyncJob(); var ov = new Overlapped(0, 0, IntPtr.Zero, job); var ovAsync = new Overlapped(0, 0, IntPtr.Zero, jobAsync); NativeOverlapped *ov_native = ov.UnsafePack(FlushCallback, IntPtr.Zero); NativeOverlapped *ov_nativeAsync = ovAsync.UnsafePack(FlushAsyncCallBack, IntPtr.Zero); Thread.Sleep(10); var myIOThreadState = new IOThreadState(); myIOThreadState.filePointer = filePointer; myIOThreadState.ov_native = ov_native; _IOThreadInfo[i] = myIOThreadState; var myIOThreadStateAsync = new IOThreadState(); myIOThreadStateAsync.filePointer = filePointer; myIOThreadStateAsync.ov_native = ov_nativeAsync; _IOThreadInfoAsync[i] = myIOThreadStateAsync; } _bufBytesOccupied = 0; _chunkSize = chunkSize; _maxChunksPerWrite = maxChunksPerWrite; if (!appendOpen) { _fileSize = 0; _filePos = 0; } else { // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!inefficient workaround until Badrish adds a filesize call using (var fileReader = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { _fileSize = _filePos = (ulong)fileReader.Length; } } _outstandingWrites = 0; }
static unsafe void Main(string[] args) { // create completion port var completionPortHandle = Interop.CreateIoCompletionPort(new IntPtr(-1), IntPtr.Zero, 0, 0); ThreadLogger.Log("Completion port handle: {0}", completionPortHandle); var completionPortThread = new Thread(() => new IOCompletionWorker().Start(completionPortHandle)) { IsBackground = true }; completionPortThread.Start(); const uint Flags = 128 | (uint)1 << 30; var fileHandle = Interop.CreateFile("test.txt", (uint)1 << 31, 0, IntPtr.Zero, 3, /*FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED */ Flags, IntPtr.Zero); ThreadLogger.Log("File handle: {0}", fileHandle); Interop.CreateIoCompletionPort( fileHandle, completionPortHandle, (uint)fileHandle.ToInt64(), 0); ThreadLogger.Log("Associated file handle with completion port"); var readBuffer = new byte[1024]; uint bytesRead; var overlapped = new Overlapped { AsyncResult = new FileReadAsyncResult() { ReadCallback = (bytesCount, buffer) => { var contentRead = Encoding.UTF8.GetString(buffer, 0, (int)bytesCount); ThreadLogger.Log(contentRead); }, Buffer = readBuffer } }; NativeOverlapped *nativeOverlapped = overlapped.UnsafePack(null, readBuffer); ThreadLogger.Log("Before read in main thread"); Interop.ReadFile(fileHandle, readBuffer, (uint)readBuffer.Length, out bytesRead, nativeOverlapped); ThreadLogger.Log("After read in main thread"); Console.ReadLine(); }
public unsafe void WriteAsync(IntPtr alignedSourceAddress, ulong alignedDestinationAddress, uint numBytesToWrite, IOCompletionCallback callback, IAsyncResult asyncResult) { Overlapped ov = new Overlapped(0, 0, IntPtr.Zero, asyncResult); NativeOverlapped *ov_native = ov.UnsafePack(callback, IntPtr.Zero); ov_native->OffsetLow = unchecked ((int)(alignedDestinationAddress & 0xFFFFFFFF)); ov_native->OffsetHigh = unchecked ((int)((alignedDestinationAddress >> 32) & 0xFFFFFFFF)); callback(0, numBytesToWrite, ov_native); }
internal OverlappedCache(Overlapped overlapped, object pinnedObjects, IOCompletionCallback callback, bool alreadyTriedCast) { m_Overlapped = overlapped; m_PinnedObjects = pinnedObjects; m_PinnedObjectsArray = alreadyTriedCast ? null : NclConstants.EmptyObjectArray; unsafe { m_NativeOverlapped = (IntPtr)overlapped.UnsafePack(callback, pinnedObjects); } }
internal OverlappedCache(Overlapped overlapped, object[] pinnedObjectsArray, IOCompletionCallback callback) { m_Overlapped = overlapped; m_PinnedObjects = pinnedObjectsArray; m_PinnedObjectsArray = pinnedObjectsArray; unsafe { m_NativeOverlapped = (IntPtr)overlapped.UnsafePack(callback, pinnedObjectsArray); } }
public unsafe void ReadAsync(int segmentId, ulong alignedSourceAddress, IntPtr alignedDestinationAddress, uint aligned_read_length, IOCompletionCallback callback, IAsyncResult asyncResult) { alignedSourceAddress = ((ulong)segmentId << _segmentSizeBits) | alignedSourceAddress; Overlapped ov = new Overlapped(0, 0, IntPtr.Zero, asyncResult); NativeOverlapped *ov_native = ov.UnsafePack(callback, IntPtr.Zero); ov_native->OffsetLow = unchecked ((int)(alignedSourceAddress & 0xFFFFFFFF)); ov_native->OffsetHigh = unchecked ((int)((alignedSourceAddress >> 32) & 0xFFFFFFFF)); callback(0, aligned_read_length, ov_native); }
/// <summary> /// <see cref="IDevice.WriteAsync(IntPtr, int, ulong, uint, IOCompletionCallback, IAsyncResult)"/> /// </summary> /// <param name="sourceAddress"></param> /// <param name="segmentId"></param> /// <param name="destinationAddress"></param> /// <param name="numBytesToWrite"></param> /// <param name="callback"></param> /// <param name="asyncResult"></param> public unsafe override void WriteAsync(IntPtr sourceAddress, int segmentId, ulong destinationAddress, uint numBytesToWrite, IOCompletionCallback callback, IAsyncResult asyncResult) { // Starts off in one, in order to prevent some issued writes calling the callback before all parallel writes are issued. var countdown = new CountdownEvent(1); long currentWriteStart = (long)destinationAddress; long writeEnd = currentWriteStart + (long)numBytesToWrite; uint aggregateErrorCode = 0; while (currentWriteStart < writeEnd) { long newStart = partitions.MapRange(currentWriteStart, writeEnd, out int shard, out long shardStartAddress, out long shardEndAddress); ulong writeOffset = (ulong)currentWriteStart - destinationAddress; // Indicate that there is one more task to wait for countdown.AddCount(); // Because more than one device can return with an error, it is important that we remember the most recent error code we saw. (It is okay to only // report one error out of many. It will be as if we failed on that error and cancelled all other reads, even though we issue reads in parallel and // wait until all of them are complete in the implementation) // Can there be races on async result as we issue writes or reads in parallel? partitions.Devices[shard].WriteAsync(IntPtr.Add(sourceAddress, (int)writeOffset), segmentId, (ulong)shardStartAddress, (uint)(shardEndAddress - shardStartAddress), (e, n, o) => { // TODO: Check if it is incorrect to ignore o if (e != 0) { aggregateErrorCode = e; } if (countdown.Signal()) { callback(aggregateErrorCode, n, o); countdown.Dispose(); } else { Overlapped.Free(o); } }, asyncResult); currentWriteStart = newStart; } // TODO: Check if overlapped wrapper is handled correctly if (countdown.Signal()) { Overlapped ov = new Overlapped(0, 0, IntPtr.Zero, asyncResult); NativeOverlapped *ovNative = ov.UnsafePack(callback, IntPtr.Zero); callback(aggregateErrorCode, numBytesToWrite, ovNative); countdown.Dispose(); } }
public unsafe void Callback(IAsyncResult result) { fixed(void *source = memory.buffer) { Buffer.MemoryCopy(source, (void *)destinationAddress, readLength, readLength); } memory.Return(); Overlapped ov = new Overlapped(0, 0, IntPtr.Zero, asyncResult); callback(0, 0, ov.UnsafePack(callback, IntPtr.Zero)); }
// ReSharper disable once SuggestVarOrType_Elsewhere private static unsafe void WatchFolderForChanges( object wrapper, ISwatcherConfig config, IWindowsFacade windowsFacade, SafeFileHandle directoryHandle) { var result = new SwatcherAsyncResult { Buffer = new byte[DefaultBufferSize] }; var overlapped = new Overlapped { AsyncResult = result }; //the first parameter is null because we're not using IO completion callbacks; they're too slow. //we're taking the byte array from our empty byte array and passing that as user data to the overlapped. var overlappedPointer = overlapped.UnsafePack(null, result.Buffer); var success = false; try { //now we wrap this section in a fixed block to pin it to the original address. //we cannot have it move because the OS will write information about the changes //into this byte array. fixed(byte *bufferPointer = result.Buffer) { var bytesReturned = 0; var bufferHandle = new HandleRef(result, (IntPtr)bufferPointer); var isRecursive = Convert.ToInt32(config.IsRecursive); //because we're using IO completion ports, we pass our overlapped pointer into this unmanaged //call. when a change has been received, the OS will callback via GetQueuedCompletionStatus //passing the overlapped pointer (which has our IAsyncResult/byte array) back to us. success = windowsFacade.ReadDirectoryChangesW( directoryHandle, bufferHandle, DefaultBufferSize, isRecursive, (int)config.NotificationTypes, bytesReturned, overlappedPointer, SafeLocalMemHandle.Empty); //in this usage of ReadDirectoryChangesW, we should *always* get 0 bytes returned. if (bytesReturned != 0) { Debugger.Break(); } } } finally { //if success is false, our directory handle has likely become invalid. attempt to re-establish it. if (!success) { Debugger.Break(); //before doing anything else, cleanup here to prevent memory leaks. Overlapped.Free(overlappedPointer); } } }
/// <summary> /// <see cref="IDevice.ReadAsync(int, ulong, IntPtr, uint, IOCompletionCallback, IAsyncResult)"/> /// </summary> /// <param name="segmentId"></param> /// <param name="sourceAddress"></param> /// <param name="destinationAddress"></param> /// <param name="readLength"></param> /// <param name="callback"></param> /// <param name="asyncResult"></param> public unsafe override void ReadAsync(int segmentId, ulong sourceAddress, IntPtr destinationAddress, uint readLength, IOCompletionCallback callback, IAsyncResult asyncResult) { // Starts off in one, in order to prevent some issued writes calling the callback before all parallel writes are issued. var countdown = new CountdownEvent(1); long currentReadStart = (long)sourceAddress; long readEnd = currentReadStart + readLength; uint aggregateErrorCode = 0; while (currentReadStart < readEnd) { long newStart = partitions.MapRange(currentReadStart, readEnd, out int shard, out long shardStartAddress, out long shardEndAddress); ulong writeOffset = (ulong)currentReadStart - sourceAddress; // Because more than one device can return with an error, it is important that we remember the most recent error code we saw. (It is okay to only // report one error out of many. It will be as if we failed on that error and cancelled all other reads, even though we issue reads in parallel and // wait until all of them are complete in the implementation) // TODO(Tianyu): Can there be races on async result as we issue writes or reads in parallel? countdown.AddCount(); partitions.Devices[shard].ReadAsync(segmentId, (ulong)shardStartAddress, IntPtr.Add(destinationAddress, (int)writeOffset), (uint)(shardEndAddress - shardStartAddress), (e, n, o) => { // TODO(Tianyu): this is incorrect if returned "bytes" written is allowed to be less than requested like POSIX. if (e != 0) { aggregateErrorCode = e; } if (countdown.Signal()) { callback(aggregateErrorCode, n, o); countdown.Dispose(); } else { Overlapped.Free(o); } }, asyncResult); currentReadStart = newStart; } // TODO(Tianyu): What do for the dumb overlapped wrapper... if (countdown.Signal()) { Overlapped ov = new Overlapped(0, 0, IntPtr.Zero, asyncResult); NativeOverlapped *ovNative = ov.UnsafePack(callback, IntPtr.Zero); callback(aggregateErrorCode, readLength, ovNative); countdown.Dispose(); } }
private unsafe CancellationToken CreateToken(ulong connectionId) { // Create a nativeOverlapped callback so we can register for disconnect callback var overlapped = new Overlapped(); var cts = new CancellationTokenSource(); CancellationToken returnToken = cts.Token; NativeOverlapped *nativeOverlapped = overlapped.UnsafePack( (errorCode, numBytes, overlappedPtr) => { // Free the overlapped Overlapped.Free(overlappedPtr); if (errorCode != NativeMethods.HttpErrors.NO_ERROR) { LogHelper.LogException(_logger, "IOCompletionCallback", new Win32Exception((int)errorCode)); } // Pull the token out of the list and Cancel it. ConnectionCancellation cancellation; _connectionCancellationTokens.TryRemove(connectionId, out cancellation); bool success = ThreadPool.UnsafeQueueUserWorkItem(CancelToken, cts); Debug.Assert(success, "Unable to queue disconnect notification."); }, null); uint hr = NativeMethods.HttpWaitForDisconnectEx(_requestQueueHandle, connectionId, 0, nativeOverlapped); if (hr != NativeMethods.HttpErrors.ERROR_IO_PENDING && hr != NativeMethods.HttpErrors.NO_ERROR) { // We got an unknown result, assume the connection has been closed. Overlapped.Free(nativeOverlapped); ConnectionCancellation cancellation; _connectionCancellationTokens.TryRemove(connectionId, out cancellation); LogHelper.LogException(_logger, "HttpWaitForDisconnectEx", new Win32Exception((int)hr)); cts.Cancel(); } if (hr == NativeMethods.HttpErrors.NO_ERROR && SkipIOCPCallbackOnSuccess) { // IO operation completed synchronously - callback won't be called to signal completion Overlapped.Free(nativeOverlapped); ConnectionCancellation cancellation; _connectionCancellationTokens.TryRemove(connectionId, out cancellation); cts.Cancel(); } return(returnToken); }
unsafe private FileStreamAsyncResult BeginWriteCore(byte[] bytes, int offset, int numBytes, AsyncCallback userCallback, Object stateObject) { Contract.Assert(!_handle.IsClosed, "!_handle.IsClosed"); Contract.Assert(CanWrite, "CanWrite"); Contract.Assert(bytes != null, "bytes != null"); Contract.Assert(_readPos == _readLen, "_readPos == _readLen"); Contract.Assert(_isAsync, "BeginWriteCore doesn't work on synchronous file streams!"); Contract.Assert(offset >= 0, "offset is negative"); Contract.Assert(numBytes >= 0, "numBytes is negative"); // Create and store async stream class library specific data in the // async result FileStreamAsyncResult asyncResult = new FileStreamAsyncResult(); asyncResult._handle = _handle; asyncResult._userCallback = userCallback; asyncResult._userStateObject = stateObject; asyncResult._isWrite = true; // For Synchronous IO, I could go with either a callback and using // the managed Monitor class, or I could create a handle and wait on it. ManualResetEvent waitHandle = new ManualResetEvent(false); asyncResult._waitHandle = waitHandle; // Create a managed overlapped class // We will set the file offsets later Overlapped overlapped = new Overlapped(0, 0, IntPtr.Zero, asyncResult); // Pack the Overlapped class, and store it in the async result NativeOverlapped* intOverlapped; if (userCallback != null) intOverlapped = overlapped.Pack(IOCallback, bytes); else intOverlapped = overlapped.UnsafePack(null, bytes); asyncResult._overlapped = intOverlapped; if (CanSeek) { // Make sure we set the length of the file appropriately. long len = Length; //Console.WriteLine("BeginWrite - Calculating end pos. pos: "+pos+" len: "+len+" numBytes: "+numBytes); // Make sure we are writing to the position that we think we are if (_exposedHandle) VerifyOSHandlePosition(); if (_pos + numBytes > len) { //Console.WriteLine("BeginWrite - Setting length to: "+(pos + numBytes)); SetLengthCore(_pos + numBytes); } // Now set the position to read from in the NativeOverlapped struct // For pipes, we should leave the offset fields set to 0. intOverlapped->OffsetLow = (int)_pos; intOverlapped->OffsetHigh = (int)(_pos>>32); // When using overlapped IO, the OS is not supposed to // touch the file pointer location at all. We will adjust it // ourselves. This isn't threadsafe. // SeekCore(numBytes, SeekOrigin.Current); } //Console.WriteLine("BeginWrite finishing. pos: "+pos+" numBytes: "+numBytes+" _pos: "+_pos+" Position: "+Position); int hr = 0; // queue an async WriteFile operation and pass in a packed overlapped int r = WriteFileNative(_handle, bytes, offset, numBytes, intOverlapped, out hr); // WriteFile, the OS version, will return 0 on failure. But // my WriteFileNative wrapper returns -1. My wrapper will return // the following: // On error, r==-1. // On async requests that are still pending, r==-1 w/ hr==ERROR_IO_PENDING // On async requests that completed sequentially, r==0 // You will NEVER RELIABLY be able to get the number of bytes // written back from this call when using overlapped IO! You must // not pass in a non-null lpNumBytesWritten to WriteFile when using // overlapped structures! This is ByDesign NT behavior. if (r==-1 && numBytes!=-1) { //Console.WriteLine("WriteFile returned 0; Write will complete asynchronously (if hr==3e5) hr: 0x{0:x}", hr); // For pipes, when they are closed on the other side, they will come here. if (hr == ERROR_NO_DATA) { // Not an error, but EOF. AsyncFSCallback will NOT be // called. Call the user callback here. asyncResult.CallUserCallback(); // EndWrite will free the Overlapped struct correctly. } else if (hr != ERROR_IO_PENDING) { if (!_handle.IsClosed && CanSeek) // Update Position - It could be anywhere. SeekCore(0, SeekOrigin.Current); if (hr == ERROR_HANDLE_EOF) __Error.EndOfFile(); else __Error.WinIOError(hr, String.Empty); } } else { // Due to a workaround for a race condition in NT's ReadFile & // WriteFile routines, we will always be returning 0 from WriteFileNative // when we do async IO instead of the number of bytes written, // irregardless of whether the operation completed // synchronously or asynchronously. We absolutely must not // set asyncResult._numBytes here, since will never have correct // results. //Console.WriteLine("WriteFile returned: "+r+" (0x"+Int32.Format(r, "x")+") The IO completed synchronously, but the user callback was called on another thread."); } return asyncResult; }
unsafe private FileStreamAsyncResult BeginReadCore(byte[] bytes, int offset, int numBytes, AsyncCallback userCallback, Object stateObject, int numBufferedBytesRead) { Contract.Assert(!_handle.IsClosed, "!_handle.IsClosed"); Contract.Assert(CanRead, "CanRead"); Contract.Assert(bytes != null, "bytes != null"); Contract.Assert(_writePos == 0, "_writePos == 0"); Contract.Assert(_isAsync, "BeginReadCore doesn't work on synchronous file streams!"); Contract.Assert(offset >= 0, "offset is negative"); Contract.Assert(numBytes >= 0, "numBytes is negative"); // Create and store async stream class library specific data in the // async result FileStreamAsyncResult asyncResult = new FileStreamAsyncResult(); asyncResult._handle = _handle; asyncResult._userCallback = userCallback; asyncResult._userStateObject = stateObject; asyncResult._isWrite = false; // Must set this here to ensure all the state on the IAsyncResult // object is set before we call ReadFile, which gives the OS an // opportunity to run our callback (including the user callback & // the call to EndRead) before ReadFile has returned. asyncResult._numBufferedBytes = numBufferedBytesRead; // For Synchronous IO, I could go with either a callback and using // the managed Monitor class, or I could create a handle and wait on it. ManualResetEvent waitHandle = new ManualResetEvent(false); asyncResult._waitHandle = waitHandle; // Create a managed overlapped class // We will set the file offsets later Overlapped overlapped = new Overlapped(0, 0, IntPtr.Zero, asyncResult); // Pack the Overlapped class, and store it in the async result NativeOverlapped* intOverlapped; if (userCallback != null) intOverlapped = overlapped.Pack(IOCallback, bytes); else intOverlapped = overlapped.UnsafePack(null, bytes); asyncResult._overlapped = intOverlapped; // Calculate position in the file we should be at after the read is done if (CanSeek) { long len = Length; // Make sure we are reading from the position that we think we are if (_exposedHandle) VerifyOSHandlePosition(); if (_pos + numBytes > len) { if (_pos <= len) numBytes = (int) (len - _pos); else numBytes = 0; } // Now set the position to read from in the NativeOverlapped struct // For pipes, we should leave the offset fields set to 0. intOverlapped->OffsetLow = unchecked((int)_pos); intOverlapped->OffsetHigh = (int)(_pos>>32); // When using overlapped IO, the OS is not supposed to // touch the file pointer location at all. We will adjust it // ourselves. This isn't threadsafe. // WriteFile should not update the file pointer when writing // in overlapped mode, according to MSDN. But it does update // the file pointer when writing to a UNC path! // So changed the code below to seek to an absolute // location, not a relative one. ReadFile seems consistent though. SeekCore(numBytes, SeekOrigin.Current); } // queue an async ReadFile operation and pass in a packed overlapped int hr = 0; int r = ReadFileNative(_handle, bytes, offset, numBytes, intOverlapped, out hr); // ReadFile, the OS version, will return 0 on failure. But // my ReadFileNative wrapper returns -1. My wrapper will return // the following: // On error, r==-1. // On async requests that are still pending, r==-1 w/ hr==ERROR_IO_PENDING // on async requests that completed sequentially, r==0 // You will NEVER RELIABLY be able to get the number of bytes // read back from this call when using overlapped structures! You must // not pass in a non-null lpNumBytesRead to ReadFile when using // overlapped structures! This is by design NT behavior. if (r==-1 && numBytes!=-1) { // For pipes, when they hit EOF, they will come here. if (hr == ERROR_BROKEN_PIPE) { // Not an error, but EOF. AsyncFSCallback will NOT be // called. Call the user callback here. // We clear the overlapped status bit for this special case. // Failure to do so looks like we are freeing a pending overlapped later. intOverlapped->InternalLow = IntPtr.Zero; asyncResult.CallUserCallback(); // EndRead will free the Overlapped struct correctly. } else if (hr != ERROR_IO_PENDING) { if (!_handle.IsClosed && CanSeek) // Update Position - It could be anywhere. SeekCore(0, SeekOrigin.Current); if (hr == ERROR_HANDLE_EOF) __Error.EndOfFile(); else __Error.WinIOError(hr, String.Empty); } } else { // Due to a workaround for a race condition in NT's ReadFile & // WriteFile routines, we will always be returning 0 from ReadFileNative // when we do async IO instead of the number of bytes read, // irregardless of whether the operation completed // synchronously or asynchronously. We absolutely must not // set asyncResult._numBytes here, since will never have correct // results. //Console.WriteLine("ReadFile returned: "+r+" (0x"+Int32.Format(r, "x")+") The IO completed synchronously, but the user callback was called on a separate thread"); } return asyncResult; }