/// <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 SafeWaitHandle[] ObtainSafeWaitHandles( RuntimeThread currentThread, WaitHandle[] waitHandles, out SafeWaitHandle[] rentedSafeWaitHandles) { Debug.Assert(currentThread == RuntimeThread.CurrentThread); Debug.Assert(waitHandles != null); Debug.Assert(waitHandles.Length > 0); Debug.Assert(waitHandles.Length <= MaxWaitHandles); rentedSafeWaitHandles = currentThread.RentWaitedSafeWaitHandleArray(waitHandles.Length); SafeWaitHandle[] safeWaitHandles = rentedSafeWaitHandles ?? new SafeWaitHandle[waitHandles.Length]; bool success = false; 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; if (safeWaitHandle == null) { // Throw ObjectDisposedException for backward compatibility even though it is not be representative of the issue throw new ObjectDisposedException(null, SR.ObjectDisposed_Generic); } safeWaitHandle.DangerousAddRef(); safeWaitHandles[i] = safeWaitHandle; } success = true; } finally { if (!success) { for (int i = 0; i < waitHandles.Length; ++i) { SafeWaitHandle safeWaitHandle = safeWaitHandles[i]; if (safeWaitHandle == null) { break; } safeWaitHandle.DangerousRelease(); safeWaitHandles[i] = null; } if (rentedSafeWaitHandles != null) { currentThread.ReturnWaitedSafeWaitHandleArray(rentedSafeWaitHandles); } } } return(safeWaitHandles); }
public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout) { if (waitHandles == null) { throw new ArgumentNullException(nameof(waitHandles), SR.ArgumentNull_Waithandles); } if (waitHandles.Length == 0) { // // Some history: in CLR 1.0 and 1.1, we threw ArgumentException in this case, which was correct. // Somehow, in 2.0, this became ArgumentNullException. This was not fixed until Silverlight 2, // which went back to ArgumentException. // // Now we're in a bit of a bind. Backward-compatibility requires us to keep throwing ArgumentException // in CoreCLR, and ArgumentNullException in the desktop CLR. This is ugly, but so is breaking // user code. // throw new ArgumentNullException(nameof(waitHandles), SR.Argument_EmptyWaithandleArray); } if (waitHandles.Length > MaxWaitHandles) { throw new NotSupportedException(SR.NotSupported_MaxWaitHandles); } if (-1 > millisecondsTimeout) { throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1); } Contract.EndContractBlock(); RuntimeThread currentThread = RuntimeThread.CurrentThread; SafeWaitHandle[] rentedSafeWaitHandles; SafeWaitHandle[] safeWaitHandles = ObtainSafeWaitHandles(currentThread, waitHandles, waitHandles.Length, out rentedSafeWaitHandles); try { return(WaitAllCore(currentThread, safeWaitHandles, waitHandles, millisecondsTimeout)); } finally { for (int i = 0; i < waitHandles.Length; ++i) { safeWaitHandles[i].DangerousRelease(); safeWaitHandles[i] = null; } if (rentedSafeWaitHandles != null) { currentThread.ReturnWaitedSafeWaitHandleArray(rentedSafeWaitHandles); } } }
internal static int WaitAny(WaitHandle[] waitHandles, int numWaitHandles, int millisecondsTimeout) { if (waitHandles == null) { throw new ArgumentNullException(nameof(waitHandles), SR.ArgumentNull_Waithandles); } if (waitHandles.Length == 0) { throw new ArgumentException(SR.Argument_EmptyWaithandleArray); } if (MaxWaitHandles < waitHandles.Length) { throw new NotSupportedException(SR.NotSupported_MaxWaitHandles); } if (-1 > millisecondsTimeout) { throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1); } Contract.EndContractBlock(); RuntimeThread currentThread = RuntimeThread.CurrentThread; SafeWaitHandle[] rentedSafeWaitHandles; SafeWaitHandle[] safeWaitHandles = ObtainSafeWaitHandles(currentThread, waitHandles, numWaitHandles, out rentedSafeWaitHandles); try { return(WaitAnyCore(currentThread, safeWaitHandles, waitHandles, numWaitHandles, millisecondsTimeout)); } finally { for (int i = 0; i < numWaitHandles; ++i) { safeWaitHandles[i].DangerousRelease(); safeWaitHandles[i] = null; } if (rentedSafeWaitHandles != null) { currentThread.ReturnWaitedSafeWaitHandleArray(rentedSafeWaitHandles); } } }