/// <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); }