summaryrefslogtreecommitdiff
path: root/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExMutexTest/WFSOExMutexTest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExMutexTest/WFSOExMutexTest.cpp')
-rw-r--r--src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExMutexTest/WFSOExMutexTest.cpp214
1 files changed, 214 insertions, 0 deletions
diff --git a/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExMutexTest/WFSOExMutexTest.cpp b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExMutexTest/WFSOExMutexTest.cpp
new file mode 100644
index 0000000000..3737f9cc10
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExMutexTest/WFSOExMutexTest.cpp
@@ -0,0 +1,214 @@
+// 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.
+
+/*=====================================================================
+**
+** Source: WFSOExMutex.c
+**
+** Purpose: Tests a child thread in the middle of a
+** WaitForSingleObjectEx call will be interrupted by QueueUserAPC
+** if the alert flag was set.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+/*Based on SleepEx/test2 */
+
+const int ChildThreadWaitTime = 4000;
+const int InterruptTime = 2000;
+const DWORD AcceptableDelta = 300;
+
+void RunTest(BOOL AlertThread);
+VOID PALAPI APCFunc(ULONG_PTR dwParam);
+DWORD PALAPI WaiterProc(LPVOID lpParameter);
+
+DWORD ThreadWaitDelta;
+HANDLE hMutex;
+
+
+
+int __cdecl main( int argc, char **argv )
+{
+ int ret=0;
+
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /*
+ On some platforms (e.g. FreeBSD 4.9) the first call to some synch objects
+ (such as conditions) involves some pthread internal initialization that
+ can make the first wait slighty longer, potentially going above the
+ acceptable delta for this test. Let's add a dummy wait to preinitialize
+ internal structures
+ */
+ Sleep(100);
+
+ /*
+ The state of a mutex object is signaled when it is not owned by any thread.
+ The creating thread can use the bInitialOwner flag to request immediate ownership
+ of the mutex. Otherwise, a thread must use one of the wait functions to request
+ ownership. When the mutex's state is signaled, one waiting thread is granted
+ ownership, the mutex's state changes to nonsignaled, and the wait function returns.
+ Only one thread can own a mutex at any given time. The owning thread uses the
+ ReleaseMutex function to release its ownership.
+ */
+
+ /* Create a mutex that is not in the signalled state */
+ hMutex = CreateMutex(NULL, //No security attributes
+ TRUE, //Iniitally owned
+ NULL); //Name of mutex
+
+ if (hMutex == NULL)
+ {
+ Fail("Failed to create mutex! GetLastError returned %d.\n",
+ GetLastError());
+ }
+ /*
+ * Check that Queueing an APC in the middle of a wait does interrupt
+ * it, if it's in an alertable state.
+ */
+
+ RunTest(TRUE);
+ if ((ThreadWaitDelta - InterruptTime) > AcceptableDelta)
+ {
+ Fail("Expected thread to wait for %d ms (and get interrupted).\n"
+ "Thread waited for %d ms! (Acceptable delta: %d)\n",
+ InterruptTime, ThreadWaitDelta, AcceptableDelta);
+ }
+
+
+ /*
+ * Check that Queueing an APC in the middle of a wait does NOT interrupt
+ * it, if it is not in an alertable state.
+ */
+ RunTest(FALSE);
+ if ((ThreadWaitDelta - ChildThreadWaitTime) > AcceptableDelta)
+ {
+ Fail("Expected thread to wait for %d ms (and not be interrupted).\n"
+ "Thread waited for %d ms! (Acceptable delta: %d)\n",
+ ChildThreadWaitTime, ThreadWaitDelta, AcceptableDelta);
+ }
+
+
+
+ //Release Mutex
+ ret = ReleaseMutex(hMutex);
+ if (0==ret)
+ {
+ Fail("Unable to Release Mutex!\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ //Close Mutex Handle
+ ret = CloseHandle(hMutex);
+ if (!ret)
+ {
+ Fail("Unable to close handle to Mutex!\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+void RunTest(BOOL AlertThread)
+{
+
+ HANDLE hThread = 0;
+ DWORD dwThreadId = 0;
+
+ int ret=0;
+
+ hThread = CreateThread( NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE)WaiterProc,
+ (LPVOID) AlertThread,
+ 0,
+ &dwThreadId);
+
+ if (hThread == NULL)
+ {
+ Fail("ERROR: Was not able to create the thread to test!\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+
+
+ Sleep(InterruptTime);
+
+ ret = QueueUserAPC(APCFunc, hThread, 0);
+
+ if (ret == 0)
+ {
+ Fail("QueueUserAPC failed! GetLastError returned %d\n",
+ GetLastError());
+ }
+
+ ret = WaitForSingleObject(hThread, INFINITE);
+
+ if (ret == WAIT_FAILED)
+ {
+ Fail("Unable to wait on child thread!\nGetLastError returned %d.\n",
+ GetLastError());
+ }
+
+
+ if (0==CloseHandle(hThread))
+ {
+ Trace("Could not close Thread handle\n");
+ Fail ( "GetLastError returned %d\n", GetLastError());
+ }
+}
+
+/* Function doesn't do anything, just needed to interrupt the wait*/
+VOID PALAPI APCFunc(ULONG_PTR dwParam)
+{
+}
+
+/* Entry Point for child thread. */
+DWORD PALAPI WaiterProc(LPVOID lpParameter)
+{
+ UINT64 OldTimeStamp;
+ UINT64 NewTimeStamp;
+ BOOL Alertable;
+ DWORD ret;
+
+ Alertable = (BOOL) lpParameter;
+
+ LARGE_INTEGER performanceFrequency;
+ if (!QueryPerformanceFrequency(&performanceFrequency))
+ {
+ Fail("Failed to query performance frequency!");
+ }
+
+ OldTimeStamp = GetHighPrecisionTimeStamp(performanceFrequency);
+
+ ret = WaitForSingleObjectEx( hMutex,
+ ChildThreadWaitTime,
+ Alertable);
+
+ NewTimeStamp = GetHighPrecisionTimeStamp(performanceFrequency);
+
+ if (Alertable && ret != WAIT_IO_COMPLETION)
+ {
+ Fail("Expected the interrupted wait to return WAIT_IO_COMPLETION.\n"
+ "Got %d\n", ret);
+ }
+ else if (!Alertable && ret != WAIT_TIMEOUT)
+ {
+ Fail("WaitForSingleObjectEx did not timeout.\n"
+ "Expected return of WAIT_TIMEOUT, got %d.\n", ret);
+ }
+
+ ThreadWaitDelta = NewTimeStamp - OldTimeStamp;
+
+ return 0;
+}
+
+
+