/// <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) { Debug.Assert(currentThread == RuntimeThread.CurrentThread); Debug.Assert(waitHandles != null); Debug.Assert(waitHandles.Length > 0); Debug.Assert(waitHandles.Length <= MaxWaitHandles); SafeWaitHandle[] safeWaitHandles = currentThread.GetWaitedSafeWaitHandleArray(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(); } } } return(safeWaitHandles); }