private static unsafe void CompletionPortCallback(uint errorCode, uint numBytes, NativeOverlapped *nativeOverlapped) { #if DEBUG DebugThreadTracking.SetThreadSource(ThreadKinds.CompletionPort); using (DebugThreadTracking.SetThreadKind(ThreadKinds.System)) { #endif BaseOverlappedAsyncResult asyncResult = (BaseOverlappedAsyncResult)ThreadPoolBoundHandle.GetNativeOverlappedState(nativeOverlapped); object returnObject = null; if (asyncResult.InternalPeekCompleted) { NetEventSource.Fail(null, $"asyncResult.IsCompleted: {asyncResult}"); } if (NetEventSource.IsEnabled) { NetEventSource.Info(null, $"errorCode:{errorCode} numBytes:{numBytes} nativeOverlapped:{(IntPtr)nativeOverlapped}"); } // Complete the IO and invoke the user's callback. SocketError socketError = (SocketError)errorCode; if (socketError != SocketError.Success && socketError != SocketError.OperationAborted) { // There are cases where passed errorCode does not reflect the details of the underlined socket error. // "So as of today, the key is the difference between WSAECONNRESET and ConnectionAborted, // .e.g remote party or network causing the connection reset or something on the local host (e.g. closesocket // or receiving data after shutdown (SD_RECV)). With Winsock/TCP stack rewrite in longhorn, there may // be other differences as well." Socket socket = asyncResult.AsyncObject as Socket; if (socket == null) { socketError = SocketError.NotSocket; } else if (socket.CleanedUp) { socketError = SocketError.OperationAborted; } else { try { // The async IO completed with a failure. // Here we need to call WSAGetOverlappedResult() just so Marshal.GetLastWin32Error() will return the correct error. SocketFlags ignore; bool success = Interop.Winsock.WSAGetOverlappedResult( socket.SafeHandle, asyncResult.NativeOverlapped, out numBytes, false, out ignore); if (!success) { socketError = (SocketError)Marshal.GetLastWin32Error(); if (socketError == 0) { NetEventSource.Fail(asyncResult, $"socketError:0 numBytes:{numBytes}"); } } if (success) { NetEventSource.Fail(asyncResult, $"Unexpectedly succeeded. errorCode:{errorCode} numBytes:{numBytes}"); } } catch (ObjectDisposedException) { // CleanedUp check above does not always work since this code is subject to race conditions socketError = SocketError.OperationAborted; } } } asyncResult.ErrorCode = (int)socketError; returnObject = asyncResult.PostCompletion((int)numBytes); asyncResult.ReleaseUnmanagedStructures(); asyncResult.InvokeCallback(returnObject); #if DEBUG } #endif }
private static unsafe void WaitCallback(uint errorCode, uint numBytes, NativeOverlapped *nativeOverlapped) { ListenerClientCertAsyncResult asyncResult = (ListenerClientCertAsyncResult)ThreadPoolBoundHandle.GetNativeOverlappedState(nativeOverlapped); if (NetEventSource.IsEnabled) { NetEventSource.Info(null, $"errorCode:[{errorCode}] numBytes:[{numBytes}] nativeOverlapped:[{((long)nativeOverlapped)}]"); } IOCompleted(asyncResult, errorCode, numBytes); }
private static unsafe void Callback(uint errorCode, uint numBytes, NativeOverlapped *nativeOverlapped) { var asyncResult = (ResponseStreamAsyncResult)ThreadPoolBoundHandle.GetNativeOverlappedState(nativeOverlapped) !; IOCompleted(asyncResult, errorCode, numBytes); }
unsafe private static void AsyncPSCallback(uint errorCode, uint numBytes, NativeOverlapped *pOverlapped) { // Extract async result from overlapped PipeStreamAsyncResult asyncResult = (PipeStreamAsyncResult)ThreadPoolBoundHandle.GetNativeOverlappedState(pOverlapped); 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); } }
private unsafe IAsyncResult BeginWaitForConnection(AsyncCallback callback, Object state) { CheckConnectOperationsServerWithHandle(); if (!IsAsync) { throw new InvalidOperationException(SR.InvalidOperation_PipeNotAsync); } // Create and store async stream class library specific data in the // async result PipeAsyncResult asyncResult = new PipeAsyncResult(); asyncResult._threadPoolBinding = _threadPoolBinding; asyncResult._userCallback = callback; asyncResult._userStateObject = state; IOCancellationHelper cancellationHelper = state as IOCancellationHelper; // Create wait handle and store in async result ManualResetEvent waitHandle = new ManualResetEvent(false); asyncResult._waitHandle = waitHandle; NativeOverlapped *intOverlapped = _threadPoolBinding.AllocateNativeOverlapped((errorCode, numBytes, pOverlapped) => { // Unpack overlapped, free the pinned overlapped, and complete the operation PipeAsyncResult ar = (PipeAsyncResult)ThreadPoolBoundHandle.GetNativeOverlappedState(pOverlapped); Debug.Assert(ar._overlapped == pOverlapped); ar._threadPoolBinding.FreeNativeOverlapped(pOverlapped); ar._overlapped = null; AsyncWaitForConnectionCallback(errorCode, numBytes, ar); }, asyncResult, null); asyncResult._overlapped = intOverlapped; if (!Interop.mincore.ConnectNamedPipe(InternalHandle, intOverlapped)) { int errorCode = Marshal.GetLastWin32Error(); if (errorCode == Interop.mincore.Errors.ERROR_IO_PENDING) { if (cancellationHelper != null) { cancellationHelper.AllowCancellation(InternalHandle, intOverlapped); } return(asyncResult); } // WaitForConnectionCallback will not be called because we completed synchronously. // Either the pipe is already connected, or there was an error. Unpin and free the overlapped again. _threadPoolBinding.FreeNativeOverlapped(intOverlapped); asyncResult._overlapped = null; // Did the client already connect to us? if (errorCode == Interop.mincore.Errors.ERROR_PIPE_CONNECTED) { if (State == PipeState.Connected) { throw new InvalidOperationException(SR.InvalidOperation_PipeAlreadyConnected); } asyncResult.CallUserCallback(); return(asyncResult); } throw Win32Marshal.GetExceptionForWin32Error(errorCode); } // will set state to Connected when EndWait is called if (cancellationHelper != null) { cancellationHelper.AllowCancellation(InternalHandle, intOverlapped); } return(asyncResult); }
private static unsafe void Callback(uint errorCode, uint numBytes, NativeOverlapped *nativeOverlapped) { HttpRequestStreamAsyncResult asyncResult = (HttpRequestStreamAsyncResult)ThreadPoolBoundHandle.GetNativeOverlappedState(nativeOverlapped); if (NetEventSource.IsEnabled) { NetEventSource.Info(null, $"asyncResult: {asyncResult} errorCode:0x {errorCode.ToString("x8")} numBytes: {numBytes} nativeOverlapped:0x {((IntPtr)nativeOverlapped).ToString("x8")}"); } IOCompleted(asyncResult, errorCode, numBytes); }
private static unsafe void WaitCallback(uint errorCode, uint numBytes, NativeOverlapped *nativeOverlapped) { ListenerAsyncResult asyncResult = (ListenerAsyncResult)ThreadPoolBoundHandle.GetNativeOverlappedState(nativeOverlapped); IOCompleted(asyncResult, errorCode, numBytes); }
private static unsafe void WaitCallback(uint errorCode, uint numBytes, NativeOverlapped *nativeOverlapped) { var asyncResult = (ClientCertLoader)ThreadPoolBoundHandle.GetNativeOverlappedState(nativeOverlapped) !; IOCompleted(asyncResult, errorCode, numBytes); }
// When doing IO asynchronously (ie, _isAsync==true), this callback is // called by a free thread in the threadpool when the IO operation // completes. unsafe private static void AsyncFSCallback(uint errorCode, uint numBytes, NativeOverlapped *pOverlapped) { // Extract async result from overlapped FileStreamCompletionSource completionSource = (FileStreamCompletionSource)ThreadPoolBoundHandle.GetNativeOverlappedState(pOverlapped); Debug.Assert(completionSource._overlapped == pOverlapped, "Overlaps don't match"); // Handle reading from & writing to closed pipes. While I'm not sure // this is entirely necessary anymore, maybe it's possible for // an async read on a pipe to be issued and then the pipe is closed, // returning this error. This may very well be necessary. ulong packedResult; if (errorCode != 0 && errorCode != Win32FileStream.ERROR_BROKEN_PIPE && errorCode != Win32FileStream.ERROR_NO_DATA) { packedResult = ((ulong)ResultError | errorCode); } else { packedResult = ((ulong)ResultSuccess | numBytes); } // Stow the result so that other threads can observe it // And, if no other thread is registering cancellation, continue if (NoResult == Interlocked.Exchange(ref completionSource._result, (long)packedResult)) { // Successfully set the state, attempt to take back the callback if (Interlocked.Exchange(ref completionSource._result, CompletedCallback) != NoResult) { // Successfully got the callback, finish the callback completionSource.CompleteCallback(packedResult); } // else: Some other thread stole the result, so now it is responsible to finish the callback } // else: Some other thread is registering a cancellation, so it *must* finish the callback }
/// <summary>Start monitoring the current directory.</summary> private void StartRaisingEvents() { // If we're called when "Initializing" is true, set enabled to true if (IsSuspended()) { _enabled = true; return; } // If we're already running, don't do anything. if (!IsHandleInvalid(_directoryHandle)) { return; } // Create handle to directory being monitored _directoryHandle = Interop.Kernel32.CreateFile( lpFileName: _directory, dwDesiredAccess: Interop.Kernel32.FileOperations.FILE_LIST_DIRECTORY, dwShareMode: FileShare.Read | FileShare.Delete | FileShare.Write, dwCreationDisposition: FileMode.Open, dwFlagsAndAttributes: Interop.Kernel32.FileOperations.FILE_FLAG_BACKUP_SEMANTICS | Interop.Kernel32.FileOperations.FILE_FLAG_OVERLAPPED); if (IsHandleInvalid(_directoryHandle)) { _directoryHandle = null; throw new FileNotFoundException(SR.Format(SR.FSW_IOError, _directory)); } // Create the state associated with the operation of monitoring the direction AsyncReadState state; try { // Start ignoring all events that were initiated before this, and // allocate the buffer to be pinned and used for the duration of the operation int session = Interlocked.Increment(ref _currentSession); byte[] buffer = AllocateBuffer(); // Store all state, including a preallocated overlapped, into the state object that'll be // passed from iteration to iteration during the lifetime of the operation. The buffer will be pinned // from now until the end of the operation. state = new AsyncReadState(session, buffer, _directoryHandle, ThreadPoolBoundHandle.BindHandle(_directoryHandle), this); unsafe { state.PreAllocatedOverlapped = new PreAllocatedOverlapped((errorCode, numBytes, overlappedPointer) => { AsyncReadState state = (AsyncReadState)ThreadPoolBoundHandle.GetNativeOverlappedState(overlappedPointer) !; state.ThreadPoolBinding.FreeNativeOverlapped(overlappedPointer); if (state.WeakWatcher.TryGetTarget(out FileSystemWatcher? watcher)) { watcher.ReadDirectoryChangesCallback(errorCode, numBytes, state); } }, state, buffer); } } catch { // Make sure we don't leave a valid directory handle set if we're not running _directoryHandle.Dispose(); _directoryHandle = null; throw; } // Start monitoring _enabled = true; Monitor(state); }
/// <devdoc> /// Callback from thread pool. /// </devdoc> /// <internalonly/> private unsafe void CompletionStatusChanged(uint errorCode, uint numBytes, NativeOverlapped *overlappedPointer) { FSWAsyncResult asyncResult = (FSWAsyncResult)ThreadPoolBoundHandle.GetNativeOverlappedState(overlappedPointer); 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 { _threadPoolBinding.FreeNativeOverlapped(overlappedPointer); if (!_stopListening) { Monitor(asyncResult.buffer); } } }
private static unsafe void CompletionPortCallback(uint errorCode, uint numBytes, NativeOverlapped *nativeOverlapped) { Debug.Assert(OperatingSystem.IsWindows()); BaseOverlappedAsyncResult asyncResult = (BaseOverlappedAsyncResult)ThreadPoolBoundHandle.GetNativeOverlappedState(nativeOverlapped) !; if (asyncResult.InternalPeekCompleted) { NetEventSource.Fail(null, $"asyncResult.IsCompleted: {asyncResult}"); } if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(null, $"errorCode:{errorCode} numBytes:{numBytes} nativeOverlapped:{(IntPtr)nativeOverlapped}"); } // Complete the IO and invoke the user's callback. SocketError socketError = (SocketError)errorCode; if (socketError != SocketError.Success && socketError != SocketError.OperationAborted) { // There are cases where passed errorCode does not reflect the details of the underlined socket error. // "So as of today, the key is the difference between WSAECONNRESET and ConnectionAborted, // .e.g remote party or network causing the connection reset or something on the local host (e.g. closesocket // or receiving data after shutdown (SD_RECV)). With Winsock/TCP stack rewrite in longhorn, there may // be other differences as well." Socket?socket = asyncResult.AsyncObject as Socket; if (socket == null) { socketError = SocketError.NotSocket; } else if (socket.Disposed) { socketError = SocketError.OperationAborted; } else { try { // The async IO completed with a failure. // Here we need to call WSAGetOverlappedResult() just so GetLastSocketError() will return the correct error. SocketFlags ignore; bool success = Interop.Winsock.WSAGetOverlappedResult( socket.SafeHandle, nativeOverlapped, out numBytes, false, out ignore); if (!success) { socketError = SocketPal.GetLastSocketError(); } if (success) { NetEventSource.Fail(asyncResult, $"Unexpectedly succeeded. errorCode:{errorCode} numBytes:{numBytes}"); } } catch (ObjectDisposedException) { // Disposed check above does not always work since this code is subject to race conditions socketError = SocketError.OperationAborted; } } } // Set results and invoke callback asyncResult.CompletionCallback((int)numBytes, socketError); }
private unsafe static void CompletionPortCallback(uint errorCode, uint numBytes, NativeOverlapped *nativeOverlapped) { #if DEBUG GlobalLog.SetThreadSource(ThreadKinds.CompletionPort); using (GlobalLog.SetThreadKind(ThreadKinds.System)) { #endif BaseOverlappedAsyncResult asyncResult = (BaseOverlappedAsyncResult)ThreadPoolBoundHandle.GetNativeOverlappedState(nativeOverlapped); object returnObject = null; GlobalLog.Assert(!asyncResult.InternalPeekCompleted, "BaseOverlappedAsyncResult#{0}::CompletionPortCallback()|asyncResult.IsCompleted", LoggingHash.HashString(asyncResult)); GlobalLog.Print( "BaseOverlappedAsyncResult#" + LoggingHash.HashString(asyncResult) + "::CompletionPortCallback" + " errorCode:" + errorCode.ToString() + " numBytes:" + numBytes.ToString() + " pOverlapped:" + ((int)nativeOverlapped).ToString()); // Complete the IO and invoke the user's callback. SocketError socketError = (SocketError)errorCode; if (socketError != SocketError.Success && socketError != SocketError.OperationAborted) { // There are cases where passed errorCode does not reflect the details of the underlined socket error. // "So as of today, the key is the difference between WSAECONNRESET and ConnectionAborted, // .e.g remote party or network causing the connection reset or something on the local host (e.g. closesocket // or receiving data after shutdown (SD_RECV)). With Winsock/TCP stack rewrite in longhorn, there may // be other differences as well." Socket socket = asyncResult.AsyncObject as Socket; if (socket == null) { socketError = SocketError.NotSocket; } else if (socket.CleanedUp) { socketError = SocketError.OperationAborted; } else { try { // The async IO completed with a failure. // Here we need to call WSAGetOverlappedResult() just so Marshal.GetLastWin32Error() will return the correct error. SocketFlags ignore; bool success = Interop.Winsock.WSAGetOverlappedResult( socket.SafeHandle, asyncResult.NativeOverlapped, out numBytes, false, out ignore); if (!success) { socketError = (SocketError)Marshal.GetLastWin32Error(); GlobalLog.Assert(socketError != 0, "BaseOverlappedAsyncResult#{0}::CompletionPortCallback()|socketError:0 numBytes:{1}", LoggingHash.HashString(asyncResult), numBytes); } GlobalLog.Assert(!success, "BaseOverlappedAsyncResult#{0}::CompletionPortCallback()|Unexpectedly succeeded. errorCode:{1} numBytes:{2}", LoggingHash.HashString(asyncResult), errorCode, numBytes); } catch (ObjectDisposedException) { // CleanedUp check above does not always work since this code is subject to race conditions socketError = SocketError.OperationAborted; } } } asyncResult.ErrorCode = (int)socketError; returnObject = asyncResult.PostCompletion((int)numBytes); asyncResult.ReleaseUnmanagedStructures(); asyncResult.InvokeCallback(returnObject); #if DEBUG } #endif }