public bool Unregister(WaitHandle waitObject) { // Hold the lock during the synchronous part of Unregister (as in CoreCLR) using (LockHolder.Hold(_lock)) { if (!_unregistering) { // Ensure callbacks will not call SetThreadpoolWait anymore _unregistering = true; // Cease queueing more callbacks Interop.Kernel32.SetThreadpoolWait(_tpWait, IntPtr.Zero, IntPtr.Zero); // Should we wait for callbacks synchronously? Note that we treat the zero handle as the asynchronous case. SafeWaitHandle?safeWaitHandle = waitObject?.SafeWaitHandle; bool blocking = ((safeWaitHandle != null) && (safeWaitHandle.DangerousGetHandle() == new IntPtr(-1))); if (blocking) { FinishUnregistering(); } else { // Wait for callbacks and dispose resources asynchronously ThreadPool.QueueUserWorkItem(FinishUnregisteringAsync, safeWaitHandle); } return(true); } } return(false); }
/// <summary> /// Obtains all of the corresponding safe wait handles and adds a ref to each. Since the <see cref="SafeWaitHandle"/> /// property is publically modifiable, this makes sure that we add and release refs one the same set of safe wait /// handles to keep them alive during a multi-wait operation. /// </summary> private static void ObtainSafeWaitHandles( ReadOnlySpan <WaitHandle> waitHandles, Span <SafeWaitHandle?> safeWaitHandles, Span <IntPtr> unsafeWaitHandles) { Debug.Assert(waitHandles != null); Debug.Assert(waitHandles.Length > 0); Debug.Assert(waitHandles.Length <= MaxWaitHandles); bool lastSuccess = true; SafeWaitHandle?lastSafeWaitHandle = null; try { for (int i = 0; i < waitHandles.Length; ++i) { WaitHandle waitHandle = waitHandles[i]; if (waitHandle == null) { throw new ArgumentNullException("waitHandles[" + i + ']', SR.ArgumentNull_ArrayElement); } SafeWaitHandle safeWaitHandle = waitHandle._waitHandle ?? // Throw ObjectDisposedException for backward compatibility even though it is not representative of the issue throw new ObjectDisposedException(null, SR.ObjectDisposed_Generic); lastSafeWaitHandle = safeWaitHandle; lastSuccess = false; safeWaitHandle.DangerousAddRef(ref lastSuccess); safeWaitHandles[i] = safeWaitHandle; unsafeWaitHandles[i] = safeWaitHandle.DangerousGetHandle(); } } catch { for (int i = 0; i < waitHandles.Length; ++i) { SafeWaitHandle?safeWaitHandle = safeWaitHandles[i]; if (safeWaitHandle == null) { break; } safeWaitHandle.DangerousRelease(); safeWaitHandles[i] = null; if (safeWaitHandle == lastSafeWaitHandle) { lastSafeWaitHandle = null; lastSuccess = true; } } if (!lastSuccess) { Debug.Assert(lastSafeWaitHandle != null); lastSafeWaitHandle.DangerousRelease(); } throw; } }
public static OpenExistingResult OpenNamedMutex(string name, out SafeWaitHandle?result) { OpenExistingResult status = WaitableObject.OpenNamedMutex(name, out WaitableObject? mutex); result = status == OpenExistingResult.Success ? NewHandle(mutex !) : null; return(status); }
internal SafeProcessHandle(int processId, SafeWaitHandle handle) : this(handle.DangerousGetHandle(), ownsHandle : true) { ProcessId = processId; _handle = handle; handle.DangerousAddRef(ref _releaseRef); }
private static bool SignalAndWait(WaitHandle toSignal, WaitHandle toWaitOn, int millisecondsTimeout) { if (toSignal == null) { throw new ArgumentNullException(nameof(toSignal)); } if (toWaitOn == null) { throw new ArgumentNullException(nameof(toWaitOn)); } if (millisecondsTimeout < -1) { throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1); } // The field value is modifiable via the public <see cref="WaitHandle.SafeWaitHandle"/> property, save it locally // to ensure that one instance is used in all places in this method SafeWaitHandle?safeWaitHandleToSignal = toSignal._waitHandle; SafeWaitHandle?safeWaitHandleToWaitOn = toWaitOn._waitHandle; if (safeWaitHandleToSignal == null || safeWaitHandleToWaitOn == null) { // Throw ObjectDisposedException for backward compatibility even though it is not be representative of the issue throw new ObjectDisposedException(null, SR.ObjectDisposed_Generic); } bool successSignal = false, successWait = false; try { safeWaitHandleToSignal.DangerousAddRef(ref successSignal); safeWaitHandleToWaitOn.DangerousAddRef(ref successWait); int ret = SignalAndWaitCore( safeWaitHandleToSignal.DangerousGetHandle(), safeWaitHandleToWaitOn.DangerousGetHandle(), millisecondsTimeout); if (ret == WaitAbandoned) { throw new AbandonedMutexException(); } return(ret != WaitTimeout); } finally { if (successWait) { safeWaitHandleToWaitOn.DangerousRelease(); } if (successSignal) { safeWaitHandleToSignal.DangerousRelease(); } } }
/// <summary> /// Sets the native operating system handle /// </summary> /// <param name="waitHandle">The <see cref="System.Threading.WaitHandle"/> to operate on.</param> /// <param name="value">A <see cref="System.Runtime.InteropServices.SafeHandle"/> representing the native operating system handle.</param> public static void SetSafeWaitHandle(this WaitHandle waitHandle, SafeWaitHandle?value) { if (waitHandle == null) { throw new ArgumentNullException(nameof(waitHandle)); } waitHandle.SafeWaitHandle = value; }
/// <summary> /// Sets the native operating system handle /// </summary> /// <param name="waitHandle">The <see cref="System.Threading.WaitHandle"/> to operate on.</param> /// <param name="value">A <see cref="System.Runtime.InteropServices.SafeHandle"/> representing the native operating system handle.</param> public static void SetSafeWaitHandle(this WaitHandle waitHandle, SafeWaitHandle?value) { if (waitHandle == null) { throw new ArgumentNullException(nameof(waitHandle)); } waitHandle.SafeWaitHandle = value !; // TODO-NULLABLE: Remove ! when nullable attributes are respected }
private void FinishUnregisteringAsync(object?waitObject) { FinishUnregistering(); // Signal the provided wait object SafeWaitHandle?safeWaitHandle = (SafeWaitHandle?)waitObject; if ((safeWaitHandle != null) && !safeWaitHandle.IsInvalid) { Interop.Kernel32.SetEvent(safeWaitHandle); } }
private void CreateMutexCore(bool initiallyOwned, string?name, out bool createdNew) { if (name != null) { SafeWaitHandle?safeWaitHandle = WaitSubsystem.CreateNamedMutex(initiallyOwned, name, out createdNew); if (safeWaitHandle == null) { throw new WaitHandleCannotBeOpenedException(SR.Format(SR.Threading_WaitHandleCannotBeOpenedException_InvalidHandle, name)); } SafeWaitHandle = safeWaitHandle; return; } SafeWaitHandle = WaitSubsystem.NewMutex(initiallyOwned); createdNew = true; }
private static SafeWaitHandle NewHandle(WaitableObject waitableObject) { IntPtr handle = HandleManager.NewHandle(waitableObject); SafeWaitHandle?safeWaitHandle = null; try { safeWaitHandle = new SafeWaitHandle(handle, ownsHandle: true); return(safeWaitHandle); } finally { if (safeWaitHandle == null) { HandleManager.DeleteHandle(handle); } } }
/// <summary> /// Signal <see cref="UserUnregisterWaitHandle"/> if it has not been signaled yet and is a valid handle. /// </summary> private void SignalUserWaitHandle() { _callbackLock.VerifyIsLocked(); SafeWaitHandle?handle = UserUnregisterWaitHandle; IntPtr handleValue = UserUnregisterWaitHandleValue; try { if (handleValue != IntPtr.Zero && handleValue != (IntPtr)(-1)) { Debug.Assert(handleValue == handle !.DangerousGetHandle()); EventWaitHandle.Set(handle); } } finally { handle?.DangerousRelease(); _callbacksComplete?.Set(); _unregistered = true; } }
/// <summary> /// Sets the native operating system handle /// </summary> /// <param name="waitHandle">The <see cref="System.Threading.WaitHandle"/> to operate on.</param> /// <param name="value">A <see cref="System.Runtime.InteropServices.SafeHandle"/> representing the native operating system handle.</param> public static void SetSafeWaitHandle(this WaitHandle waitHandle, SafeWaitHandle?value) { ArgumentNullException.ThrowIfNull(waitHandle); waitHandle.SafeWaitHandle = value; }
public static ISafeWaitHandle?ToInterface(this SafeWaitHandle?handle) { return(handle == null ? null : new SafeWaitHandleAdapter(handle)); }