private static unsafe int WaitForMultipleObjectsIgnoringSyncContext(IntPtr *pHandles, int numHandles, bool waitAll, int millisecondsTimeout) { Debug.Assert(millisecondsTimeout >= -1); // Normalize waitAll if (numHandles == 1) { waitAll = false; } #if CORERT // TODO: reentrant wait support https://github.com/dotnet/runtime/issues/49518 bool reentrantWait = Thread.ReentrantWaitsEnabled; if (reentrantWait) { // // 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) { throw new NotSupportedException(SR.NotSupported_WaitAllSTAThread); } // CoWaitForMultipleHandles does not support more than 63 handles. It returns RPC_S_CALLPENDING for more than 63 handles // that is impossible to differentiate from timeout. if (numHandles > 63) { throw new NotSupportedException(SR.NotSupported_MaxWaitHandles_STA); } } #endif Thread currentThread = Thread.CurrentThread; currentThread.SetWaitSleepJoinState(); #if CORERT int result; if (reentrantWait) { Debug.Assert(!waitAll); result = RuntimeImports.RhCompatibleReentrantWaitAny(false, millisecondsTimeout, numHandles, pHandles); } else { result = (int)Interop.Kernel32.WaitForMultipleObjectsEx((uint)numHandles, (IntPtr)pHandles, waitAll ? Interop.BOOL.TRUE : Interop.BOOL.FALSE, (uint)millisecondsTimeout, Interop.BOOL.FALSE); } #else int result = (int)Interop.Kernel32.WaitForMultipleObjectsEx((uint)numHandles, (IntPtr)pHandles, waitAll ? Interop.BOOL.TRUE : Interop.BOOL.FALSE, (uint)millisecondsTimeout, Interop.BOOL.FALSE); #endif currentThread.ClearWaitSleepJoinState(); if (result == Interop.Kernel32.WAIT_FAILED) { int errorCode = Interop.Kernel32.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); }
private static unsafe int WaitForMultipleObjectsIgnoringSyncContext(IntPtr *pHandles, int numHandles, bool waitAll, int millisecondsTimeout) { 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 (Thread.GetCurrentApartmentType() == Thread.ApartmentType.STA) { throw new NotSupportedException(SR.NotSupported_WaitAllSTAThread); } } Thread currentThread = Thread.CurrentThread; currentThread.SetWaitSleepJoinState(); int result; if (Thread.ReentrantWaitsEnabled) { Debug.Assert(!waitAll); result = RuntimeImports.RhCompatibleReentrantWaitAny(false, millisecondsTimeout, numHandles, pHandles); } else { result = (int)Interop.Kernel32.WaitForMultipleObjectsEx((uint)numHandles, (IntPtr)pHandles, waitAll, (uint)millisecondsTimeout, false); } currentThread.ClearWaitSleepJoinState(); if (result == Interop.Kernel32.WAIT_FAILED) { 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); }