summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/System.Private.CoreLib/System.Private.CoreLib.csproj2
-rw-r--r--src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems1
-rw-r--r--src/System.Private.CoreLib/shared/System/Threading/EventWaitHandle.Windows.cs4
-rw-r--r--src/System.Private.CoreLib/shared/System/Threading/Mutex.Windows.cs2
-rw-r--r--src/System.Private.CoreLib/shared/System/Threading/WaitHandle.cs437
-rw-r--r--src/System.Private.CoreLib/src/System/Threading/WaitHandle.CoreCLR.cs41
-rw-r--r--src/System.Private.CoreLib/src/System/Threading/WaitHandle.cs471
-rw-r--r--src/vm/comwaithandle.cpp162
-rw-r--r--src/vm/comwaithandle.h7
-rw-r--r--src/vm/ecalllist.h7
10 files changed, 519 insertions, 615 deletions
diff --git a/src/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/System.Private.CoreLib/System.Private.CoreLib.csproj
index cd84eb2e31..595ed87a50 100644
--- a/src/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -260,7 +260,7 @@
<Compile Include="$(BclSourcesRoot)\System\Threading\Thread.cs" />
<Compile Include="$(BclSourcesRoot)\System\Threading\ThreadPool.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\Threading\Timer.CoreCLR.cs" />
- <Compile Include="$(BclSourcesRoot)\System\Threading\WaitHandle.cs" />
+ <Compile Include="$(BclSourcesRoot)\System\Threading\WaitHandle.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\Type.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\TypedReference.cs" />
<Compile Include="$(BclSourcesRoot)\System\TypeLoadException.cs" />
diff --git a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems
index 6d9eea8c6c..97c12067f1 100644
--- a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems
+++ b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems
@@ -840,6 +840,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\Timeout.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\TimeoutHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\Timer.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Threading\WaitHandle.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\WaitHandleCannotBeOpenedException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\ThreadStaticAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\ThrowHelper.cs" />
diff --git a/src/System.Private.CoreLib/shared/System/Threading/EventWaitHandle.Windows.cs b/src/System.Private.CoreLib/shared/System/Threading/EventWaitHandle.Windows.cs
index 0d41e2a88d..62b3e4f9fc 100644
--- a/src/System.Private.CoreLib/shared/System/Threading/EventWaitHandle.Windows.cs
+++ b/src/System.Private.CoreLib/shared/System/Threading/EventWaitHandle.Windows.cs
@@ -76,7 +76,7 @@ namespace System.Threading
public bool Reset()
{
- bool res = Interop.Kernel32.ResetEvent(_waitHandle);
+ bool res = Interop.Kernel32.ResetEvent(SafeWaitHandle);
if (!res)
throw Win32Marshal.GetExceptionForLastWin32Error();
return res;
@@ -84,7 +84,7 @@ namespace System.Threading
public bool Set()
{
- bool res = Interop.Kernel32.SetEvent(_waitHandle);
+ bool res = Interop.Kernel32.SetEvent(SafeWaitHandle);
if (!res)
throw Win32Marshal.GetExceptionForLastWin32Error();
return res;
diff --git a/src/System.Private.CoreLib/shared/System/Threading/Mutex.Windows.cs b/src/System.Private.CoreLib/shared/System/Threading/Mutex.Windows.cs
index c40ab94dc3..26eb4fe5ab 100644
--- a/src/System.Private.CoreLib/shared/System/Threading/Mutex.Windows.cs
+++ b/src/System.Private.CoreLib/shared/System/Threading/Mutex.Windows.cs
@@ -90,7 +90,7 @@ namespace System.Threading
// in a Mutex's ACL is MUTEX_ALL_ACCESS (0x1F0001).
public void ReleaseMutex()
{
- if (!Interop.Kernel32.ReleaseMutex(_waitHandle))
+ if (!Interop.Kernel32.ReleaseMutex(SafeWaitHandle))
{
throw new ApplicationException(SR.Arg_SynchronizationLockException);
}
diff --git a/src/System.Private.CoreLib/shared/System/Threading/WaitHandle.cs b/src/System.Private.CoreLib/shared/System/Threading/WaitHandle.cs
new file mode 100644
index 0000000000..d90db240a2
--- /dev/null
+++ b/src/System.Private.CoreLib/shared/System/Threading/WaitHandle.cs
@@ -0,0 +1,437 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using Microsoft.Win32.SafeHandles;
+
+namespace System.Threading
+{
+ public abstract partial class WaitHandle : MarshalByRefObject, IDisposable
+ {
+ internal const int MaxWaitHandles = 64;
+
+ protected static readonly IntPtr InvalidHandle = new IntPtr(-1);
+
+ // IMPORTANT:
+ // - Do not add or rearrange fields as the EE depends on this layout.
+
+ private SafeWaitHandle _waitHandle;
+
+ [ThreadStatic]
+ private static SafeWaitHandle[] t_safeWaitHandlesForRent;
+
+ private protected enum OpenExistingResult
+ {
+ Success,
+ NameNotFound,
+ PathNotFound,
+ NameInvalid
+ }
+
+ // The wait result values below match Win32 wait result codes (WAIT_OBJECT_0,
+ // WAIT_ABANDONED, WAIT_TIMEOUT).
+
+ // Successful wait on first object. When waiting for multiple objects the
+ // return value is (WaitSuccess + waitIndex).
+ internal const int WaitSuccess = 0;
+
+ // The specified object is a mutex object that was not released by the
+ // thread that owned the mutex object before the owning thread terminated.
+ // When waiting for multiple objects the return value is (WaitAbandoned +
+ // waitIndex).
+ internal const int WaitAbandoned = 0x80;
+
+ internal const int WaitTimeout = 0x102;
+
+ protected WaitHandle()
+ {
+ }
+
+ [Obsolete("Use the SafeWaitHandle property instead.")]
+ public virtual IntPtr Handle
+ {
+ get
+ {
+ return _waitHandle == null ? InvalidHandle : _waitHandle.DangerousGetHandle();
+ }
+ set
+ {
+ if (value == InvalidHandle)
+ {
+ // This line leaks a handle. However, it's currently
+ // not perfectly clear what the right behavior is here
+ // anyways. This preserves Everett behavior. We should
+ // ideally do these things:
+ // *) Expose a settable SafeHandle property on WaitHandle.
+ // *) Expose a settable OwnsHandle property on SafeHandle.
+ if (_waitHandle != null)
+ {
+ _waitHandle.SetHandleAsInvalid();
+ _waitHandle = null;
+ }
+ }
+ else
+ {
+ _waitHandle = new SafeWaitHandle(value, true);
+ }
+ }
+ }
+
+ public SafeWaitHandle SafeWaitHandle
+ {
+ get
+ {
+ if (_waitHandle == null)
+ {
+ _waitHandle = new SafeWaitHandle(InvalidHandle, false);
+ }
+ return _waitHandle;
+ }
+ set
+ {
+ _waitHandle = value;
+ }
+ }
+
+ internal static int ToTimeoutMilliseconds(TimeSpan timeout)
+ {
+ var timeoutMilliseconds = (long)timeout.TotalMilliseconds;
+ if (timeoutMilliseconds < -1)
+ {
+ throw new ArgumentOutOfRangeException(nameof(timeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
+ }
+ if (timeoutMilliseconds > int.MaxValue)
+ {
+ throw new ArgumentOutOfRangeException(nameof(timeout), SR.ArgumentOutOfRange_LessEqualToIntegerMaxVal);
+ }
+ return (int)timeoutMilliseconds;
+ }
+
+ public virtual void Close() => Dispose();
+
+ protected virtual void Dispose(bool explicitDisposing)
+ {
+ _waitHandle?.Close();
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ public virtual bool WaitOne(int millisecondsTimeout)
+ {
+ if (millisecondsTimeout < -1)
+ {
+ throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
+ }
+
+ return WaitOneNoCheck(millisecondsTimeout);
+ }
+
+ 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();
+ }
+ }
+
+ // Returns an array for storing SafeWaitHandles in WaitMultiple calls. The array
+ // is reused for subsequent calls to reduce GC pressure.
+ private static SafeWaitHandle[] RentSafeWaitHandleArray(int capacity)
+ {
+ SafeWaitHandle[] safeWaitHandles = t_safeWaitHandlesForRent;
+
+ t_safeWaitHandlesForRent = null;
+
+ // t_safeWaitHandlesForRent can be null when it was not initialized yet or
+ // if a re-entrant wait is performed and the array is already rented. In
+ // that case we just allocate a new one and reuse it as necessary.
+ if (safeWaitHandles == null || safeWaitHandles.Length < capacity)
+ {
+ // Always allocate at least 4 slots to prevent unnecessary reallocations
+ safeWaitHandles = new SafeWaitHandle[Math.Max(capacity, 4)];
+ }
+
+ return safeWaitHandles;
+ }
+
+ private static void ReturnSafeWaitHandleArray(SafeWaitHandle[] safeWaitHandles)
+ => t_safeWaitHandlesForRent = safeWaitHandles;
+
+ /// <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;
+ 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);
+ }
+
+ 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)
+ {
+ lastSafeWaitHandle.DangerousRelease();
+ }
+
+ throw;
+ }
+ }
+
+ private static int WaitMultiple(ReadOnlySpan<WaitHandle> waitHandles, bool waitAll, int millisecondsTimeout)
+ {
+ if (waitHandles == null)
+ {
+ throw new ArgumentNullException(nameof(waitHandles), SR.ArgumentNull_Waithandles);
+ }
+ if (waitHandles.Length == 0)
+ {
+ //
+ // Some history: in CLR 1.0 and 1.1, we threw ArgumentException in this case, which was correct.
+ // Somehow, in 2.0, this became ArgumentNullException. This was not fixed until Silverlight 2,
+ // which went back to ArgumentException.
+ //
+ // Now we're in a bit of a bind. Backward-compatibility requires us to keep throwing ArgumentException
+ // in CoreCLR, and ArgumentNullException in the desktop CLR. This is ugly, but so is breaking
+ // user code.
+ //
+ throw new ArgumentException(SR.Argument_EmptyWaithandleArray, nameof(waitHandles));
+ }
+ if (waitHandles.Length > MaxWaitHandles)
+ {
+ throw new NotSupportedException(SR.NotSupported_MaxWaitHandles);
+ }
+ if (millisecondsTimeout < -1)
+ {
+ throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
+ }
+
+ SynchronizationContext context = SynchronizationContext.Current;
+ bool useWaitContext = context != null && context.IsWaitNotificationRequired();
+ SafeWaitHandle[] safeWaitHandles = RentSafeWaitHandleArray(waitHandles.Length);
+
+ try
+ {
+ int waitResult;
+
+ if (useWaitContext)
+ {
+ IntPtr[] unsafeWaitHandles = new IntPtr[waitHandles.Length];
+ ObtainSafeWaitHandles(waitHandles, safeWaitHandles, unsafeWaitHandles);
+ waitResult = context.Wait(unsafeWaitHandles, waitAll, millisecondsTimeout);
+ }
+ else
+ {
+ Span<IntPtr> unsafeWaitHandles = stackalloc IntPtr[waitHandles.Length];
+ ObtainSafeWaitHandles(waitHandles, safeWaitHandles, unsafeWaitHandles);
+ waitResult = WaitMultipleIgnoringSyncContext(unsafeWaitHandles, waitAll, millisecondsTimeout);
+ }
+
+ if (waitResult >= WaitAbandoned && waitResult < WaitAbandoned + waitHandles.Length)
+ {
+ if (waitAll)
+ {
+ // In the case of WaitAll the OS will only provide the information that mutex was abandoned.
+ // It won't tell us which one. So we can't set the Index or provide access to the Mutex
+ throw new AbandonedMutexException();
+ }
+
+ waitResult -= WaitAbandoned;
+ throw new AbandonedMutexException(waitResult, waitHandles[waitResult]);
+ }
+
+ return waitResult;
+ }
+ finally
+ {
+ for (int i = 0; i < waitHandles.Length; ++i)
+ {
+ if (safeWaitHandles[i] != null)
+ {
+ safeWaitHandles[i].DangerousRelease();
+ safeWaitHandles[i] = null;
+ }
+ }
+
+ ReturnSafeWaitHandleArray(safeWaitHandles);
+ }
+ }
+
+ 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();
+ }
+ }
+ }
+
+ public virtual bool WaitOne(TimeSpan timeout) => WaitOneNoCheck(ToTimeoutMilliseconds(timeout));
+ public virtual bool WaitOne() => WaitOneNoCheck(-1);
+ public virtual bool WaitOne(int millisecondsTimeout, bool exitContext) => WaitOne(millisecondsTimeout);
+ public virtual bool WaitOne(TimeSpan timeout, bool exitContext) => WaitOneNoCheck(ToTimeoutMilliseconds(timeout));
+
+ public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout) =>
+ WaitMultiple(waitHandles, true, millisecondsTimeout) != WaitTimeout;
+ public static bool WaitAll(WaitHandle[] waitHandles, TimeSpan timeout) =>
+ WaitMultiple(waitHandles, true, ToTimeoutMilliseconds(timeout)) != WaitTimeout;
+ public static bool WaitAll(WaitHandle[] waitHandles) =>
+ WaitMultiple(waitHandles, true, -1) != WaitTimeout;
+ public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) =>
+ WaitMultiple(waitHandles, true, millisecondsTimeout) != WaitTimeout;
+ public static bool WaitAll(WaitHandle[] waitHandles, TimeSpan timeout, bool exitContext) =>
+ WaitMultiple(waitHandles, true, ToTimeoutMilliseconds(timeout)) != WaitTimeout;
+
+ public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout) =>
+ WaitMultiple(waitHandles, false, millisecondsTimeout);
+ public static int WaitAny(WaitHandle[] waitHandles, TimeSpan timeout) =>
+ WaitMultiple(waitHandles, false, ToTimeoutMilliseconds(timeout));
+ public static int WaitAny(WaitHandle[] waitHandles) =>
+ WaitMultiple(waitHandles, false, -1);
+ public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) =>
+ WaitMultiple(waitHandles, false, millisecondsTimeout);
+ public static int WaitAny(WaitHandle[] waitHandles, TimeSpan timeout, bool exitContext) =>
+ WaitMultiple(waitHandles, false, ToTimeoutMilliseconds(timeout));
+
+ public static bool SignalAndWait(WaitHandle toSignal, WaitHandle toWaitOn) =>
+ SignalAndWait(toSignal, toWaitOn, -1);
+ public static bool SignalAndWait(WaitHandle toSignal, WaitHandle toWaitOn, TimeSpan timeout, bool exitContext) =>
+ SignalAndWait(toSignal, toWaitOn, ToTimeoutMilliseconds(timeout));
+ public static bool SignalAndWait(WaitHandle toSignal, WaitHandle toWaitOn, int millisecondsTimeout, bool exitContext) =>
+ SignalAndWait(toSignal, toWaitOn, millisecondsTimeout);
+ }
+}
diff --git a/src/System.Private.CoreLib/src/System/Threading/WaitHandle.CoreCLR.cs b/src/System.Private.CoreLib/src/System/Threading/WaitHandle.CoreCLR.cs
new file mode 100644
index 0000000000..97b5c574e3
--- /dev/null
+++ b/src/System.Private.CoreLib/src/System/Threading/WaitHandle.CoreCLR.cs
@@ -0,0 +1,41 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace System.Threading
+{
+ public abstract partial class WaitHandle
+ {
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern int WaitOneCore(IntPtr waitHandle, int millisecondsTimeout);
+
+ internal static unsafe int WaitMultipleIgnoringSyncContext(Span<IntPtr> waitHandles, bool waitAll, int millisecondsTimeout)
+ {
+ fixed (IntPtr *pWaitHandles = &MemoryMarshal.GetReference(waitHandles))
+ {
+ return WaitMultipleIgnoringSyncContext(pWaitHandles, waitHandles.Length, waitAll, millisecondsTimeout);
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static unsafe extern int WaitMultipleIgnoringSyncContext(IntPtr *waitHandles, int numHandles, bool waitAll, int millisecondsTimeout);
+
+ private static int SignalAndWaitCore(IntPtr waitHandleToSignal, IntPtr waitHandleToWaitOn, int millisecondsTimeout)
+ {
+ int ret = SignalAndWaitNative(waitHandleToSignal, waitHandleToWaitOn, millisecondsTimeout);
+
+ if (ret == Interop.Errors.ERROR_TOO_MANY_POSTS)
+ {
+ throw new InvalidOperationException(SR.Threading_WaitHandleTooManyPosts);
+ }
+
+ return ret;
+ }
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern int SignalAndWaitNative(IntPtr waitHandleToSignal, IntPtr waitHandleToWaitOn, int millisecondsTimeout);
+ }
+}
diff --git a/src/System.Private.CoreLib/src/System/Threading/WaitHandle.cs b/src/System.Private.CoreLib/src/System/Threading/WaitHandle.cs
deleted file mode 100644
index a5a5643df0..0000000000
--- a/src/System.Private.CoreLib/src/System/Threading/WaitHandle.cs
+++ /dev/null
@@ -1,471 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-//
-/*=============================================================================
-**
-**
-**
-** Purpose: Class to represent all synchronization objects in the runtime (that allow multiple wait)
-**
-**
-=============================================================================*/
-
-using System;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using Microsoft.Win32.SafeHandles;
-using System.Diagnostics.CodeAnalysis;
-
-namespace System.Threading
-{
- public abstract class WaitHandle : MarshalByRefObject, IDisposable
- {
- public const int WaitTimeout = 0x102;
-
- private const int MAX_WAITHANDLES = 64;
-
- // IMPORTANT:
- // - Do not add or rearrange fields as the EE depends on this layout.
-
- internal SafeWaitHandle _waitHandle;
-
- protected static readonly IntPtr InvalidHandle = new IntPtr(-1);
- private const int WAIT_OBJECT_0 = 0;
- private const int WAIT_ABANDONED = 0x80;
- private const int WAIT_FAILED = 0x7FFFFFFF;
- private const int ERROR_TOO_MANY_POSTS = 0x12A;
-
- internal enum OpenExistingResult
- {
- Success,
- NameNotFound,
- PathNotFound,
- NameInvalid
- }
-
- protected WaitHandle()
- {
- }
-
- [Obsolete("Use the SafeWaitHandle property instead.")]
- public virtual IntPtr Handle
- {
- get { return _waitHandle == null ? InvalidHandle : _waitHandle.DangerousGetHandle(); }
- set
- {
- if (value == InvalidHandle)
- {
- // This line leaks a handle. However, it's currently
- // not perfectly clear what the right behavior is here
- // anyways. This preserves Everett behavior. We should
- // ideally do these things:
- // *) Expose a settable SafeHandle property on WaitHandle.
- // *) Expose a settable OwnsHandle property on SafeHandle.
- if (_waitHandle != null)
- {
- _waitHandle.SetHandleAsInvalid();
- _waitHandle = null;
- }
- }
- else
- {
- _waitHandle = new SafeWaitHandle(value, true);
- }
- }
- }
-
- public SafeWaitHandle SafeWaitHandle
- {
- get
- {
- if (_waitHandle == null)
- {
- _waitHandle = new SafeWaitHandle(InvalidHandle, false);
- }
- return _waitHandle;
- }
-
- set
- {
- _waitHandle = value;
- }
- }
-
- public virtual bool WaitOne(int millisecondsTimeout, bool exitContext)
- {
- if (millisecondsTimeout < -1)
- {
- throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
- }
- return WaitOne((long)millisecondsTimeout, exitContext);
- }
-
- public virtual bool WaitOne(TimeSpan timeout, bool exitContext)
- {
- long tm = (long)timeout.TotalMilliseconds;
- if (-1 > tm || (long)int.MaxValue < tm)
- {
- throw new ArgumentOutOfRangeException(nameof(timeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
- }
- return WaitOne(tm, exitContext);
- }
-
- public virtual bool WaitOne()
- {
- //Infinite Timeout
- return WaitOne(-1, false);
- }
-
- public virtual bool WaitOne(int millisecondsTimeout)
- {
- return WaitOne(millisecondsTimeout, false);
- }
-
- public virtual bool WaitOne(TimeSpan timeout)
- {
- return WaitOne(timeout, false);
- }
-
- [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "Reviewed for thread-safety.")]
- private bool WaitOne(long timeout, bool exitContext)
- {
- return InternalWaitOne(_waitHandle, timeout, exitContext);
- }
-
- internal static bool InternalWaitOne(SafeHandle waitableSafeHandle, long millisecondsTimeout, bool exitContext)
- {
- if (waitableSafeHandle == null)
- {
- throw new ObjectDisposedException(null, SR.ObjectDisposed_Generic);
- }
- int ret = WaitOneNative(waitableSafeHandle, (uint)millisecondsTimeout, exitContext);
-
- if (ret == WAIT_ABANDONED)
- {
- ThrowAbandonedMutexException();
- }
- return (ret != WaitTimeout);
- }
-
- internal bool WaitOneWithoutFAS()
- {
- // version of waitone without fast application switch (FAS) support
- // This is required to support the Wait which FAS needs (otherwise recursive dependency comes in)
- if (_waitHandle == null)
- {
- throw new ObjectDisposedException(null, SR.ObjectDisposed_Generic);
- }
-
- long timeout = -1;
- int ret = WaitOneNative(_waitHandle, (uint)timeout, false);
- if (ret == WAIT_ABANDONED)
- {
- ThrowAbandonedMutexException();
- }
- return (ret != WaitTimeout);
- }
-
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private static extern int WaitOneNative(SafeHandle waitableSafeHandle, uint millisecondsTimeout, bool exitContext);
-
- /*========================================================================
- ** Waits for signal from all the objects.
- ** timeout indicates how long to wait before the method returns.
- ** This method will return either when all the object have been pulsed
- ** or timeout milliseconds have elapsed.
- ** If exitContext is true then the synchronization domain for the context
- ** (if in a synchronized context) is exited before the wait and reacquired
- ========================================================================*/
-
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private static extern int WaitMultiple(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext, bool WaitAll);
-
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal static extern int WaitMultipleIgnoringSyncContext(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout);
-
- public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
- {
- if (waitHandles == null)
- {
- throw new ArgumentNullException(nameof(waitHandles), SR.ArgumentNull_Waithandles);
- }
- if (waitHandles.Length == 0)
- {
- //
- // Some history: in CLR 1.0 and 1.1, we threw ArgumentException in this case, which was correct.
- // Somehow, in 2.0, this became ArgumentNullException. This was not fixed until Silverlight 2,
- // which went back to ArgumentException.
- //
- // Now we're in a bit of a bind. Backward-compatibility requires us to keep throwing ArgumentException
- // in CoreCLR, and ArgumentNullException in the desktop CLR. This is ugly, but so is breaking
- // user code.
- //
- throw new ArgumentException(SR.Argument_EmptyWaithandleArray);
- }
- if (waitHandles.Length > MAX_WAITHANDLES)
- {
- throw new NotSupportedException(SR.NotSupported_MaxWaitHandles);
- }
- if (-1 > millisecondsTimeout)
- {
- throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
- }
- WaitHandle[] internalWaitHandles = new WaitHandle[waitHandles.Length];
- for (int i = 0; i < waitHandles.Length; i++)
- {
- WaitHandle waitHandle = waitHandles[i];
-
- if (waitHandle == null)
- throw new ArgumentNullException("waitHandles[" + i + "]", SR.ArgumentNull_ArrayElement);
-
- internalWaitHandles[i] = waitHandle;
- }
-#if DEBUG
- // make sure we do not use waitHandles any more.
- waitHandles = null;
-#endif
-
- int ret = WaitMultiple(internalWaitHandles, millisecondsTimeout, exitContext, true /* waitall*/ );
-
- if ((WAIT_ABANDONED <= ret) && (WAIT_ABANDONED + internalWaitHandles.Length > ret))
- {
- //In the case of WaitAll the OS will only provide the
- // information that mutex was abandoned.
- // It won't tell us which one. So we can't set the Index or provide access to the Mutex
- ThrowAbandonedMutexException();
- }
-
- GC.KeepAlive(internalWaitHandles);
- return (ret != WaitTimeout);
- }
-
- public static bool WaitAll(
- WaitHandle[] waitHandles,
- TimeSpan timeout,
- bool exitContext)
- {
- long tm = (long)timeout.TotalMilliseconds;
- if (-1 > tm || (long)int.MaxValue < tm)
- {
- throw new ArgumentOutOfRangeException(nameof(timeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
- }
- return WaitAll(waitHandles, (int)tm, exitContext);
- }
-
-
- /*========================================================================
- ** Shorthand for WaitAll with timeout = Timeout.Infinite and exitContext = true
- ========================================================================*/
- public static bool WaitAll(WaitHandle[] waitHandles)
- {
- return WaitAll(waitHandles, Timeout.Infinite, true);
- }
-
- public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout)
- {
- return WaitAll(waitHandles, millisecondsTimeout, true);
- }
-
- public static bool WaitAll(WaitHandle[] waitHandles, TimeSpan timeout)
- {
- return WaitAll(waitHandles, timeout, true);
- }
-
-
- /*========================================================================
- ** Waits for notification from any of the objects.
- ** timeout indicates how long to wait before the method returns.
- ** This method will return either when either one of the object have been
- ** signaled or timeout milliseconds have elapsed.
- ** If exitContext is true then the synchronization domain for the context
- ** (if in a synchronized context) is exited before the wait and reacquired
- ========================================================================*/
-
- public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
- {
- if (waitHandles == null)
- {
- throw new ArgumentNullException(nameof(waitHandles), SR.ArgumentNull_Waithandles);
- }
- if (waitHandles.Length == 0)
- {
- throw new ArgumentException(SR.Argument_EmptyWaithandleArray);
- }
- if (MAX_WAITHANDLES < waitHandles.Length)
- {
- throw new NotSupportedException(SR.NotSupported_MaxWaitHandles);
- }
- if (-1 > millisecondsTimeout)
- {
- throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
- }
- WaitHandle[] internalWaitHandles = new WaitHandle[waitHandles.Length];
- for (int i = 0; i < waitHandles.Length; i++)
- {
- WaitHandle waitHandle = waitHandles[i];
-
- if (waitHandle == null)
- throw new ArgumentNullException("waitHandles[" + i + "]", SR.ArgumentNull_ArrayElement);
-
- internalWaitHandles[i] = waitHandle;
- }
-#if DEBUG
- // make sure we do not use waitHandles any more.
- waitHandles = null;
-#endif
- int ret = WaitMultiple(internalWaitHandles, millisecondsTimeout, exitContext, false /* waitany*/ );
-
- if ((WAIT_ABANDONED <= ret) && (WAIT_ABANDONED + internalWaitHandles.Length > ret))
- {
- int mutexIndex = ret - WAIT_ABANDONED;
- if (0 <= mutexIndex && mutexIndex < internalWaitHandles.Length)
- {
- ThrowAbandonedMutexException(mutexIndex, internalWaitHandles[mutexIndex]);
- }
- else
- {
- ThrowAbandonedMutexException();
- }
- }
-
- GC.KeepAlive(internalWaitHandles);
- return ret;
- }
-
- public static int WaitAny(
- WaitHandle[] waitHandles,
- TimeSpan timeout,
- bool exitContext)
- {
- long tm = (long)timeout.TotalMilliseconds;
- if (-1 > tm || (long)int.MaxValue < tm)
- {
- throw new ArgumentOutOfRangeException(nameof(timeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
- }
- return WaitAny(waitHandles, (int)tm, exitContext);
- }
- public static int WaitAny(WaitHandle[] waitHandles, TimeSpan timeout)
- {
- return WaitAny(waitHandles, timeout, true);
- }
-
-
- /*========================================================================
- ** Shorthand for WaitAny with timeout = Timeout.Infinite and exitContext = true
- ========================================================================*/
- public static int WaitAny(WaitHandle[] waitHandles)
- {
- return WaitAny(waitHandles, Timeout.Infinite, true);
- }
-
- public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout)
- {
- return WaitAny(waitHandles, millisecondsTimeout, true);
- }
-
- /*=================================================
- ==
- == SignalAndWait
- ==
- ==================================================*/
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private static extern int SignalAndWaitOne(SafeWaitHandle waitHandleToSignal, SafeWaitHandle waitHandleToWaitOn, int millisecondsTimeout,
- bool exitContext);
-
- public static bool SignalAndWait(
- WaitHandle toSignal,
- WaitHandle toWaitOn)
- {
- return SignalAndWait(toSignal, toWaitOn, -1, false);
- }
-
- public static bool SignalAndWait(
- WaitHandle toSignal,
- WaitHandle toWaitOn,
- TimeSpan timeout,
- bool exitContext)
- {
- long tm = (long)timeout.TotalMilliseconds;
- if (-1 > tm || (long)int.MaxValue < tm)
- {
- throw new ArgumentOutOfRangeException(nameof(timeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
- }
- return SignalAndWait(toSignal, toWaitOn, (int)tm, exitContext);
- }
-
- [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "Reviewed for thread-safety.")]
- public static bool SignalAndWait(
- WaitHandle toSignal,
- WaitHandle toWaitOn,
- int millisecondsTimeout,
- bool exitContext)
- {
- if (null == toSignal)
- {
- throw new ArgumentNullException(nameof(toSignal));
- }
- if (null == toWaitOn)
- {
- throw new ArgumentNullException(nameof(toWaitOn));
- }
- if (-1 > millisecondsTimeout)
- {
- throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
- }
-
- //NOTE: This API is not supporting Pause/Resume as it's not exposed in CoreCLR (not in WP or SL)
- int ret = SignalAndWaitOne(toSignal._waitHandle, toWaitOn._waitHandle, millisecondsTimeout, exitContext);
-
- if (WAIT_ABANDONED == ret)
- {
- ThrowAbandonedMutexException();
- }
-
- if (ERROR_TOO_MANY_POSTS == ret)
- {
- throw new InvalidOperationException(SR.Threading_WaitHandleTooManyPosts);
- }
-
- //Object was signaled
- if (WAIT_OBJECT_0 == ret)
- {
- return true;
- }
-
- //Timeout
- return false;
- }
-
- private static void ThrowAbandonedMutexException()
- {
- throw new AbandonedMutexException();
- }
-
- private static void ThrowAbandonedMutexException(int location, WaitHandle handle)
- {
- throw new AbandonedMutexException(location, handle);
- }
-
- public virtual void Close()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- protected virtual void Dispose(bool explicitDisposing)
- {
- if (_waitHandle != null)
- {
- _waitHandle.Close();
- }
- }
-
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
- }
-}
diff --git a/src/vm/comwaithandle.cpp b/src/vm/comwaithandle.cpp
index abb1daf16b..d6c7da37aa 100644
--- a/src/vm/comwaithandle.cpp
+++ b/src/vm/comwaithandle.cpp
@@ -78,37 +78,6 @@ private:
}
};
-void AcquireSafeHandleFromWaitHandle(WAITHANDLEREF wh)
-{
- CONTRACTL {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(wh != NULL);
- } CONTRACTL_END;
-
- SAFEHANDLEREF sh = wh->GetSafeHandle();
- if (sh == NULL)
- COMPlusThrow(kObjectDisposedException);
- sh->AddRef();
-}
-
-void ReleaseSafeHandleFromWaitHandle(WAITHANDLEREF wh)
-{
- CONTRACTL {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(wh != NULL);
- } CONTRACTL_END;
-
- SAFEHANDLEREF sh = wh->GetSafeHandle();
- _ASSERTE(sh);
- sh->Release();
-}
-
-typedef ObjArrayHolder<WAITHANDLEREF, AcquireSafeHandleFromWaitHandle, ReleaseSafeHandleFromWaitHandle> WaitHandleArrayHolder;
-
INT64 AdditionalWait(INT64 sPauseTime, INT64 sTime, INT64 expDuration)
{
LIMITED_METHOD_CONTRACT;
@@ -157,91 +126,58 @@ INT64 AdditionalWait(INT64 sPauseTime, INT64 sTime, INT64 expDuration)
return additional;
}
-FCIMPL3(INT32, WaitHandleNative::CorWaitOneNative, SafeHandle* safeWaitHandleUNSAFE, INT32 timeout, CLR_BOOL exitContext)
+FCIMPL2(INT32, WaitHandleNative::CorWaitOneNative, HANDLE handle, INT32 timeout)
{
FCALL_CONTRACT;
INT32 retVal = 0;
- SAFEHANDLEREF sh(safeWaitHandleUNSAFE);
- HELPER_METHOD_FRAME_BEGIN_RET_1(sh);
+ HELPER_METHOD_FRAME_BEGIN_RET_0();
- _ASSERTE(sh != NULL);
+ _ASSERTE(handle != 0);
+ _ASSERTE(handle != INVALID_HANDLE_VALUE);
Thread* pThread = GET_THREAD();
DWORD res = (DWORD) -1;
- SafeHandleHolder shh(&sh);
- // Note that SafeHandle is a GC object, and RequestCallback and
- // DoAppropriateWait work on an array of handles. Don't pass the address
- // of the handle field - that's a GC hole. Instead, pass this temp
- // array.
- HANDLE handles[1];
- handles[0] = sh->GetHandle();
+ // Support for pause/resume (FXFREEZE)
+ while(true)
{
- // Support for pause/resume (FXFREEZE)
- while(true)
- {
- INT64 sPauseTime = g_PauseTime;
- INT64 sTime = CLRGetTickCount64();
- res = pThread->DoAppropriateWait(1,handles,TRUE,timeout, WaitMode_Alertable /*alertable*/);
- if(res != WAIT_TIMEOUT)
- break;
- timeout = (INT32)AdditionalWait(sPauseTime, sTime, timeout);
- if(timeout == 0)
- break;
- }
+ INT64 sPauseTime = g_PauseTime;
+ INT64 sTime = CLRGetTickCount64();
+ res = pThread->DoAppropriateWait(1, &handle, TRUE, timeout, (WaitMode)(WaitMode_Alertable | WaitMode_IgnoreSyncCtx));
+ if(res != WAIT_TIMEOUT)
+ break;
+ timeout = (INT32)AdditionalWait(sPauseTime, sTime, timeout);
+ if(timeout == 0)
+ break;
}
retVal = res;
-
HELPER_METHOD_FRAME_END();
return retVal;
}
FCIMPLEND
-FCIMPL4(INT32, WaitHandleNative::CorWaitMultipleNative, Object* waitObjectsUNSAFE, INT32 timeout, CLR_BOOL exitContext, CLR_BOOL waitForAll)
+FCIMPL4(INT32, WaitHandleNative::CorWaitMultipleNative, HANDLE *handleArray, INT32 numHandles, CLR_BOOL waitForAll, INT32 timeout)
{
FCALL_CONTRACT;
- INT32 retVal = 0;
- OBJECTREF waitObjects = (OBJECTREF) waitObjectsUNSAFE;
- HELPER_METHOD_FRAME_BEGIN_RET_1(waitObjects);
-
- _ASSERTE(waitObjects);
-
- Thread* pThread = GET_THREAD();
+ INT32 ret = 0;
+ HELPER_METHOD_FRAME_BEGIN_RET_0();
- PTRARRAYREF pWaitObjects = (PTRARRAYREF)waitObjects; // array of objects on which to wait
- int numWaiters = pWaitObjects->GetNumComponents();
+ Thread * pThread = GET_THREAD();
#ifdef FEATURE_COMINTEROP_APARTMENT_SUPPORT
// There are some issues with wait-all from an STA thread
// - https://github.com/dotnet/coreclr/issues/17787#issuecomment-385117537
- if (waitForAll && numWaiters > 1 && pThread->GetApartment() == Thread::AS_InSTA)
+ if (waitForAll && numHandles > 1 && pThread->GetApartment() == Thread::AS_InSTA)
{
COMPlusThrow(kNotSupportedException, W("NotSupported_WaitAllSTAThread"));
}
#endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT
- WaitHandleArrayHolder arrayHolder;
- arrayHolder.Initialize(numWaiters, (PTRARRAYREF*) &waitObjects);
-
- pWaitObjects = (PTRARRAYREF)waitObjects; // array of objects on which to wait
- HANDLE* internalHandles = (HANDLE*) _alloca(numWaiters*sizeof(HANDLE));
- for (int i=0;i<numWaiters;i++)
- {
- WAITHANDLEREF waitObject = (WAITHANDLEREF) pWaitObjects->m_Array[i];
- _ASSERTE(waitObject != NULL);
-
- //If the size of the array is 1 and handle is INVALID_HANDLE_VALUE then WaitForMultipleObjectsEx will
- // return ERROR_INVALID_HANDLE but DoAppropriateWait will convert to WAIT_OBJECT_0. i.e Success,
- // this behavior seems wrong but someone explicitly coded that condition so it must have been for a reason.
- internalHandles[i] = waitObject->GetWaitHandle();
-
- }
-
DWORD res = (DWORD) -1;
{
// Support for pause/resume (FXFREEZE)
@@ -249,7 +185,7 @@ FCIMPL4(INT32, WaitHandleNative::CorWaitMultipleNative, Object* waitObjectsUNSAF
{
INT64 sPauseTime = g_PauseTime;
INT64 sTime = CLRGetTickCount64();
- res = pThread->DoAppropriateWait(numWaiters, internalHandles, waitForAll, timeout, WaitMode_Alertable /*alertable*/);
+ res = pThread->DoAppropriateWait(numHandles, handleArray, waitForAll, timeout, (WaitMode)(WaitMode_Alertable | WaitMode_IgnoreSyncCtx));
if(res != WAIT_TIMEOUT)
break;
timeout = (INT32)AdditionalWait(sPauseTime, sTime, timeout);
@@ -258,30 +194,23 @@ FCIMPL4(INT32, WaitHandleNative::CorWaitMultipleNative, Object* waitObjectsUNSAF
}
}
-
- retVal = res;
-
+ ret = res;
+
HELPER_METHOD_FRAME_END();
- return retVal;
+ return ret;
}
FCIMPLEND
-FCIMPL4(INT32, WaitHandleNative::CorSignalAndWaitOneNative, SafeHandle* safeWaitHandleSignalUNSAFE,SafeHandle* safeWaitHandleWaitUNSAFE, INT32 timeout, CLR_BOOL exitContext)
+FCIMPL3(INT32, WaitHandleNative::CorSignalAndWaitOneNative, HANDLE waitHandleSignalUNSAFE, HANDLE waitHandleWaitUNSAFE, INT32 timeout)
{
FCALL_CONTRACT;
INT32 retVal = 0;
- SAFEHANDLEREF shSignal(safeWaitHandleSignalUNSAFE);
- SAFEHANDLEREF shWait(safeWaitHandleWaitUNSAFE);
- HELPER_METHOD_FRAME_BEGIN_RET_2(shSignal,shWait);
-
- if(shSignal == NULL || shWait == NULL)
- COMPlusThrow(kObjectDisposedException);
-
- _ASSERTE(safeWaitHandleSignalUNSAFE != NULL);
- _ASSERTE( safeWaitHandleWaitUNSAFE != NULL);
+ HELPER_METHOD_FRAME_BEGIN_RET_0();
+ _ASSERTE(waitHandleSignalUNSAFE != 0);
+ _ASSERTE(waitHandleWaitUNSAFE != 0);
Thread* pThread = GET_THREAD();
@@ -293,47 +222,16 @@ FCIMPL4(INT32, WaitHandleNative::CorSignalAndWaitOneNative, SafeHandle* safeWait
DWORD res = (DWORD) -1;
- SafeHandleHolder shhSignal(&shSignal);
- SafeHandleHolder shhWait(&shWait);
- // Don't pass the address of the handle field
- // - that's a GC hole. Instead, pass this temp array.
HANDLE handles[2];
- handles[0] = shSignal->GetHandle();
- handles[1] = shWait->GetHandle();
+ handles[0] = waitHandleSignalUNSAFE;
+ handles[1] = waitHandleWaitUNSAFE;
{
- res = pThread->DoSignalAndWait(handles,timeout,TRUE /*alertable*/);
+ res = pThread->DoSignalAndWait(handles, timeout, TRUE /*alertable*/);
}
-
retVal = res;
HELPER_METHOD_FRAME_END();
return retVal;
}
FCIMPLEND
-
-FCIMPL3(DWORD, WaitHandleNative::WaitHelper, PTRArray *handleArrayUNSAFE, CLR_BOOL waitAll, DWORD millis)
-{
- FCALL_CONTRACT;
-
- DWORD ret = 0;
-
- PTRARRAYREF handleArrayObj = (PTRARRAYREF) handleArrayUNSAFE;
- HELPER_METHOD_FRAME_BEGIN_RET_1(handleArrayObj);
-
- CQuickArray<HANDLE> qbHandles;
- int cHandles = handleArrayObj->GetNumComponents();
-
- // Since DoAppropriateWait could cause a GC, we need to copy the handles to an unmanaged block
- // of memory to ensure they aren't relocated during the call to DoAppropriateWait.
- qbHandles.AllocThrows(cHandles);
- memcpy(qbHandles.Ptr(), handleArrayObj->GetDataPtr(), cHandles * sizeof(HANDLE));
-
- Thread * pThread = GetThread();
- ret = pThread->DoAppropriateWait(cHandles, qbHandles.Ptr(), waitAll, millis,
- (WaitMode)(WaitMode_Alertable | WaitMode_IgnoreSyncCtx));
-
- HELPER_METHOD_FRAME_END();
- return ret;
-}
-FCIMPLEND
diff --git a/src/vm/comwaithandle.h b/src/vm/comwaithandle.h
index 816af13e9b..218446881a 100644
--- a/src/vm/comwaithandle.h
+++ b/src/vm/comwaithandle.h
@@ -19,9 +19,8 @@
class WaitHandleNative
{
public:
- static FCDECL3(INT32, CorWaitOneNative, SafeHandle* safeWaitHandleUNSAFE, INT32 timeout, CLR_BOOL exitContext);
- static FCDECL4(INT32, CorWaitMultipleNative, Object* waitObjectsUNSAFE, INT32 timeout, CLR_BOOL exitContext, CLR_BOOL waitForAll);
- static FCDECL4(INT32, CorSignalAndWaitOneNative, SafeHandle* safeWaitHandleSignalUNSAFE, SafeHandle* safeWaitHandleWaitUNSAFE, INT32 timeout, CLR_BOOL exitContext);
- static FCDECL3(DWORD, WaitHelper, PTRArray *handleArrayUNSAFE, CLR_BOOL waitAll, DWORD millis);
+ static FCDECL2(INT32, CorWaitOneNative, HANDLE handle, INT32 timeout);
+ static FCDECL4(INT32, CorWaitMultipleNative, HANDLE *handleArray, INT32 numHandles, CLR_BOOL waitForAll, INT32 timeout);
+ static FCDECL3(INT32, CorSignalAndWaitOneNative, HANDLE waitHandleSignalUNSAFE, HANDLE waitHandleWaitUNSAFE, INT32 timeout);
};
#endif
diff --git a/src/vm/ecalllist.h b/src/vm/ecalllist.h
index cc07d0e570..30492d1512 100644
--- a/src/vm/ecalllist.h
+++ b/src/vm/ecalllist.h
@@ -689,10 +689,9 @@ FCFuncStart(gRegisteredWaitHandleFuncs)
FCFuncEnd()
FCFuncStart(gWaitHandleFuncs)
- FCFuncElement("WaitOneNative", WaitHandleNative::CorWaitOneNative)
- FCFuncElement("WaitMultiple", WaitHandleNative::CorWaitMultipleNative)
- FCFuncElement("SignalAndWaitOne", WaitHandleNative::CorSignalAndWaitOneNative)
- FCFuncElement("WaitMultipleIgnoringSyncContext", WaitHandleNative::WaitHelper)
+ FCFuncElement("WaitOneCore", WaitHandleNative::CorWaitOneNative)
+ FCFuncElement("WaitMultipleIgnoringSyncContext", WaitHandleNative::CorWaitMultipleNative)
+ FCFuncElement("SignalAndWaitNative", WaitHandleNative::CorSignalAndWaitOneNative)
FCFuncEnd()
#ifdef FEATURE_COMINTEROP