Esempio n. 1
0
        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);
        }
Esempio n. 2
0
        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);
        }