private void AsyncReadPageCallback<TContext>(uint errorCode, uint numBytes, NativeOverlapped* overlap) { if (errorCode != 0) { Trace.TraceError("OverlappedStream GetQueuedCompletionStatus error: {0}", errorCode); } PageAsyncReadResult<TContext> result = (PageAsyncReadResult<TContext>)Overlapped.Unpack(overlap).AsyncResult; if (Interlocked.Decrement(ref result.count) == 1) { // We will be issuing another I/O, so free this overlap Overlapped.Free(overlap); long ptr = (long)pointers[result.page % BufferSize]; // Correct for page 0 of HLOG if (result.page == 0) ptr += Constants.kFirstValidAddress; long minObjAddress = long.MaxValue; long maxObjAddress = long.MinValue; while (ptr < (long)pointers[result.page % BufferSize] + PageSize) { if (!Layout.GetInfo(ptr)->Invalid) { if (Key.HasObjectsToSerialize()) { Key* key = Layout.GetKey(ptr); var addr = ((AddressInfo*)key)->Address; if (addr < minObjAddress) minObjAddress = addr; addr += ((AddressInfo*)key)->Size; if (addr > maxObjAddress) maxObjAddress = addr; } if (Value.HasObjectsToSerialize()) { Value* value = Layout.GetValue(ptr); var addr = ((AddressInfo*)value)->Address; if (addr < minObjAddress) minObjAddress = addr; addr += ((AddressInfo*)value)->Size; if (addr > maxObjAddress) maxObjAddress = addr; } } ptr += Layout.GetPhysicalSize(ptr); } // Object log fragment should be aligned by construction Debug.Assert(minObjAddress % sectorSize == 0); var to_read = (int)(maxObjAddress - minObjAddress); var objBuffer = ioBufferPool.Get(to_read); result.freeBuffer1 = objBuffer; var alignedLength = (to_read + (sectorSize - 1)) & ~(sectorSize - 1); // Request objects from objlog result.objlogDevice.ReadAsync( (int)(result.page >> (LogSegmentSizeBits-LogPageSizeBits)), (ulong)minObjAddress, (IntPtr)objBuffer.aligned_pointer, (uint)alignedLength, AsyncReadPageCallback<TContext>, result); } else { // Load objects from buffer into memory long ptr = (long)pointers[result.page % BufferSize]; // Correct for page 0 of HLOG if (result.page == 0) ptr += Constants.kFirstValidAddress; MemoryStream ms = new MemoryStream(result.freeBuffer1.buffer); ms.Seek(result.freeBuffer1.offset + result.freeBuffer1.valid_offset, SeekOrigin.Begin); while (ptr < (long)pointers[result.page % BufferSize] + PageSize) { if (!Layout.GetInfo(ptr)->Invalid) { if (Key.HasObjectsToSerialize()) { Key.Deserialize(Layout.GetKey(ptr), ms); } if (Value.HasObjectsToSerialize()) { Value.Deserialize(Layout.GetValue(ptr), ms); } } ptr += Layout.GetPhysicalSize(ptr); } ms.Dispose(); result.Free(); // Call the "real" page read callback result.callback(errorCode, numBytes, overlap); } }
unsafe private static void AsyncPSCallback(uint errorCode, uint numBytes, NativeOverlapped* pOverlapped) { // Unpack overlapped Overlapped overlapped = Overlapped.Unpack(pOverlapped); // Free the overlapped struct in EndRead/EndWrite. // Extract async result from overlapped PipeStreamAsyncResult asyncResult = (PipeStreamAsyncResult)overlapped.AsyncResult; asyncResult._numBytes = (int)numBytes; // Allow async read to finish if (!asyncResult._isWrite) { if (errorCode == Interop.mincore.Errors.ERROR_BROKEN_PIPE || errorCode == Interop.mincore.Errors.ERROR_PIPE_NOT_CONNECTED || errorCode == Interop.mincore.Errors.ERROR_NO_DATA) { errorCode = 0; numBytes = 0; } } // For message type buffer. if (errorCode == Interop.mincore.Errors.ERROR_MORE_DATA) { errorCode = 0; asyncResult._isMessageComplete = false; } else { asyncResult._isMessageComplete = true; } asyncResult._errorCode = (int)errorCode; // Call the user-provided callback. It can and often should // call EndRead or EndWrite. There's no reason to use an async // delegate here - we're already on a threadpool thread. // IAsyncResult's completedSynchronously property must return // false here, saying the user callback was called on another thread. asyncResult._completedSynchronously = false; asyncResult._isComplete = true; // The OS does not signal this event. We must do it ourselves. ManualResetEvent wh = asyncResult._waitHandle; if (wh != null) { Debug.Assert(!wh.GetSafeWaitHandle().IsClosed, "ManualResetEvent already closed!"); bool r = wh.Set(); Debug.Assert(r, "ManualResetEvent::Set failed!"); if (!r) { throw Win32Marshal.GetExceptionForLastWin32Error(); } } AsyncCallback callback = asyncResult._userCallback; if (callback != null) { callback(asyncResult); } }
protected void AsyncGetFromDiskCallback( uint errorCode, uint numBytes, NativeOverlapped *overlap) { if (errorCode != 0) { Trace.TraceError("OverlappedStream GetQueuedCompletionStatus error: {0}", errorCode); } var result = (AsyncGetFromDiskResult <AsyncIOContext>)Overlapped.Unpack(overlap).AsyncResult; Interlocked.Decrement(ref numPendingReads); var ctx = result.context; var record = ctx.record.GetValidPointer(); if (Layout.HasTotalRecord(record, ctx.record.available_bytes, out int requiredBytes)) { //We have the complete record. if (RetrievedObjects(record, ctx)) { if (Key.Equals(ctx.key, Layout.GetKey((long)record))) { //The keys are same, so I/O is complete // ctx.record = result.record; ctx.callbackQueue.Add(ctx); } else { var oldAddress = ctx.logicalAddress; //keys are not same. I/O is not complete ctx.logicalAddress = ((RecordInfo *)record)->PreviousAddress; if (ctx.logicalAddress != Constants.kInvalidAddress) { // Delete key, value, record if (Key.HasObjectsToSerialize()) { var physicalAddress = (long)ctx.record.GetValidPointer(); Key.Free(Layout.GetKey(physicalAddress)); } if (Value.HasObjectsToSerialize()) { var physicalAddress = (long)ctx.record.GetValidPointer(); Value.Free(Layout.GetValue(physicalAddress)); } ctx.record.Return(); AsyncGetFromDisk(ctx.logicalAddress, requiredBytes, AsyncGetFromDiskCallback, ctx); } else { ctx.callbackQueue.Add(ctx); } } } } else { ctx.record.Return(); AsyncGetFromDisk(ctx.logicalAddress, requiredBytes, AsyncGetFromDiskCallback, ctx); } Overlapped.Free(overlap); }
/// <include file='doc\FileSystemWatcher.uex' path='docs/doc[@for="FileSystemWatcher.CompletionStatusChanged"]/*' /> /// <devdoc> /// Callback from thread pool. /// </devdoc> /// <internalonly/> private unsafe void CompletionStatusChanged(uint errorCode, uint numBytes, NativeOverlapped *overlappedPointer) { Overlapped overlapped = Overlapped.Unpack(overlappedPointer); ulong bufferPtrTemp = ((ulong)overlapped.OffsetHigh) << 32; bufferPtrTemp = bufferPtrTemp | (0x00000000ffffffff & (ulong)overlapped.OffsetLow); IntPtr bufferPtr = (IntPtr)bufferPtrTemp; try { if (stopListening) { return; } lock (this) { if (errorCode != 0) { if (errorCode == 995 /* ERROR_OPERATION_ABORTED */) { //Win2000 inside a service the first completion status is false //cannot return without monitoring again. //NOTE, stefanph: Because this return statement is inside a try/finally block, //the finally block will execute. It does restart the monitoring. return; } else { OnError(new ErrorEventArgs(new Win32Exception((int)errorCode))); EnableRaisingEvents = false; return; } } if (numBytes == 0) { NotifyInternalBufferOverflowEvent(); } else // Else, parse each of them and notify appropriate delegates /****** * Format for the buffer is the following C struct: * * typedef struct _FILE_NOTIFY_INFORMATION { * DWORD NextEntryOffset; * DWORD Action; * DWORD FileNameLength; * WCHAR FileName[1]; * } FILE_NOTIFY_INFORMATION; * * NOTE1: FileNameLength is length in bytes. * NOTE2: The Filename is a Unicode string that's NOT NULL terminated. * NOTE3: A NextEntryOffset of zero means that it's the last entry *******/ // Parse the file notify buffer { int offset = 0; int nextOffset, action, nameLength; string oldName = null; do { // Get next offset nextOffset = Marshal.ReadInt32((IntPtr)((long)bufferPtr + offset)); // Get change flag action = Marshal.ReadInt32((IntPtr)((long)bufferPtr + offset + 4)); // Get filename length (in bytes) nameLength = Marshal.ReadInt32((IntPtr)((long)bufferPtr + offset + 8)); string name = Marshal.PtrToStringUni((IntPtr)((long)bufferPtr + offset + 12), nameLength / 2).ToLower(CultureInfo.InvariantCulture); /* A slightly convoluted piece of code follows. Here's what's happening: * * We wish to collapse the poorly done rename notifications from the * ReadDirectoryChangesW API into a nice rename event. So to do that, * it's assumed that a FILE_ACTION_RENAMED_OLD_NAME will be followed * immediately by a FILE_ACTION_RENAMED_NEW_NAME in the buffer, which is * all that the following code is doing. * * On a FILE_ACTION_RENAMED_OLD_NAME, it asserts that no previous one existed * and saves its name. If there are no more events in the buffer, it'll * assert and fire a RenameEventArgs with the Name field null. * * If a NEW_NAME action comes in with no previous OLD_NAME, we assert and fire * a rename event with the OldName field null. * * If the OLD_NAME and NEW_NAME actions are indeed there one after the other, * we'll fire the RenamedEventArgs normally and clear oldName. * * If the OLD_NAME is followed by another action, we assert and then fire the * rename event with the Name field null and then fire the next action. * * In case it's not a OLD_NAME or NEW_NAME action, we just fire the event normally. * * (Phew!) */ // If the action is RENAMED_FROM, save the name of the file if (action == Direct.FILE_ACTION_RENAMED_OLD_NAME) { Debug.Assert(oldName == null, "FileSystemWatcher: Two FILE_ACTION_RENAMED_OLD_NAME " + "in a row! [" + oldName + "], [ " + name + "]"); oldName = name; } else if (action == Direct.FILE_ACTION_RENAMED_NEW_NAME) { if (oldName != null) { NotifyRenameEventArgs(WatcherChangeTypes.Renamed, name, oldName); oldName = null; } else { Debug.Assert(false, "FileSystemWatcher: FILE_ACTION_RENAMED_NEW_NAME with no" + "old name! [ " + name + "]"); NotifyRenameEventArgs(WatcherChangeTypes.Renamed, name, oldName); oldName = null; } } else { if (oldName != null) { Debug.Assert(false, "FileSystemWatcher: FILE_ACTION_RENAMED_OLD_NAME with no" + "new name! [" + oldName + "]"); NotifyRenameEventArgs(WatcherChangeTypes.Renamed, null, oldName); oldName = null; } // Notify each file of change NotifyFileSystemEventArgs(action, name); } offset += nextOffset; } while (nextOffset != 0); if (oldName != null) { Debug.Assert(false, "FileSystemWatcher: FILE_ACTION_RENAMED_OLD_NAME with no" + "new name! [" + oldName + "]"); NotifyRenameEventArgs(WatcherChangeTypes.Renamed, null, oldName); oldName = null; } } } } finally { Overlapped.Free(overlappedPointer); if (stopListening || runOnce) { if (bufferPtr != (IntPtr)0) { Marshal.FreeHGlobal(bufferPtr); } } else { Monitor(bufferPtr); } } }
/// <summary> /// IOCompletion callback for page flush /// </summary> /// <param name="errorCode"></param> /// <param name="numBytes"></param> /// <param name="overlap"></param> private void AsyncFlushPartialObjectLogCallback <TContext>(uint errorCode, uint numBytes, NativeOverlapped *overlap) { if (errorCode != 0) { Trace.TraceError("OverlappedStream GetQueuedCompletionStatus error: {0}", errorCode); } // Set the page status to flushed PageAsyncFlushResult <TContext> result = (PageAsyncFlushResult <TContext>)Overlapped.Unpack(overlap).AsyncResult; result.done.Set(); Overlapped.Free(overlap); }
private static unsafe Task <TOut?> ExplicitDeviceIoControlAsync <TIn, TOut>(SafeFileHandle hDevice, uint ioControlCode, TIn?inVal, TOut?outVal) where TIn : struct where TOut : struct { ThreadPool.BindHandle(hDevice); var tcs = new TaskCompletionSource <TOut?>(); var buffer = Pack(inVal, outVal); var nativeOverlapped = new Overlapped().Pack((code, bytes, overlap) => { try { switch (code) { case Win32Error.ERROR_SUCCESS: outVal = Unpack <TIn, TOut>(buffer).Item2; tcs.TrySetResult(outVal); break; case Win32Error.ERROR_OPERATION_ABORTED: tcs.TrySetCanceled(); break; default: tcs.TrySetException(new Win32Exception((int)code)); break; } } finally { Overlapped.Unpack(overlap); Overlapped.Free(overlap); } }, buffer); var unpack = true; try { var inSz = Marshal.SizeOf(typeof(TIn)); fixed(byte *pIn = buffer, pOut = &buffer[inSz]) { uint bRet; var ret = DeviceIoControl(hDevice, ioControlCode, pIn, (uint)inSz, pOut, (uint)(buffer.Length - inSz), out bRet, nativeOverlapped); if (ret) { outVal = Unpack <TIn, TOut>(buffer).Item2; tcs.SetResult(outVal); return(tcs.Task); } } var lastWin32Error = Marshal.GetLastWin32Error(); if (lastWin32Error != Win32Error.ERROR_IO_PENDING && lastWin32Error != Win32Error.ERROR_SUCCESS) { throw new Win32Exception(lastWin32Error); } unpack = false; return(tcs.Task); } finally { if (unpack) { Overlapped.Unpack(nativeOverlapped); Overlapped.Free(nativeOverlapped); } } }
private static unsafe void CompletionCallback(uint errorCode, uint numBytes, NativeOverlapped *nativeOverlapped) { ThreadPoolBoundHandleOverlapped overlapped = (ThreadPoolBoundHandleOverlapped)Overlapped.Unpack(nativeOverlapped); // // The Win32 thread pool implementation of ThreadPoolBoundHandle does not permit reuse of NativeOverlapped // pointers without freeing them and allocating new a new one. We need to ensure that code using the CLR // ThreadPool implementation follows those rules. // if (overlapped._completed) { throw new InvalidOperationException(SR.InvalidOperation_NativeOverlappedReused); } overlapped._completed = true; if (overlapped._boundHandle == null) { throw new InvalidOperationException(SR.Argument_NativeOverlappedAlreadyFree); } overlapped._userCallback(errorCode, numBytes, nativeOverlapped); }
public static unsafe Task WriteAsync(SafeFileHandle hFile, long fileOffset, ArraySegment <byte> bytes) { if (fileOffset < 0) { throw new ArgumentOutOfRangeException(nameof(fileOffset)); } var asyncResult = new AsyncResult(); int low = (int)(fileOffset & 0xFFFFFFFF); int high = (int)(fileOffset >> 32); var o = new Overlapped(low, high, IntPtr.Zero, asyncResult); fixed(byte *bufferBase = bytes.Array) { // https://docs.microsoft.com/en-us/dotnet/api/system.threading.overlapped.pack?view=netframework-4.7#System_Threading_Overlapped_Pack_System_Threading_IOCompletionCallback_System_Object_ // The buffer or buffers specified in userData must be the same as those passed to the unmanaged operating system function that performs the asynchronous I/O. // The runtime pins the buffer or buffers specified in userData for the duration of the I/O operation. NativeOverlapped *pOverlapped = o.Pack(CompletionCallback, bytes.Array); bool needToFree = true; try { if (WriteFile(hFile, bufferBase + bytes.Offset, bytes.Count, IntPtr.Zero, pOverlapped) != 0) { // Completed synchronously. // The number of bytes transferred for the I/O request. The system sets this member if the request is completed without errors. // https://msdn.microsoft.com/en-us/library/windows/desktop/ms684342(v=vs.85).aspx int bytesWritten = (int)pOverlapped->InternalHigh.ToInt64(); if (bytesWritten != bytes.Count) { throw new EndOfStreamException("Could not write all the bytes."); } return(CompletedTask); } else { int systemErrorCode = Marshal.GetLastWin32Error(); if (systemErrorCode == ERROR_IO_DEVICE) { throw new IOException($"WriteFile failed with system error ERROR_IO_DEVICE", new Win32Exception(systemErrorCode)); } else if (systemErrorCode == ERROR_IO_PENDING) { needToFree = false; } else { throw new Win32Exception(systemErrorCode, $"WriteFile failed with system error code:{systemErrorCode}"); } return(asyncResult.CompletionSource.Value.Task.ContinueWith(t => { if (t.Status == TaskStatus.RanToCompletion && t.Result != bytes.Count) { throw new EndOfStreamException("Could not write all the bytes."); } return t; })); } } finally { if (needToFree) { Overlapped.Unpack(pOverlapped); Overlapped.Free(pOverlapped); } } } }
/// <devdoc> /// Callback from thread pool. /// </devdoc> /// <internalonly/> private unsafe void CompletionStatusChanged(uint errorCode, uint numBytes, NativeOverlapped *overlappedPointer) { Overlapped overlapped = Overlapped.Unpack(overlappedPointer); FSWAsyncResult asyncResult = (FSWAsyncResult)overlapped.AsyncResult; try { if (_stopListening) { return; } lock (this) { if (errorCode != 0) { if (errorCode == 995 /* ERROR_OPERATION_ABORTED */) { //Inside a service the first completion status is false //cannot return without monitoring again. //Because this return statement is inside a try/finally block, //the finally block will execute. It does restart the monitoring. return; } else { OnError(new ErrorEventArgs(new Win32Exception((int)errorCode))); EnableRaisingEvents = false; return; } } // Ignore any events that occurred before this "session", // so we don't get changed or error events after we // told FSW to stop. if (asyncResult.session != _currentSession) { return; } if (numBytes == 0) { NotifyInternalBufferOverflowEvent(); } else { // Else, parse each of them and notify appropriate delegates /****** * Format for the buffer is the following C struct: * * typedef struct _FILE_NOTIFY_INFORMATION { * DWORD NextEntryOffset; * DWORD Action; * DWORD FileNameLength; * WCHAR FileName[1]; * } FILE_NOTIFY_INFORMATION; * * NOTE1: FileNameLength is length in bytes. * NOTE2: The Filename is a Unicode string that's NOT NULL terminated. * NOTE3: A NextEntryOffset of zero means that it's the last entry *******/ // Parse the file notify buffer: int offset = 0; int nextOffset, action, nameLength; string oldName = null; string name = null; do { fixed(byte *buffPtr = asyncResult.buffer) { // Get next offset: nextOffset = *((int *)(buffPtr + offset)); // Get change flag: action = *((int *)(buffPtr + offset + 4)); // Get filename length (in bytes): nameLength = *((int *)(buffPtr + offset + 8)); name = new string((char *)(buffPtr + offset + 12), 0, nameLength / 2); } /* A slightly convoluted piece of code follows. Here's what's happening: * * We wish to collapse the poorly done rename notifications from the * ReadDirectoryChangesW API into a nice rename event. So to do that, * it's assumed that a FILE_ACTION_RENAMED_OLD_NAME will be followed * immediately by a FILE_ACTION_RENAMED_NEW_NAME in the buffer, which is * all that the following code is doing. * * On a FILE_ACTION_RENAMED_OLD_NAME, it asserts that no previous one existed * and saves its name. If there are no more events in the buffer, it'll * assert and fire a RenameEventArgs with the Name field null. * * If a NEW_NAME action comes in with no previous OLD_NAME, we assert and fire * a rename event with the OldName field null. * * If the OLD_NAME and NEW_NAME actions are indeed there one after the other, * we'll fire the RenamedEventArgs normally and clear oldName. * * If the OLD_NAME is followed by another action, we assert and then fire the * rename event with the Name field null and then fire the next action. * * In case it's not a OLD_NAME or NEW_NAME action, we just fire the event normally. * * (Phew!) */ // If the action is RENAMED_FROM, save the name of the file if (action == Direct.FILE_ACTION_RENAMED_OLD_NAME) { Debug.Assert(oldName == null, "FileSystemWatcher: Two FILE_ACTION_RENAMED_OLD_NAME " + "in a row! [" + oldName + "], [ " + name + "]"); oldName = name; } else if (action == Direct.FILE_ACTION_RENAMED_NEW_NAME) { if (oldName != null) { NotifyRenameEventArgs(WatcherChangeTypes.Renamed, name, oldName); oldName = null; } else { Debug.Fail("FileSystemWatcher: FILE_ACTION_RENAMED_NEW_NAME with no" + "old name! [ " + name + "]"); NotifyRenameEventArgs(WatcherChangeTypes.Renamed, name, oldName); oldName = null; } } else { if (oldName != null) { Debug.Fail("FileSystemWatcher: FILE_ACTION_RENAMED_OLD_NAME with no" + "new name! [" + oldName + "]"); NotifyRenameEventArgs(WatcherChangeTypes.Renamed, null, oldName); oldName = null; } // Notify each file of change NotifyFileSystemEventArgs(action, name); } offset += nextOffset; } while (nextOffset != 0); if (oldName != null) { Debug.Fail("FileSystemWatcher: FILE_ACTION_RENAMED_OLD_NAME with no" + "new name! [" + oldName + "]"); NotifyRenameEventArgs(WatcherChangeTypes.Renamed, null, oldName); oldName = null; } } } } finally { Overlapped.Free(overlappedPointer); if (!_stopListening) { Monitor(asyncResult.buffer); } } }
private static unsafe void WaitCallback(uint errorCode, uint numBytes, System.Threading.NativeOverlapped *nativeOverlapped) { ListenerClientCertAsyncResult asyncResult = (ListenerClientCertAsyncResult)Overlapped.Unpack(nativeOverlapped).AsyncResult; HttpListenerRequest asyncObject = (HttpListenerRequest)asyncResult.AsyncObject; object result = null; try { if (errorCode == 0xea) { UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO *requestBlob = asyncResult.RequestBlob; asyncResult.Reset(numBytes + requestBlob->CertEncodedSize); uint pBytesReceived = 0; errorCode = UnsafeNclNativeMethods.HttpApi.HttpReceiveClientCertificate(asyncObject.HttpListenerContext.RequestQueueHandle, asyncObject.m_ConnectionId, 0, asyncResult.m_MemoryBlob, asyncResult.m_Size, &pBytesReceived, asyncResult.m_pOverlapped); if ((errorCode == 0x3e5) || (errorCode == 0)) { return; } } if (errorCode != 0) { asyncResult.ErrorCode = (int)errorCode; result = new HttpListenerException((int)errorCode); } else { UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO *memoryBlob = asyncResult.m_MemoryBlob; if (memoryBlob != null) { if (memoryBlob->pCertEncoded != null) { try { byte[] destination = new byte[memoryBlob->CertEncodedSize]; Marshal.Copy((IntPtr)memoryBlob->pCertEncoded, destination, 0, destination.Length); result = asyncObject.ClientCertificate = new X509Certificate2(destination); } catch (CryptographicException exception) { result = exception; } catch (SecurityException exception2) { result = exception2; } } asyncObject.SetClientCertificateError((int)memoryBlob->CertFlags); } } } catch (Exception exception3) { if (NclUtilities.IsFatal(exception3)) { throw; } result = exception3; } finally { if (errorCode != 0x3e5) { asyncObject.ClientCertState = ListenerClientCertState.Completed; } } asyncResult.InvokeCallback(result); }