Exemple #1
0
        public virtual bool WaitOne()
        {
            CheckDisposed();
            bool release = false;

            try {
                safe_wait_handle.DangerousAddRef(ref release);
                return(WaitOne_internal(safe_wait_handle.DangerousGetHandle(), Timeout.Infinite, false));
            } finally {
                if (release)
                {
                    safe_wait_handle.DangerousRelease();
                }
            }
        }
Exemple #2
0
        internal static void CompleteInitialization(SafeCloseSocketAndEvent socketAndEventHandle)
        {
            SafeWaitHandle handle = socketAndEventHandle._waitHandle.GetSafeWaitHandle();
            bool           b      = false;

            try
            {
                handle.DangerousAddRef(ref b);
            }
            catch
            {
                if (b)
                {
                    handle.DangerousRelease();
                    socketAndEventHandle._waitHandle = null;
                    b = false;
                }
            }
            finally
            {
                if (b)
                {
                    handle.Dispose();
                }
            }
        }
        private bool JoinInternal(int millisecondsTimeout)
        {
            // This method assumes the thread has been started
            Debug.Assert(!GetThreadStateBit(ThreadState.Unstarted) || (millisecondsTimeout == 0));
            SafeWaitHandle waitHandle = _stopped.SafeWaitHandle;

            // If an OS thread is terminated and its Thread object is resurrected, waitHandle may be finalized and closed
            if (waitHandle.IsClosed)
            {
                return(true);
            }

            // Prevent race condition with the finalizer
            try
            {
                waitHandle.DangerousAddRef();
            }
            catch (ObjectDisposedException)
            {
                return(true);
            }

            try
            {
                return(_stopped.WaitOne(millisecondsTimeout));
            }
            finally
            {
                waitHandle.DangerousRelease();
            }
        }
Exemple #4
0
        /// <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);
        }
        internal RegisteredWaitHandle(SafeWaitHandle waitHandle, _ThreadPoolWaitOrTimerCallback callbackHelper,
                                      uint millisecondsTimeout, bool repeating)
        {
            _lock = new Lock();

            // Protect the handle from closing while we are waiting on it (VSWhidbey 285642)
            waitHandle.DangerousAddRef();
            _waitHandle = waitHandle;

            _callbackHelper      = callbackHelper;
            _millisecondsTimeout = millisecondsTimeout;
            _repeating           = repeating;

            // Allocate _gcHandle and _tpWait as the last step and make sure they are never leaked
            _gcHandle = GCHandle.Alloc(this);

            _tpWait = Interop.mincore.CreateThreadpoolWait(
                AddrofIntrinsics.AddrOf <Interop.mincore.WaitCallback>(RegisteredWaitCallback), (IntPtr)_gcHandle, IntPtr.Zero);

            if (_tpWait == IntPtr.Zero)
            {
                _gcHandle.Free();
                throw new OutOfMemoryException();
            }
        }
Exemple #6
0
        internal static void CompleteInitialization(SafeCloseSocketAndEvent socketAndEventHandle)
        {
            SafeWaitHandle safeWaitHandle = socketAndEventHandle.waitHandle.SafeWaitHandle;
            bool           success        = false;

            RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                safeWaitHandle.DangerousAddRef(ref success);
            }
            catch
            {
                if (success)
                {
                    safeWaitHandle.DangerousRelease();
                    socketAndEventHandle.waitHandle = null;
                    success = false;
                }
            }
            finally
            {
                if (success)
                {
                    safeWaitHandle.Dispose();
                }
            }
        }
Exemple #7
0
        internal static int TryMsgWaitForMultipleObjects(SafeWaitHandle handle, bool waitAll, int milliseconds, int wakeMask, ref int lastWin32Error)
        {
            int terminationEvent;

            if (handle == null)
            {
                terminationEvent = UnsafeNativeMethods.MsgWaitForMultipleObjects(0, null, waitAll, milliseconds, wakeMask);
                lastWin32Error   = Marshal.GetLastWin32Error();
            }
            else
            {
                bool fRelease = false;
                try
                {
                    handle.DangerousAddRef(ref fRelease);
                    IntPtr[] handles = { handle.DangerousGetHandle() };
                    terminationEvent = UnsafeNativeMethods.MsgWaitForMultipleObjects(1, handles, waitAll, milliseconds, wakeMask);
                    lastWin32Error   = Marshal.GetLastWin32Error();
                }
                finally
                {
                    if (fRelease)
                    {
                        handle.DangerousRelease();
                    }
                }
            }
            return(terminationEvent);
        }
Exemple #8
0
        /// <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 void ObtainSafeWaitHandles(
            ReadOnlySpan <WaitHandle> waitHandles,
            Span <SafeWaitHandle?> safeWaitHandles,
            Span <IntPtr> unsafeWaitHandles)
        {
            Debug.Assert(waitHandles != null);
            Debug.Assert(waitHandles.Length > 0);
            Debug.Assert(waitHandles.Length <= MaxWaitHandles);

            bool           lastSuccess        = true;
            SafeWaitHandle?lastSafeWaitHandle = null;

            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 ??
                                                    // Throw ObjectDisposedException for backward compatibility even though it is not representative of the issue
                                                    throw new ObjectDisposedException(null, SR.ObjectDisposed_Generic);

                    lastSafeWaitHandle = safeWaitHandle;
                    lastSuccess        = false;
                    safeWaitHandle.DangerousAddRef(ref lastSuccess);
                    safeWaitHandles[i]   = safeWaitHandle;
                    unsafeWaitHandles[i] = safeWaitHandle.DangerousGetHandle();
                }
            }
            catch
            {
                for (int i = 0; i < waitHandles.Length; ++i)
                {
                    SafeWaitHandle?safeWaitHandle = safeWaitHandles[i];
                    if (safeWaitHandle == null)
                    {
                        break;
                    }
                    safeWaitHandle.DangerousRelease();
                    safeWaitHandles[i] = null;
                    if (safeWaitHandle == lastSafeWaitHandle)
                    {
                        lastSafeWaitHandle = null;
                        lastSuccess        = true;
                    }
                }

                if (!lastSuccess)
                {
                    Debug.Assert(lastSafeWaitHandle != null);
                    lastSafeWaitHandle.DangerousRelease();
                }

                throw;
            }
        }
        internal static int TryMsgWaitForMultipleObjects(SafeWaitHandle handle, bool waitAll, int milliseconds, int wakeMask, ref int lastWin32Error)
        {
            int terminationEvent;

            if (handle == null)
            {
                terminationEvent = UnsafeNativeMethods.MsgWaitForMultipleObjects(0, null, waitAll, milliseconds, wakeMask);
                lastWin32Error   = Marshal.GetLastWin32Error();
            }
            else
            {
                #pragma warning disable SYSLIB0004 // The Constrained Execution Region (CER) feature is not supported.
                RuntimeHelpers.PrepareConstrainedRegions();
                #pragma warning restore SYSLIB0004 // The Constrained Execution Region (CER) feature is not supported.
                bool fRelease = false;
                try
                {
                    handle.DangerousAddRef(ref fRelease);
                    IntPtr[] handles = { handle.DangerousGetHandle() };
                    terminationEvent = UnsafeNativeMethods.MsgWaitForMultipleObjects(1, handles, waitAll, milliseconds, wakeMask);
                    lastWin32Error   = Marshal.GetLastWin32Error();
                }
                finally
                {
                    if (fRelease)
                    {
                        handle.DangerousRelease();
                    }
                }
            }
            return(terminationEvent);
        }
Exemple #10
0
        private static bool SignalAndWait(WaitHandle toSignal, WaitHandle toWaitOn, int millisecondsTimeout)
        {
            if (toSignal == null)
            {
                throw new ArgumentNullException(nameof(toSignal));
            }
            if (toWaitOn == null)
            {
                throw new ArgumentNullException(nameof(toWaitOn));
            }
            if (millisecondsTimeout < -1)
            {
                throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
            }

            // The field value is modifiable via the public <see cref="WaitHandle.SafeWaitHandle"/> property, save it locally
            // to ensure that one instance is used in all places in this method
            SafeWaitHandle safeWaitHandleToSignal = toSignal._waitHandle;
            SafeWaitHandle safeWaitHandleToWaitOn = toWaitOn._waitHandle;

            if (safeWaitHandleToSignal == null || safeWaitHandleToWaitOn == null)
            {
                // Throw ObjectDisposedException for backward compatibility even though it is not be representative of the issue
                throw new ObjectDisposedException(null, SR.ObjectDisposed_Generic);
            }

            bool successSignal = false, successWait = false;

            try
            {
                safeWaitHandleToSignal.DangerousAddRef(ref successSignal);
                safeWaitHandleToWaitOn.DangerousAddRef(ref successWait);

                int ret = SignalAndWaitCore(
                    safeWaitHandleToSignal.DangerousGetHandle(),
                    safeWaitHandleToWaitOn.DangerousGetHandle(),
                    millisecondsTimeout);

                if (ret == WaitAbandoned)
                {
                    throw new AbandonedMutexException();
                }

                return(ret != WaitTimeout);
            }
            finally
            {
                if (successWait)
                {
                    safeWaitHandleToWaitOn.DangerousRelease();
                }
                if (successSignal)
                {
                    safeWaitHandleToSignal.DangerousRelease();
                }
            }
        }
Exemple #11
0
        public void SetDependencies(SafeWaitHandle waitHandle)
        {
            bool darSuccess = false;

            waitHandle.DangerousAddRef(ref darSuccess);
            Debug.Assert(darSuccess == true);

            _waitHandle = waitHandle;
        }
        internal static void CompleteInitialization(SafeCloseSocketAndEvent socketAndEventHandle)
        {
            SafeWaitHandle handle = socketAndEventHandle._waitHandle.GetSafeWaitHandle();

            bool ignore = false;

            handle.DangerousAddRef(ref ignore);

            // TODO #3562: Investigate if this pattern is still correct.
            // Note that the handle still has a reference from the above DangerousAddRef.
            handle.Dispose();
        }
Exemple #13
0
 internal static bool Set(SafeWaitHandle waitHandle)
 {
     waitHandle.DangerousAddRef();
     try
     {
         WaitSubsystem.SetEvent(waitHandle.DangerousGetHandle());
         return(true);
     }
     finally
     {
         waitHandle.DangerousRelease();
     }
 }
Exemple #14
0
        internal static int WaitOneNative(SafeWaitHandle waitableSafeHandle, long millisecondsTimeout)
        {
            Debug.Assert(millisecondsTimeout >= -1 && millisecondsTimeout <= int.MaxValue);

            waitableSafeHandle.DangerousAddRef();
            try
            {
                return(LowLevelThread.WaitForSingleObject(waitableSafeHandle.DangerousGetHandle(), (int)millisecondsTimeout));
            }
            finally
            {
                waitableSafeHandle.DangerousRelease();
            }
        }
Exemple #15
0
        public static bool ResetEvent(SafeWaitHandle handle)
        {
            bool release = false;

            try {
                handle.DangerousAddRef(ref release);
                return(ResetEvent_internal(handle.DangerousGetHandle()));
            } finally {
                if (release)
                {
                    handle.DangerousRelease();
                }
            }
        }
Exemple #16
0
        internal static bool Set(SafeWaitHandle waitHandle)
        {
            bool release = false;

            try {
                waitHandle.DangerousAddRef(ref release);
                return(SetEventInternal(waitHandle.DangerousGetHandle()));
            } finally {
                if (release)
                {
                    waitHandle.DangerousRelease();
                }
            }
        }
Exemple #17
0
        private void SignalNoCallbacksRunning()
        {
            SafeWaitHandle waitHandle = _notifyWhenNoCallbacksRunning.SafeWaitHandle;

            waitHandle.DangerousAddRef();
            try
            {
                WaitSubsystem.SetEvent(waitHandle.DangerousGetHandle());
            }
            finally
            {
                waitHandle.DangerousRelease();
            }
        }
Exemple #18
0
        private SafeWaitHandle ValidateHandle()
        {
            // The field value is modifiable via the public <see cref="WaitHandle.SafeWaitHandle"/> property, save it locally
            // to ensure that one instance is used in all places in this method
            SafeWaitHandle waitHandle = SafeWaitHandle;

            if (waitHandle.IsInvalid)
            {
                ThrowInvalidHandleException();
            }

            waitHandle.DangerousAddRef();
            return(waitHandle);
        }
Exemple #19
0
        static int SignalAndWaitOne(SafeWaitHandle waitHandleToSignal,SafeWaitHandle waitHandleToWaitOn, int millisecondsTimeout, bool hasThreadAffinity,  bool exitContext)
        {
            bool releaseHandleToSignal = false, releaseHandleToWaitOn = false;
            try {
                waitHandleToSignal.DangerousAddRef (ref releaseHandleToSignal);
                waitHandleToWaitOn.DangerousAddRef (ref releaseHandleToWaitOn);

                return SignalAndWait_Internal (waitHandleToSignal.DangerousGetHandle (), waitHandleToWaitOn.DangerousGetHandle (), millisecondsTimeout);
            } finally {
                if (releaseHandleToSignal)
                    waitHandleToSignal.DangerousRelease ();
                if (releaseHandleToWaitOn)
                    waitHandleToWaitOn.DangerousRelease ();
            }
        }
        private SafeWaitHandle ValidateHandle(out bool success)
        {
            // The field value is modifiable via the public <see cref="WaitHandle.SafeWaitHandle"/> property, save it locally
            // to ensure that one instance is used in all places in this method
            SafeWaitHandle waitHandle = SafeWaitHandle;

            if (waitHandle.IsInvalid)
            {
                throw new InvalidOperationException();
            }

            success = false;
            waitHandle.DangerousAddRef(ref success);
            return(waitHandle);
        }
Exemple #21
0
        private bool WaitOneNoCheck(int millisecondsTimeout)
        {
            Debug.Assert(millisecondsTimeout >= -1);

            // The field value is modifiable via the public <see cref="WaitHandle.SafeWaitHandle"/> property, save it locally
            // to ensure that one instance is used in all places in this method
            SafeWaitHandle waitHandle = _waitHandle;

            if (waitHandle == null)
            {
                // Throw ObjectDisposedException for backward compatibility even though it is not be representative of the issue
                throw new ObjectDisposedException(null, SR.ObjectDisposed_Generic);
            }

            bool success = false;

            try
            {
                int waitResult;

                waitHandle.DangerousAddRef(ref success);

                SynchronizationContext context = SynchronizationContext.Current;
                if (context != null && context.IsWaitNotificationRequired())
                {
                    waitResult = context.Wait(new[] { waitHandle.DangerousGetHandle() }, false, millisecondsTimeout);
                }
                else
                {
                    waitResult = WaitOneCore(waitHandle.DangerousGetHandle(), millisecondsTimeout);
                }

                if (waitResult == WaitAbandoned)
                {
                    throw new AbandonedMutexException();
                }

                return(waitResult != WaitTimeout);
            }
            finally
            {
                if (success)
                {
                    waitHandle.DangerousRelease();
                }
            }
        }
Exemple #22
0
        public void Wait(WaitHandle launchCompleteHandle, CancellationTokenSource cancellationSource)
        {
            int hr;

            SafeWaitHandle safeWaitHandle  = launchCompleteHandle.SafeWaitHandle;
            bool           addRefSucceeded = false;

            try
            {
                safeWaitHandle.DangerousAddRef(ref addRefSucceeded);
                if (!addRefSucceeded)
                {
                    throw new ObjectDisposedException("launchCompleteHandle");
                }

                IntPtr   nativeHandle = safeWaitHandle.DangerousGetHandle();
                IntPtr[] handles      = { nativeHandle };
                uint     waitResult;

                hr = _messagePump.ModalWaitForObjects(handles, (uint)handles.Length, out waitResult);
                if (hr == 0)
                {
                    return;
                }
                else if (hr == VSConstants.E_PENDING || hr == VSConstants.E_ABORT)
                {
                    // E_PENDING: user canceled
                    // E_ABORT: application exit
                    cancellationSource.Cancel();

                    throw new OperationCanceledException();
                }
                else
                {
                    Debug.Fail("Unexpected result from ModalWaitForObjects");
                    Marshal.ThrowExceptionForHR(hr);
                }
            }
            finally
            {
                if (addRefSucceeded)
                {
                    safeWaitHandle.DangerousRelease();
                }
            }
        }
Exemple #23
0
        private bool JoinCore(int millisecondsTimeout)
        {
            SafeWaitHandle waitHandle = _osHandle;
            int            result;

            waitHandle.DangerousAddRef();
            try
            {
                result = WaitHandle.WaitForSingleObject(waitHandle.DangerousGetHandle(), millisecondsTimeout);
            }
            finally
            {
                waitHandle.DangerousRelease();
            }

            return(result == (int)Interop.Constants.WaitObject0);
        }
        private bool JoinInternal(int millisecondsTimeout)
        {
            // This method assumes the thread has been started
            Debug.Assert(!GetThreadStateBit(ThreadState.Unstarted) || (millisecondsTimeout == 0));
            SafeWaitHandle waitHandle = _osHandle;

            // If an OS thread is terminated and its Thread object is resurrected, _osHandle may be finalized and closed
            if (waitHandle.IsClosed)
            {
                return(true);
            }

            // Handle race condition with the finalizer
            try
            {
                waitHandle.DangerousAddRef();
            }
            catch (ObjectDisposedException)
            {
                return(true);
            }

            try
            {
                int result;

                if (millisecondsTimeout == 0)
                {
                    result = (int)Interop.Kernel32.WaitForSingleObject(waitHandle.DangerousGetHandle(), 0);
                }
                else
                {
                    result = WaitHandle.WaitOneCore(waitHandle.DangerousGetHandle(), millisecondsTimeout);
                }

                return(result == (int)Interop.Kernel32.WAIT_OBJECT_0);
            }
            finally
            {
                waitHandle.DangerousRelease();
            }
        }
Exemple #25
0
        private int ReleaseCore(int releaseCount)
        {
            // The field value is modifiable via the public <see cref="WaitHandle.SafeWaitHandle"/> property, save it locally
            // to ensure that one instance is used in all places in this method
            SafeWaitHandle waitHandle = _waitHandle;

            if (waitHandle == null)
            {
                ThrowInvalidHandleException();
            }

            waitHandle.DangerousAddRef();
            try
            {
                return(ReleaseCore(waitHandle.DangerousGetHandle(), releaseCount));
            }
            finally
            {
                waitHandle.DangerousRelease();
            }
        }
        public bool Reset()
        {
            // The field value is modifiable via <see cref="SafeWaitHandle"/>, save it locally to ensure that ref modification
            // is done on the same instance
            SafeWaitHandle waitHandle = _waitHandle;

            if (waitHandle == null)
            {
                ThrowInvalidHandleException();
            }

            waitHandle.DangerousAddRef();
            try
            {
                return(ResetCore(_waitHandle.DangerousGetHandle()));
            }
            finally
            {
                waitHandle.DangerousRelease();
            }
        }
Exemple #27
0
        public void ReleaseMutex()
        {
            // The field value is modifiable via the public <see cref="WaitHandle.SafeWaitHandle"/> property, save it locally
            // to ensure that one instance is used in all places in this method
            SafeWaitHandle waitHandle = _waitHandle;

            if (waitHandle == null)
            {
                ThrowInvalidHandleException();
            }

            waitHandle.DangerousAddRef();
            try
            {
                WaitSubsystem.ReleaseMutex(waitHandle.DangerousGetHandle());
            }
            finally
            {
                waitHandle.DangerousRelease();
            }
        }
Exemple #28
0
        private bool WaitOneCore(int millisecondsTimeout, bool interruptible = true)
        {
            Debug.Assert(millisecondsTimeout >= -1);

            // The field value is modifiable via the public <see cref="WaitHandle.SafeWaitHandle"/> property, save it locally
            // to ensure that one instance is used in all places in this method
            SafeWaitHandle waitHandle = _waitHandle;

            if (waitHandle == null)
            {
                // Throw ObjectDisposedException for backward compatibility even though it is not be representative of the issue
                throw new ObjectDisposedException(null, SR.ObjectDisposed_Generic);
            }

            waitHandle.DangerousAddRef();
            try
            {
                return(WaitOneCore(waitHandle.DangerousGetHandle(), millisecondsTimeout, interruptible));
            }
            finally
            {
                waitHandle.DangerousRelease();
            }
        }
Exemple #29
0
        private void SignalNoCallbacksRunning()
        {
            object toSignal = _notifyWhenNoCallbacksRunning;

            Debug.Assert(toSignal is WaitHandle || toSignal is Task <bool>);

            if (toSignal is WaitHandle wh)
            {
                SafeWaitHandle waitHandle = wh.SafeWaitHandle;
                waitHandle.DangerousAddRef();
                try
                {
                    WaitSubsystem.SetEvent(waitHandle.DangerousGetHandle());
                }
                finally
                {
                    waitHandle.DangerousRelease();
                }
            }
            else
            {
                ((Task <bool>)toSignal).TrySetResult(true);
            }
        }
Exemple #30
0
        ///////////////////////////////////////////////////////////////////////////////////////////////

        //
        // WARNING: Contains a "Constrained Execution Region", modify carefully.
        //
        private static ReturnCode WaitForSingleHandle(
            WaitHandle waitHandle,
            int milliseconds,
            bool userInterface,
            ref uint returnValue,
            ref Result error
            )
        {
            SafeWaitHandle safeWaitHandle = null;
            bool           success        = false;

            RuntimeHelpers.PrepareConstrainedRegions();

            try
            {
                if (waitHandle == null)
                {
                    error = "invalid wait handle";
                    return(ReturnCode.Error);
                }

                safeWaitHandle = waitHandle.SafeWaitHandle;

                if (safeWaitHandle == null)
                {
                    error = "invalid safe wait handle";
                    return(ReturnCode.Error);
                }

                safeWaitHandle.DangerousAddRef(ref success);

                if (!success)
                {
                    error = "failed to add reference to safe wait handle";
                    return(ReturnCode.Error);
                }

                IntPtr[] handles = { safeWaitHandle.DangerousGetHandle() };

                if (handles[0] == IntPtr.Zero)
                {
                    error = "failed to get native handle from safe wait handle";
                    return(ReturnCode.Error);
                }

                if (userInterface)
                {
                    returnValue = UnsafeNativeMethods.MsgWaitForMultipleObjectsEx(
                        1, handles, (uint)milliseconds, UnsafeNativeMethods.QS_ALLINPUT,
                        UnsafeNativeMethods.MWMO_DEFAULT);
                }
                else
                {
                    returnValue = UnsafeNativeMethods.WaitForMultipleObjectsEx(
                        1, handles, false, (uint)milliseconds, true);
                }

                return(ReturnCode.Ok);
            }
            catch (Exception e)
            {
                if (traceException)
                {
                    TraceOps.DebugTrace(
                        e, typeof(WindowOps).Name,
                        TracePriority.NativeError);
                }

                error = e;
            }
            finally
            {
                if (success)
                {
                    safeWaitHandle.DangerousRelease();
                    success = false;
                }
            }

            return(ReturnCode.Error);
        }