private static unsafe int WaitForMultipleObjectsIgnoringSyncContext(IntPtr *pHandles, int numHandles, bool waitAll, int millisecondsTimeout, bool interruptible) { Debug.Assert(millisecondsTimeout >= -1); // // In the CLR, we use CoWaitForMultipleHandles to pump messages while waiting in an STA. In that case, we cannot use WAIT_ALL. // That's because the wait would only be satisfied if a message arrives while the handles are signalled. // if (waitAll) { if (numHandles == 1) { waitAll = false; } else if (RuntimeThread.GetCurrentApartmentType() == RuntimeThread.ApartmentType.STA) { throw new NotSupportedException(SR.NotSupported_WaitAllSTAThread); } } RuntimeThread currentThread = RuntimeThread.CurrentThread; currentThread.SetWaitSleepJoinState(); int result; if (RuntimeThread.ReentrantWaitsEnabled) { Debug.Assert(!waitAll); result = RuntimeImports.RhCompatibleReentrantWaitAny(false, millisecondsTimeout, numHandles, pHandles); } else { result = (int)Interop.mincore.WaitForMultipleObjectsEx((uint)numHandles, (IntPtr)pHandles, waitAll, (uint)millisecondsTimeout, false); } currentThread.ClearWaitSleepJoinState(); if (result == WaitHandle.WaitFailed) { int errorCode = Interop.mincore.GetLastError(); if (waitAll && errorCode == Interop.Errors.ERROR_INVALID_PARAMETER) { // Check for duplicate handles. This is a brute force O(n^2) search, which is intended since the typical // array length is short enough that this would actually be faster than using a hash set. Also, the worst // case is not so bad considering that the array length is limited by // <see cref="WaitHandle.MaxWaitHandles"/>. for (int i = 1; i < numHandles; ++i) { IntPtr handle = pHandles[i]; for (int j = 0; j < i; ++j) { if (pHandles[j] == handle) { throw new DuplicateWaitObjectException("waitHandles[" + i + ']'); } } } } ThrowWaitFailedException(errorCode); } return(result); }