Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/coreclr/src/System.Private.CoreLib/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -2896,6 +2896,9 @@
<data name="NotSupported_MaxWaitHandles" xml:space="preserve">
<value>The number of WaitHandles must be less than or equal to 64.</value>
</data>
<data name="NotSupported_MaxWaitHandles_STA" xml:space="preserve">
<value>The number of WaitHandles on a STA thread must be less than or equal to 63.</value>
</data>
<data name="NotSupported_MemStreamNotExpandable" xml:space="preserve">
<value>Memory stream is not expandable.</value>
</data>
Expand Down
35 changes: 10 additions & 25 deletions src/coreclr/src/vm/threads.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3203,22 +3203,11 @@ DWORD Thread::DoAppropriateWait(AppropriateWaitFunc func, void *args,
//--------------------------------------------------------------------
DWORD MsgWaitHelper(int numWaiters, HANDLE* phEvent, BOOL bWaitAll, DWORD millis, BOOL bAlertable)
{
STATIC_CONTRACT_THROWS;
// The true contract for GC trigger should be the following. But this puts a very strong restriction
// on contract for functions that call EnablePreemptiveGC.
//if (GetThread() && !ThreadStore::HoldingThreadStore(GetThread())) {GC_TRIGGERS;} else {GC_NOTRIGGER;}
STATIC_CONTRACT_GC_TRIGGERS;
STANDARD_VM_CONTRACT;

DWORD flags = 0;
DWORD dwReturn=WAIT_ABANDONED;

Thread* pThread = GetThread();
// If pThread is NULL, we'd better shut down.
if (pThread == NULL)
_ASSERTE (g_fEEShutDown);

DWORD lastError = 0;

// If we're going to pump, we cannot use WAIT_ALL. That's because the wait would
// only be satisfied if a message arrives while the handles are signalled. If we
// want true WAIT_ALL, we need to fire up a different thread in the MTA and wait
Expand All @@ -3244,8 +3233,12 @@ DWORD MsgWaitHelper(int numWaiters, HANDLE* phEvent, BOOL bWaitAll, DWORD millis
if (bAlertable)
flags |= COWAIT_ALERTABLE;

HRESULT hr = S_OK;
hr = CoWaitForMultipleHandles(flags, millis, numWaiters, phEvent, &dwReturn);
// 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 (numWaiters > 63)
COMPlusThrow(kNotSupportedException, W("NotSupported_MaxWaitHandles_STA"));

HRESULT hr = CoWaitForMultipleHandles(flags, millis, numWaiters, phEvent, &dwReturn);

if (hr == RPC_S_CALLPENDING)
{
Expand All @@ -3259,13 +3252,9 @@ DWORD MsgWaitHelper(int numWaiters, HANDLE* phEvent, BOOL bWaitAll, DWORD millis
dwReturn = WAIT_FAILED;
}
else
{
{
dwReturn += WAIT_OBJECT_0; // success -- bias back
}

lastError = ::GetLastError();

::SetLastError(lastError);
}

return dwReturn;
}
Expand All @@ -3277,11 +3266,7 @@ DWORD MsgWaitHelper(int numWaiters, HANDLE* phEvent, BOOL bWaitAll, DWORD millis
DWORD Thread::DoAppropriateAptStateWait(int numWaiters, HANDLE* pHandles, BOOL bWaitAll,
DWORD timeout, WaitMode mode)
{
CONTRACTL {
THROWS;
GC_TRIGGERS;
}
CONTRACTL_END;
STANDARD_VM_CONTRACT;

BOOL alertable = (mode & WaitMode_Alertable) != 0;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,15 +261,6 @@ private static int WaitMultiple(ReadOnlySpan<WaitHandle> waitHandles, bool waitA
{
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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,39 @@ public static void WaitAny_SameHandles()
Assert.Equal(0, WaitHandle.WaitAny(wh));
}

static ManualResetEvent[] CreateManualResetEvents(int length)
{
var handles = new ManualResetEvent[length];
for (int i = 0; i < handles.Length; i++)
handles[i] = new ManualResetEvent(true);
return handles;
}

[Fact]
public static void WaitAny_MaxHandles()
{
Assert.Equal(0, WaitHandle.WaitAny(CreateManualResetEvents(64)));
Assert.Throws<NotSupportedException>(() => WaitHandle.WaitAny(CreateManualResetEvents(65)));
}

[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))]
[PlatformSpecific(TestPlatforms.Windows)]
public static void WaitAny_MaxHandles_STA()
{
Thread t = new Thread(() =>
{
Assert.Equal(0, WaitHandle.WaitAny(CreateManualResetEvents(63)));
Assert.Throws<NotSupportedException>(() => WaitHandle.WaitAny(CreateManualResetEvents(64)));
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
t.Join();
}

[Fact]
public static void WaitAll()
{
var handles = new ManualResetEvent[] {
new ManualResetEvent(true),
new ManualResetEvent(true),
new ManualResetEvent(true)
};
ManualResetEvent[] handles = CreateManualResetEvents(3);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess disposing these isn’t important


Assert.True(WaitHandle.WaitAll(handles));
Assert.True(WaitHandle.WaitAll(handles, 1));
Expand Down