summaryrefslogtreecommitdiff
path: root/src/pal/tests/palsuite/threading/DuplicateHandle
diff options
context:
space:
mode:
Diffstat (limited to 'src/pal/tests/palsuite/threading/DuplicateHandle')
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/CMakeLists.txt15
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test1/test1.c152
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test10/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test10/test10.c239
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test10/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test11/CMakeLists.txt36
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test11/childprocess.c74
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test11/myexitcode.h13
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test11/test11.c364
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test11/testinfo.dat19
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test12/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test12/test12.c129
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test12/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test2/test2.c96
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test2/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test3/test3.c123
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test3/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test4/test4.c239
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test4/testinfo.dat19
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test5/test5.c145
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test5/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test6/test6.c146
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test6/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test7/test7.c149
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test7/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test8/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test8/test8.c164
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test8/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test9/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test9/test9.c127
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test9/testinfo.dat17
39 files changed, 2617 insertions, 0 deletions
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/CMakeLists.txt b/src/pal/tests/palsuite/threading/DuplicateHandle/CMakeLists.txt
new file mode 100644
index 0000000000..b908c1246b
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/CMakeLists.txt
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test10)
+add_subdirectory(test11)
+add_subdirectory(test12)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+add_subdirectory(test7)
+add_subdirectory(test8)
+add_subdirectory(test9)
+
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/DuplicateHandle/test1/CMakeLists.txt
new file mode 100644
index 0000000000..04588b75fe
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_duplicatehandle_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_duplicatehandle_test1 coreclrpal)
+
+target_link_libraries(paltest_duplicatehandle_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test1/test1.c b/src/pal/tests/palsuite/threading/DuplicateHandle/test1/test1.c
new file mode 100644
index 0000000000..e080e98ae8
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test1/test1.c
@@ -0,0 +1,152 @@
+// 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: test1.c (DuplicateHandle)
+**
+** Purpose: Tests the PAL implementation of the DuplicateHandle function.
+** This test will create two handles to file, one to write and
+** one to read what was written. Test on a closed handle and a
+** NULL handle, both should fail.
+**
+**
+**===================================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ HANDLE hFile;
+ HANDLE hDupFile;
+ char buf[256];
+ char teststr[] = "A uNiQuE tEsT sTrInG";
+ char lpFileName[] = "testfile.txt";
+ DWORD dwBytesWritten;
+ DWORD dwBytesRead;
+ BOOL bRetVal;
+
+ /*Initalize the PAL*/
+ if ((PAL_Initialize(argc,argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+ /*Create a file handle with CreateFile*/
+ hFile = CreateFile(lpFileName,
+ GENERIC_WRITE|GENERIC_READ,
+ FILE_SHARE_WRITE|FILE_SHARE_READ,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: %u :unable to create file \"%s\".\n",
+ GetLastError(),
+ lpFileName);
+ }
+
+ /*Write test string to the file.*/
+ bRetVal = WriteFile(hFile, // handle to file
+ teststr, // data buffer
+ strlen(teststr), // number of bytes to write
+ &dwBytesWritten, // number of bytes written
+ NULL); // overlapped buffer
+
+ if (bRetVal == FALSE)
+ {
+ Trace("ERROR: %u : unable to write to file handle "
+ "hFile=0x%lx\n",
+ GetLastError(),
+ hFile);
+ CloseHandle(hFile);
+ Fail("");
+ }
+
+ /*Create a duplicate handle with DuplicateHandle.*/
+ if (!(DuplicateHandle(
+ GetCurrentProcess(),
+ hFile,
+ GetCurrentProcess(),
+ &hDupFile,
+ GENERIC_READ|GENERIC_WRITE,
+ FALSE,
+ DUPLICATE_SAME_ACCESS)))
+ {
+ Trace("ERROR: %u : Fail to create the duplicate handle"
+ " to hFile=0x%lx\n",
+ GetLastError(),
+ hFile);
+ CloseHandle(hFile);
+ Fail("");
+ }
+
+ memset(buf, 0, 256);
+
+ /*Read from the Duplicated handle.*/
+ bRetVal = ReadFile(hDupFile,
+ buf,
+ 256,
+ &dwBytesRead,
+ NULL);
+ if (bRetVal == FALSE)
+ {
+ Trace("ERROR: %u :unable to read from file handle "
+ "hFile=0x%lx\n",
+ GetLastError(),
+ hFile);
+ CloseHandle(hFile);
+ CloseHandle(hDupFile);
+ Fail("");
+ }
+
+ /*Compare what was written to what was read.*/
+ if (memcmp(teststr, buf, dwBytesRead) != 0)
+ {
+ Trace("ERROR: expected %s, got %s\n", teststr, buf);
+ CloseHandle(hFile);
+ CloseHandle(hDupFile);
+ Fail("");
+ }
+
+ /*Close the handles*/
+ CloseHandle(hFile);
+ CloseHandle(hDupFile);
+
+ /*Failure test: Create DuplicateHandle to a closed handle*/
+ if ((DuplicateHandle(
+ GetCurrentProcess(),
+ hFile,
+ GetCurrentProcess(),
+ &hDupFile,
+ GENERIC_READ|GENERIC_WRITE,
+ FALSE,
+ DUPLICATE_SAME_ACCESS)))
+ {
+ Fail("ERROR: %u :Created a duplicate handle to"
+ " a closed handle hFile=0x%lx\n",
+ GetLastError(),
+ hFile);
+ }
+
+ /*Failure test: Create DuplicateHandle to a NULL handle*/
+ hFile = NULL;
+ if ((DuplicateHandle(
+ GetCurrentProcess(),
+ hFile,
+ GetCurrentProcess(),
+ &hDupFile,
+ GENERIC_READ|GENERIC_WRITE,
+ FALSE,
+ DUPLICATE_SAME_ACCESS)))
+ {
+ Fail("ERROR: %u :Created a duplicate handle to "
+ " a NULL handle hFile=0x%lx\n",
+ GetLastError(),
+ hFile);
+ }
+
+ PAL_Terminate();
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test1/testinfo.dat b/src/pal/tests/palsuite/threading/DuplicateHandle/test1/testinfo.dat
new file mode 100644
index 0000000000..e22b0bea6a
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# 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.
+
+Version = 1.0
+Section = Threading
+Function = DuplicateHandle
+Name = Positive Test for DuplicateHandle
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the DuplicateHandle function.
+= This test will create two handles to file, one to write and
+= one to read what was written. Test on a closed handle and a
+= NULL handle, both should fail.
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test10/CMakeLists.txt b/src/pal/tests/palsuite/threading/DuplicateHandle/test10/CMakeLists.txt
new file mode 100644
index 0000000000..ba16252cb4
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test10/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test10.c
+)
+
+add_executable(paltest_duplicatehandle_test10
+ ${SOURCES}
+)
+
+add_dependencies(paltest_duplicatehandle_test10 coreclrpal)
+
+target_link_libraries(paltest_duplicatehandle_test10
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test10/test10.c b/src/pal/tests/palsuite/threading/DuplicateHandle/test10/test10.c
new file mode 100644
index 0000000000..108d748de6
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test10/test10.c
@@ -0,0 +1,239 @@
+// 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: test10.c (DuplicateHandle)
+**
+** Purpose: Tests the PAL implementation of the DuplicateHandle function.
+** This tests the operation of a duplicated Semaphore handle
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+enum wait_results
+{
+ WR_WAITING,
+ WR_GOT_MUTEX,
+ WR_TIMED_OUT,
+ WR_RELEASED
+};
+
+
+volatile int t1_result=WR_WAITING;
+volatile int t2_result=WR_WAITING;
+
+
+DWORD PALAPI ThreadTest1(LPVOID lpParam)
+{
+ DWORD dwWait;
+
+ dwWait = WaitForSingleObject((HANDLE)lpParam, 0);
+ if (dwWait == WAIT_OBJECT_0)
+ {
+ /* tell the main thread we got the mutex */
+ t1_result=WR_GOT_MUTEX;
+
+ /* wait for main thread to tell us to release the mutex */
+ while(WR_GOT_MUTEX == t1_result)
+ Sleep(1);
+ ReleaseSemaphore((HANDLE)lpParam, 1, NULL);
+
+ /* tell the main thread we released the mutex */
+ t1_result = WR_RELEASED;
+ }
+ else
+ {
+ t1_result = WR_TIMED_OUT;
+ }
+ return 0;
+}
+
+DWORD PALAPI ThreadTest2(LPVOID lpParam)
+{
+ DWORD dwWait;
+
+ dwWait = WaitForSingleObject((HANDLE)lpParam, 0 );
+ if (dwWait == WAIT_OBJECT_0)
+ {
+ ReleaseSemaphore((HANDLE)lpParam, 1, NULL);
+ t2_result = WR_GOT_MUTEX;
+ }
+ else
+ {
+ t2_result = WR_TIMED_OUT;
+ }
+
+ return 0;
+}
+
+
+int __cdecl main(int argc, char **argv)
+{
+
+ HANDLE hDupSemaphore;
+ HANDLE hSemaphore;
+ HANDLE hThread;
+ HANDLE hThread2;
+ BOOL bDupHandle=FALSE;
+ DWORD dwThreadId = 0;
+
+ if ((PAL_Initialize(argc,argv)) != 0)
+ {
+ return(FAIL);
+ }
+
+ hSemaphore = CreateSemaphoreW( NULL,
+ 1,
+ 1,
+ NULL);
+ if (hSemaphore == NULL)
+ {
+ Fail("PALSUITE ERROR:%u: Unable to create mutex\n",
+ GetLastError());
+ }
+
+ /*Create Duplicate of the Semaphore above*/
+ bDupHandle = DuplicateHandle(GetCurrentProcess(),
+ hSemaphore,
+ GetCurrentProcess(),
+ &hDupSemaphore,
+ GENERIC_READ|GENERIC_WRITE,
+ FALSE,
+ DUPLICATE_SAME_ACCESS);
+ if (!bDupHandle)
+ {
+ Trace("PALSUITE ERROR:%u: Created the duplicate handle to "
+ "closed event handle hSemaphore=0x%lx\n",
+ GetLastError(),
+ hSemaphore);
+ CloseHandle(hSemaphore);
+ Fail("");
+ }
+
+ /*Create a thread to test the Semaphore*/
+ hThread = CreateThread(NULL,
+ 0,
+ &ThreadTest1,
+ hSemaphore,
+ 0,
+ &dwThreadId);
+ if (hThread == NULL)
+ {
+ Trace("PALSUITE ERROR:%u: unable to create thread\n",
+ GetLastError());
+ CloseHandle(hSemaphore);
+ CloseHandle(hDupSemaphore);
+ Fail("");
+ }
+
+ /* wait until thread has taken the mutex */
+ while (WR_WAITING == t1_result)
+ Sleep(1);
+
+ if(WR_TIMED_OUT == t1_result)
+ {
+ Trace("PALSUITE ERROR: %u: thread couldn't acquire the semaphore\n",
+ GetLastError());
+ CloseHandle(hSemaphore);
+ CloseHandle(hDupSemaphore);
+ CloseHandle(hThread);
+ Fail("");
+ }
+
+ /*Create a second thread to use the Semaphore's duplicate handle*/
+ /*This thread should block since the Semaphore is owned by another
+ thread*/
+ hThread2 = CreateThread(NULL,
+ 0,
+ &ThreadTest2,
+ hDupSemaphore,
+ 0,
+ &dwThreadId);
+
+ if (hThread2 == NULL)
+ {
+ Trace("PALSUITE ERROR:%u: unable to create thread\n",
+ GetLastError());
+ CloseHandle(hSemaphore);
+ CloseHandle(hDupSemaphore);
+ CloseHandle(hThread);
+ Fail("");
+ }
+
+ /* wait until thread has tried to take the mutex */
+ while (WR_WAITING == t2_result)
+ Sleep(1);
+
+ if (WR_TIMED_OUT != t2_result )
+ {
+ Trace("PALSUITE ERROR:%u: Able to take mutex %#x while its "
+ "duplicate %#x is held\n", GetLastError(), hDupSemaphore,
+ hSemaphore);
+ CloseHandle(hSemaphore);
+ CloseHandle(hDupSemaphore);
+ CloseHandle(hThread);
+ CloseHandle(hThread2);
+ Fail("");
+ }
+
+ /* reset second thread status */
+ t2_result = WR_WAITING;
+
+ /* tell thread 1 to release the mutex */
+ t1_result = WR_WAITING;
+
+ /* wait for thread 1 to release the mutex */
+ while (WR_WAITING == t1_result)
+ Sleep(1);
+
+ CloseHandle(hThread2);
+
+ /*Re-Create the second thread to reuse the duplicated Semaphore*/
+ /*Since the Semaphore has since been released, the thread should
+ put WR_GOT_MUTEX into t2_result */
+ hThread2 = CreateThread(NULL,
+ 0,
+ &ThreadTest2,
+ hDupSemaphore,
+ 0,
+ &dwThreadId);
+
+ if (hThread2 == NULL)
+ {
+ Trace("PALSUITE ERROR:%u: unable to create thread\n",
+ GetLastError());
+ CloseHandle(hSemaphore);
+ CloseHandle(hDupSemaphore);
+ CloseHandle(hThread);
+ Fail("");
+ }
+
+ /* wait until thread has taken the semaphore */
+ while (WR_WAITING == t2_result)
+ Sleep(1);
+
+ if (WR_GOT_MUTEX != t2_result )
+ {
+ Trace("PALSUITE ERROR:%u: Unable to take semaphore %#x after its"
+ " duplicate %#x was released\n", GetLastError(), hDupSemaphore,
+ hSemaphore);
+ CloseHandle(hSemaphore);
+ CloseHandle(hDupSemaphore);
+ CloseHandle(hThread);
+ CloseHandle(hThread2);
+ Fail("");
+ }
+
+ /*Cleanup.*/
+ CloseHandle(hSemaphore);
+ CloseHandle(hDupSemaphore);
+ CloseHandle(hThread);
+ CloseHandle(hThread2);
+
+ PAL_Terminate();
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test10/testinfo.dat b/src/pal/tests/palsuite/threading/DuplicateHandle/test10/testinfo.dat
new file mode 100644
index 0000000000..674c71c2b3
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test10/testinfo.dat
@@ -0,0 +1,17 @@
+# 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.
+
+Version = 1.0
+Section = Threading
+Function = DuplicateHandle
+Name = Test for DuplicateHandle (CreateSemaphore)
+TYPE = DEFAULT
+EXE1 = test10
+Description
+= Tests the PAL implementation of the DuplicateHandle function.
+= This test duplication of a Semaphore handle. The test will
+= create a Semaphore and duplicate a handle to it.
+= Then two subthreads will be used to verify that they can selectively
+= block each other with different handles that refer to the
+= same Semaphore
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test11/CMakeLists.txt b/src/pal/tests/palsuite/threading/DuplicateHandle/test11/CMakeLists.txt
new file mode 100644
index 0000000000..68ce7b23fb
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test11/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(TESTSOURCES
+ test11.c
+)
+
+add_executable(paltest_duplicatehandle_test11
+ ${TESTSOURCES}
+)
+
+add_dependencies(paltest_duplicatehandle_test11 coreclrpal)
+
+target_link_libraries(paltest_duplicatehandle_test11
+ pthread
+ m
+ coreclrpal
+)
+
+
+set(HELPERSOURCES
+ childprocess.c
+)
+
+add_executable(paltest_duplicatehandle_test11_child
+ ${HELPERSOURCES}
+)
+
+add_dependencies(paltest_duplicatehandle_test11_child coreclrpal)
+
+target_link_libraries(paltest_duplicatehandle_test11_child
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test11/childprocess.c b/src/pal/tests/palsuite/threading/DuplicateHandle/test11/childprocess.c
new file mode 100644
index 0000000000..d5b310e46c
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test11/childprocess.c
@@ -0,0 +1,74 @@
+// 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: childprocess.c
+**
+** Purpose: Test to ensure DuplicateHandle works properly.
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** CreateMutexW
+** WaitForSingleObject
+** CloseHandle
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+#include "myexitcode.h"
+
+
+int __cdecl main( int argc, char **argv )
+{
+ HANDLE hMutex;
+ WCHAR wszMutexName[] = { 'T','E','S','T','1','1','\0' };
+ DWORD dwRet;
+ int i;
+
+ /* initialize the PAL */
+ if( PAL_Initialize(argc, argv) != 0 )
+ {
+ return( FAIL );
+ }
+
+ /* open a mutex to synchronize with the parent process */
+ hMutex = CreateMutexW( NULL, FALSE, wszMutexName );
+ if( hMutex == NULL )
+ {
+ Fail( "ERROR:%lu:CreateMutex() call failed\r\n", GetLastError() );
+ }
+
+ /* acquire the mutex lock */
+ dwRet = WaitForSingleObject( hMutex, 10000 );
+ if( dwRet != WAIT_OBJECT_0 )
+ {
+ Trace( "ERROR:WaitForSingleObject() returned %lu, "
+ "expected WAIT_OBJECT_0",
+ dwRet );
+ if( ! CloseHandle( hMutex ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ }
+ Fail( "test failed\n" );
+ }
+
+
+ /* simulate some activity */
+ for( i=0; i<50000; i++ )
+ ;
+
+ /* close our mutex handle */
+ if( ! CloseHandle( hMutex ) )
+ {
+ Fail( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ }
+
+ /* terminate the PAL */
+ PAL_Terminate();
+
+ /* return the predefined exit code */
+ return TEST_EXIT_CODE;
+}
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test11/myexitcode.h b/src/pal/tests/palsuite/threading/DuplicateHandle/test11/myexitcode.h
new file mode 100644
index 0000000000..84801cbb54
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test11/myexitcode.h
@@ -0,0 +1,13 @@
+// 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: duplicatehandle/test11/myexitcode.h
+**
+** Purpose: Define an exit code constant.
+**
+**
+**=========================================================*/
+#define TEST_EXIT_CODE 31
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test11/test11.c b/src/pal/tests/palsuite/threading/DuplicateHandle/test11/test11.c
new file mode 100644
index 0000000000..b05244c4b8
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test11/test11.c
@@ -0,0 +1,364 @@
+// 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: test11.c
+**
+** Purpose:
+**
+** Test to ensure proper operation of the DuplicateHandle API.
+** The test launches a trivial child process, then opens
+** a handle to it using OpenProcess. It then duplicates that
+** handle and uses it to wait for the child process to terminate,
+** and then checks the exit code of the child process in order to
+** verify that it was in fact a handle to the correct
+** process. The test tries to duplicate the handle again after
+** the process has been closed, to verify that failure ensues.
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+** ZeroMemory
+** GetCurrentDirectoryW
+** CreateProcessW
+** WaitForSingleObject
+** CreateMutexW
+** ReleaseMutex
+** CloseHandle
+** GetLastError
+** strlen
+** strncpy
+**
+**
+**===========================================================================*/
+#include <palsuite.h>
+#include "myexitcode.h"
+
+
+static const char* rgchPathDelim = "\\";
+
+
+int
+mkAbsoluteFilename( LPSTR dirName,
+ DWORD dwDirLength,
+ LPCSTR fileName,
+ DWORD dwFileLength,
+ LPSTR absPathName )
+{
+ DWORD sizeDN, sizeFN, sizeAPN;
+
+ sizeDN = strlen( dirName );
+ sizeFN = strlen( fileName );
+ sizeAPN = (sizeDN + 1 + sizeFN + 1);
+
+ /* ensure ((dirName + DELIM + fileName + \0) =< _MAX_PATH ) */
+ if( sizeAPN > _MAX_PATH )
+ {
+ return ( 0 );
+ }
+
+ strncpy( absPathName, dirName, dwDirLength +1 );
+ strncpy( absPathName, rgchPathDelim, 2 );
+ strncpy( absPathName, fileName, dwFileLength +1 );
+
+ return (sizeAPN);
+
+}
+
+
+int __cdecl main( int argc, char **argv )
+
+{
+ const char* rgchChildFile = "childprocess";
+
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+
+ DWORD dwError;
+ DWORD dwExitCode;
+ DWORD dwFileLength;
+ DWORD dwDirLength;
+ DWORD dwSize;
+ DWORD dwRet;
+
+ HANDLE hMutex;
+ HANDLE hChildProcess;
+ HANDLE hDupChildProcess;
+
+ char rgchDirName[_MAX_DIR];
+ char absPathBuf[_MAX_PATH];
+ char* rgchAbsPathName;
+
+ BOOL ret = FAIL;
+ BOOL bChildDone = FALSE;
+ WCHAR wszMutexName[] = { 'T','E','S','T','1','1','\0' };
+
+ /* initialize the PAL */
+ if( PAL_Initialize(argc, argv) != 0 )
+ {
+ return( FAIL );
+ }
+
+ /* create a mutex to synchronize with the child process */
+ hMutex = CreateMutexW( NULL, TRUE, wszMutexName );
+ if( hMutex == NULL )
+ {
+ Fail( "ERROR:%lu:CreateMutex() call failed\r\n", GetLastError() );
+ }
+
+ /* zero our process and startup info structures */
+ ZeroMemory( &si, sizeof(si) );
+ si.cb = sizeof( si );
+ ZeroMemory( &pi, sizeof(pi) );
+
+ /* build the absolute path to the child process */
+ rgchAbsPathName = &absPathBuf[0];
+ dwFileLength = strlen( rgchChildFile );
+
+ dwDirLength = GetCurrentDirectory( _MAX_PATH, rgchDirName );
+ if( dwDirLength == 0 )
+ {
+ dwError = GetLastError();
+ if( ReleaseMutex( hMutex ) == 0 )
+ {
+ Trace( "ERROR:%lu:ReleaseMutex() call failed\n", GetLastError() );
+ }
+ if( CloseHandle( hMutex ) == 0 )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ }
+ Fail( "GetCurrentDirectory call failed with error code %d\n",
+ dwError );
+ }
+
+ dwSize = mkAbsoluteFilename( rgchDirName,
+ dwDirLength,
+ rgchChildFile,
+ dwFileLength,
+ rgchAbsPathName );
+ if( dwSize == 0 )
+ {
+ if( ReleaseMutex( hMutex ) == 0 )
+ {
+ Trace( "ERROR:%lu:ReleaseMutex() call failed\n", GetLastError() );
+ }
+ if( CloseHandle( hMutex ) == 0 )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ }
+ Fail( "Palsuite Code: mkAbsoluteFilename() call failed. Could ",
+ "not build absolute path name to file\n. Exiting.\n" );
+ }
+
+ /* launch the child process */
+ if( !CreateProcess( NULL, /* module name to execute */
+ rgchAbsPathName, /* command line */
+ NULL, /* process handle not */
+ /* inheritable */
+ NULL, /* thread handle not */
+ /*inheritable */
+ FALSE, /* handle inheritance */
+ CREATE_NEW_CONSOLE, /* dwCreationFlags */
+ NULL, /* use parent's environment */
+ NULL, /* use parent's starting */
+ /* directory */
+ &si, /* startup info struct */
+ &pi ) /* process info struct */
+ )
+ {
+ dwError = GetLastError();
+ if( ReleaseMutex( hMutex ) == 0 )
+ {
+ Trace( "ERROR:%lu:ReleaseMutex() call failed\n", GetLastError() );
+ }
+ if( CloseHandle( hMutex ) == 0 )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ }
+ Fail( "CreateProcess call failed with error code %d\n",
+ dwError );
+ }
+
+ /* open another handle to the child process */
+ hChildProcess = OpenProcess( PROCESS_ALL_ACCESS, /* access */
+ FALSE, /* inheritable */
+ pi.dwProcessId /* process id */
+ );
+ if( hChildProcess == NULL )
+ {
+ dwError = GetLastError();
+ if( ReleaseMutex( hMutex ) == 0 )
+ {
+ Trace( "ERROR:%lu:ReleaseMutex() call failed\n", GetLastError() );
+ }
+ Trace( "ERROR:%lu:OpenProcess call failed\n", dwError );
+ goto cleanup3;
+ }
+
+ /* duplicate the child process handle */
+ if( ! DuplicateHandle( GetCurrentProcess(),
+ hChildProcess,
+ GetCurrentProcess(),
+ &hDupChildProcess,
+ GENERIC_READ|GENERIC_WRITE,
+ FALSE,
+ DUPLICATE_SAME_ACCESS) )
+ {
+ Trace( "ERROR:%lu:DuplicateHandle() call failed\n", GetLastError() );
+ if( ReleaseMutex( hMutex ) == 0 )
+ {
+ Trace( "ERROR:%lu:ReleaseMutex() call failed\n", GetLastError() );
+ }
+ goto cleanup2;
+ }
+
+ /* release the mutex so the child can proceed */
+ if( ReleaseMutex( hMutex ) == 0 )
+ {
+ Trace( "ERROR:%lu:ReleaseMutex() call failed\n", GetLastError() );
+ goto cleanup1;
+ }
+
+ /* wait for the child process to complete, using the new handle */
+ dwRet = WaitForSingleObject( hDupChildProcess, 10000 );
+ if( dwRet != WAIT_OBJECT_0 )
+ {
+ Trace( "ERROR:WaitForSingleObject call returned %lu, "
+ "expected WAIT_OBJECT_0",
+ dwRet );
+ goto cleanup1;
+ }
+
+ /* remember that we waited until the child was finished */
+ bChildDone = TRUE;
+
+ /* check the exit code from the process -- this is a bit of an */
+ /* extra verification that we opened the correct process handle */
+ if( ! GetExitCodeProcess( hDupChildProcess, &dwExitCode ) )
+ {
+ Trace( "ERROR:%lu:GetExitCodeProcess call failed\n", GetLastError() );
+ goto cleanup1;
+ }
+
+ /* verification */
+ if( (dwExitCode & 0xFF) != (TEST_EXIT_CODE & 0xFF) )
+ {
+ Trace( "GetExitCodeProcess returned an incorrect exit code %d, "
+ "expected value is %d\n",
+ (dwExitCode & 0xFF),
+ (TEST_EXIT_CODE & 0xFF));
+ goto cleanup1;
+ }
+
+ /* close the duplicate handle */
+ if( ! CloseHandle( hDupChildProcess ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle call failed\n", GetLastError() );
+ goto cleanup2;
+ }
+
+ /* close the child process handle */
+ if( ! CloseHandle ( hChildProcess ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ goto cleanup3;
+ }
+
+ /* try to call duplicate handle on the closed child process handle */
+ if( DuplicateHandle( GetCurrentProcess(),
+ hChildProcess,
+ GetCurrentProcess(),
+ &hDupChildProcess,
+ GENERIC_READ|GENERIC_WRITE,
+ FALSE,
+ DUPLICATE_SAME_ACCESS) )
+ {
+ Trace( "ERROR:%lu:DuplicateHandle call succeeded on "
+ "a closed process handle, expected ERROR_INVALID_HANDLE\n" );
+ if( ! CloseHandle( hDupChildProcess ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle call failed\n", GetLastError() );
+ }
+ goto cleanup3;
+ }
+
+ /* verify that the last error was ERROR_INVALID_HANDLE */
+ dwRet = GetLastError();
+ if( dwRet != ERROR_INVALID_HANDLE )
+ {
+ Trace( "ERROR:DuplicateHandle returned %lu, "
+ "expected ERROR_INVALID_HANDLE\n",
+ dwRet );
+ goto cleanup3;
+ }
+
+
+ /* success if we get here */
+ ret = PASS;
+
+ /* skip the cleanup stuff that's already done */
+ goto cleanup3;
+
+
+cleanup1:
+ /* close our duplicate handle */
+ if( ! CloseHandle( hDupChildProcess ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle call failed\n", GetLastError() );
+ ret = FAIL;
+ }
+
+cleanup2:
+ /* wait on the child process to complete if necessary */
+ if( ! bChildDone )
+ {
+ dwRet = WaitForSingleObject( hChildProcess, 10000 );
+ if( dwRet != WAIT_OBJECT_0 )
+ {
+ Trace( "ERROR:WaitForSingleObject call returned %lu, "
+ "expected WAIT_OBJECT_0",
+ dwRet );
+ ret = FAIL;
+ }
+ }
+
+ /* close our child process handle */
+ if( CloseHandle ( hChildProcess ) == 0 )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ ret = FAIL;
+ }
+
+cleanup3:
+ /* close all our other handles */
+ if( CloseHandle ( pi.hProcess ) == 0 )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ ret = FAIL;
+ }
+ if( CloseHandle ( pi.hThread ) == 0 )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ ret = FAIL;
+ }
+ if( CloseHandle( hMutex ) == 0 )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ ret = FAIL;
+ }
+
+ if( ret == FAIL )
+ {
+ Fail( "test failed\n" );
+ }
+
+
+
+ /* terminate the PAL */
+ PAL_Terminate();
+
+ /* return success */
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test11/testinfo.dat b/src/pal/tests/palsuite/threading/DuplicateHandle/test11/testinfo.dat
new file mode 100644
index 0000000000..1937877880
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test11/testinfo.dat
@@ -0,0 +1,19 @@
+# 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.
+
+Version = 1.0
+Section = threading
+Function = DuplicateHandle
+Name = Test for DuplicateHandle
+TYPE = DEFAULT
+EXE1 = test11
+EXE2 = childprocess
+Description
+= Test to ensure proper operation of the DuplicateHandle API.
+= The test launches a trivial child process, then opens
+= a handle to it using OpenProcess. It then duplicates that
+= handle and uses it to wait for the child process to terminate,
+= and then checks the exit code of the child process in order to
+= verify that it was in fact a handle to the correct= process. The test tries to duplicate the handle again after
+= the process has been closed, to verify that failure ensues.
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test12/CMakeLists.txt b/src/pal/tests/palsuite/threading/DuplicateHandle/test12/CMakeLists.txt
new file mode 100644
index 0000000000..961a9c64e6
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test12/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test12.c
+)
+
+add_executable(paltest_duplicatehandle_test12
+ ${SOURCES}
+)
+
+add_dependencies(paltest_duplicatehandle_test12 coreclrpal)
+
+target_link_libraries(paltest_duplicatehandle_test12
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test12/test12.c b/src/pal/tests/palsuite/threading/DuplicateHandle/test12/test12.c
new file mode 100644
index 0000000000..519194bc3a
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test12/test12.c
@@ -0,0 +1,129 @@
+// 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: test12.c (DuplicateHandle)
+**
+** Purpose: Tests the PAL implementation of the DuplicateHandle function.
+** This test will create handle to file (to write) and close it,
+** then call duplicate handle to read what was written.
+**
+**
+**===================================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ HANDLE hFile;
+ HANDLE hDupFile;
+ char buf[256];
+ char teststr[] = "A uNiQuE tEsT sTrInG";
+ char lpFileName[] = "testfile.txt";
+ DWORD dwBytesWritten;
+ DWORD dwBytesRead;
+ BOOL bRetVal;
+
+ /*Initalize the PAL*/
+ if ((PAL_Initialize(argc,argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+ /*Create a file handle with CreateFile*/
+ hFile = CreateFile(lpFileName,
+ GENERIC_WRITE|GENERIC_READ,
+ FILE_SHARE_WRITE|FILE_SHARE_READ,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: %u :unable to create file \"%s\".\n",
+ GetLastError(),
+ lpFileName);
+ }
+
+ /*Write test string to the file.*/
+ bRetVal = WriteFile(hFile, // handle to file
+ teststr, // data buffer
+ strlen(teststr), // number of bytes to write
+ &dwBytesWritten, // number of bytes written
+ NULL); // overlapped buffer
+
+ if (bRetVal == FALSE)
+ {
+ Trace("ERROR: %u : unable to write to file handle "
+ "hFile=0x%lx\n",
+ GetLastError(),
+ hFile);
+ CloseHandle(hFile);
+ Fail("");
+ }
+
+ /*Create a duplicate handle with DuplicateHandle.*/
+ if (!(DuplicateHandle(
+ GetCurrentProcess(),
+ hFile,
+ GetCurrentProcess(),
+ &hDupFile,
+ GENERIC_READ|GENERIC_WRITE,
+ FALSE,
+ DUPLICATE_SAME_ACCESS)))
+ {
+ Trace("ERROR: %u : Fail to create the duplicate handle"
+ " to hFile=0x%lx\n",
+ GetLastError(),
+ hFile);
+ CloseHandle(hFile);
+ Fail("");
+ }
+
+ if( !CloseHandle(hFile) )
+ {
+ Fail("Duplicate Handle:Unable to close original file: Error[%u]\n", GetLastError());
+ }
+
+ memset(buf, 0, 256);
+
+ /*Read from the Duplicated handle.*/
+ bRetVal = ReadFile(hDupFile,
+ buf,
+ 256,
+ &dwBytesRead,
+ NULL);
+ if (bRetVal == FALSE)
+ {
+ Trace("ERROR: %u :unable to read from file handle "
+ "hFile=0x%lx\n",
+ GetLastError(),
+ hDupFile);
+ CloseHandle(hDupFile);
+ Fail("");
+ }
+
+ /*Compare what was written to what was read.*/
+ if (memcmp(teststr, buf, dwBytesRead) != 0)
+ {
+ Trace("ERROR: expected %s, got %s\n", teststr, buf);
+ CloseHandle(hDupFile);
+ Fail("");
+ }
+
+ /*Close the handles*/
+ CloseHandle(hDupFile);
+
+ bRetVal = DeleteFileA(lpFileName);
+ if (bRetVal != TRUE)
+ {
+ Trace("Error:%u: DuplicateHandle, DeleteFileA: Couldn't delete DeleteFileA's"
+ " %s\n", GetLastError(), lpFileName);
+ Fail("");
+ }
+
+
+ PAL_Terminate();
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test12/testinfo.dat b/src/pal/tests/palsuite/threading/DuplicateHandle/test12/testinfo.dat
new file mode 100644
index 0000000000..3d73362eb3
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test12/testinfo.dat
@@ -0,0 +1,15 @@
+# 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.
+
+Version = 1.0
+Section = Threading
+Function = DuplicateHandle
+Name = Positive Test for DuplicateHandle
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the DuplicateHandle function.
+= This test will create handle to file (to write),
+= then call duplicate handle, and close the original handle
+= and then use duplicated handle to read what was written.
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test2/CMakeLists.txt b/src/pal/tests/palsuite/threading/DuplicateHandle/test2/CMakeLists.txt
new file mode 100644
index 0000000000..06529a6204
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_duplicatehandle_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_duplicatehandle_test2 coreclrpal)
+
+target_link_libraries(paltest_duplicatehandle_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test2/test2.c b/src/pal/tests/palsuite/threading/DuplicateHandle/test2/test2.c
new file mode 100644
index 0000000000..d1411e62d9
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test2/test2.c
@@ -0,0 +1,96 @@
+// 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: test2.c (DuplicateHandle)
+**
+** Purpose: Tests the PAL implementation of the DuplicateHandle function.
+** This will test duplication of an CreateEvent handle. Test an
+** event in a signaled state to wait, and then set the duplicate
+** to nonsignaled state and perform the wait again. The wait on
+** the event should fail. Test the duplication of closed and NULL
+** events, these should fail.
+**
+**
+**===================================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ HANDLE hEvent;
+ HANDLE hDupEvent;
+
+ /*Initalize the PAL.*/
+ if ((PAL_Initialize(argc,argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+ /*Create an Event, and set it in the signaled state.*/
+ hEvent = CreateEvent(0, TRUE, TRUE, 0);
+ if (hEvent == NULL)
+ {
+ Fail("ERROR: %u :unable to create event\n",
+ GetLastError());
+ }
+
+ /*Create a duplicate Event handle.*/
+ if (!(DuplicateHandle(GetCurrentProcess(),
+ hEvent,GetCurrentProcess(),
+ &hDupEvent,
+ GENERIC_READ|GENERIC_WRITE,
+ FALSE, DUPLICATE_SAME_ACCESS)))
+ {
+ Trace("ERROR: %u :Fail to create the duplicate handle"
+ " to hEvent=0x%lx\n",
+ GetLastError(),
+ hEvent);
+ CloseHandle(hEvent);
+ Fail("");
+ }
+
+ /*Perform wait on Event that is in signaled state.*/
+ if ((WaitForSingleObject(hEvent, 1000)) != WAIT_OBJECT_0)
+ {
+ Trace("ERROR: %u :WaitForSignalObject on Event=0x%lx set to "
+ " signaled state failed",
+ GetLastError(),
+ hEvent);
+ CloseHandle(hEvent);
+ CloseHandle(hDupEvent);
+ Fail("");
+ }
+
+ /*Set the Duplicate Event handle to nonsignaled state.*/
+ if ((ResetEvent(hDupEvent)) == 0)
+ {
+ Trace("ERROR: %u :unable to reset dup event\n",
+ GetLastError());
+ CloseHandle(hEvent);
+ CloseHandle(hDupEvent);
+ Fail("");
+ }
+
+ /*Perform wait on Event that is in signaled state.*/
+ if ((WaitForSingleObject(hEvent, 1000)) == WAIT_OBJECT_0)
+ {
+ Trace("ERROR: %u: WaitForSignalObject succeeded on Event=0x%lx "
+ " when Duplicate Event=0x%lx set to nonsignaled state"
+ " succeeded\n",
+ GetLastError(),
+ hEvent,
+ hDupEvent);
+ CloseHandle(hEvent);
+ CloseHandle(hDupEvent);
+ Fail("");
+ }
+
+ /*Close handles to events.*/
+ CloseHandle(hEvent);
+ CloseHandle(hDupEvent);
+
+ PAL_Terminate();
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test2/testinfo.dat b/src/pal/tests/palsuite/threading/DuplicateHandle/test2/testinfo.dat
new file mode 100644
index 0000000000..273440804e
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test2/testinfo.dat
@@ -0,0 +1,17 @@
+# 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.
+
+Version = 1.0
+Section = Threading
+Function = DuplicateHandle
+Name = Test for DuplicateHandle
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Tests the PAL implementation of the DuplicateHandle function.
+= This will test duplication of an CreateEvent handle. Test an
+= event in a signaled state to wait, and then set the duplicate
+= to nonsignaled state and perform the wait again. The wait on
+= the event should fail. Test the duplication of closed and NULL
+= events, these should fail.
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test3/CMakeLists.txt b/src/pal/tests/palsuite/threading/DuplicateHandle/test3/CMakeLists.txt
new file mode 100644
index 0000000000..7f961c2213
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_duplicatehandle_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_duplicatehandle_test3 coreclrpal)
+
+target_link_libraries(paltest_duplicatehandle_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test3/test3.c b/src/pal/tests/palsuite/threading/DuplicateHandle/test3/test3.c
new file mode 100644
index 0000000000..fc91b5ec22
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test3/test3.c
@@ -0,0 +1,123 @@
+// 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: test3.c (DuplicateHandle)
+**
+** Purpose: Tests the PAL implementation of the DuplicateHandle function.
+** This will test duplication of an OpenEvent handle. Test an
+** event in a signaled state to wait, and then set the duplicate
+** to nonsignaled state and perform the wait again. The wait on
+** the event should fail. Test the duplication of closed and NULL
+** events, these should fail.
+**
+**
+**===================================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ HANDLE hCreateEvent;
+ HANDLE hOpenEvent;
+ HANDLE hDupEvent;
+ WCHAR lpEventName[]={'E','v','e','n','t','\0'};
+
+ /*Initialize the PAL.*/
+ if ((PAL_Initialize(argc,argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+ /*Create an Event, and set it in the signaled state.*/
+ hCreateEvent = CreateEventW(0,
+ TRUE,
+ TRUE,
+ lpEventName);
+ if (hCreateEvent == NULL)
+ {
+ Fail("ERROR: %u :unable to create event %s\n",
+ GetLastError(),
+ lpEventName);
+ }
+
+ /*Open another handle to hCreateHandle with OpenEvent*/
+ hOpenEvent = OpenEventW(EVENT_ALL_ACCESS,
+ TRUE,
+ lpEventName);
+ if (hOpenEvent == NULL)
+ {
+ Trace("ERROR: %u :unable to create handle with OpenEvent to %s\n",
+ GetLastError(),
+ lpEventName);
+ CloseHandle(hCreateEvent);
+ Fail("");
+ }
+
+ /*Create a duplicate Event handle*/
+ if (!(DuplicateHandle(GetCurrentProcess(),
+ hOpenEvent,
+ GetCurrentProcess(),
+ &hDupEvent,
+ GENERIC_READ|GENERIC_WRITE,
+ FALSE,
+ DUPLICATE_SAME_ACCESS)))
+ {
+ Trace("ERROR: %u :Fail to create the duplicate handle"
+ " to hCreateEvent=0x%lx\n",
+ GetLastError(),
+ hCreateEvent);
+ CloseHandle(hCreateEvent);
+ CloseHandle(hOpenEvent);
+ Fail("");
+ }
+
+ /*Perform wait on Event that is in signaled state*/
+ if ((WaitForSingleObject(hOpenEvent, 1000)) != WAIT_OBJECT_0)
+ {
+ Trace("ERROR: %u :WaitForSignalObject on hOpenEvent=0x%lx set to "
+ " signaled state failed\n",
+ GetLastError(),
+ hOpenEvent);
+ CloseHandle(hCreateEvent);
+ CloseHandle(hOpenEvent);
+ CloseHandle(hDupEvent);
+ Fail("");
+ }
+
+ /*Set the Duplicate Event handle to nonsignaled state*/
+ if ((ResetEvent(hDupEvent)) == 0)
+ {
+ Trace("ERROR: %u: unable to reset hDupEvent=0x%lx\n",
+ GetLastError(),
+ hDupEvent);
+ CloseHandle(hCreateEvent);
+ CloseHandle(hOpenEvent);
+ CloseHandle(hDupEvent);
+ Fail("");
+ }
+
+ /*Perform wait on Event that is in signaled state*/
+ if ((WaitForSingleObject(hOpenEvent, 1000)) == WAIT_OBJECT_0)
+ {
+ Trace("ERROR: %u :WaitForSignalObject succeeded on hOpenEvent=0x%lx "
+ " when Duplicate hDupEvent=0x%lx set to nonsignaled state"
+ " succeeded\n",
+ GetLastError(),
+ hOpenEvent,
+ hDupEvent);
+ CloseHandle(hCreateEvent);
+ CloseHandle(hOpenEvent);
+ CloseHandle(hDupEvent);
+ Fail("");
+ }
+
+ /*Close handles the events*/
+ CloseHandle(hCreateEvent);
+ CloseHandle(hOpenEvent);
+ CloseHandle(hDupEvent);
+
+ PAL_Terminate();
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test3/testinfo.dat b/src/pal/tests/palsuite/threading/DuplicateHandle/test3/testinfo.dat
new file mode 100644
index 0000000000..a10adb9a8e
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test3/testinfo.dat
@@ -0,0 +1,17 @@
+# 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.
+
+Version = 1.0
+Section = Threading
+Function = DuplicateHandle
+Name = Test for DuplicateHandle
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Tests the PAL implementation of the DuplicateHandle function.
+= This will test duplication of an OpenEvent handle. Test an
+= event in a signaled state to wait, and then set the duplicate
+= to nonsignaled state and perform the wait again. The wait on
+= the event should fail. Test the duplication of closed and NULL
+= events, these should fail.
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test4/CMakeLists.txt b/src/pal/tests/palsuite/threading/DuplicateHandle/test4/CMakeLists.txt
new file mode 100644
index 0000000000..c3040d09ec
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_duplicatehandle_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_duplicatehandle_test4 coreclrpal)
+
+target_link_libraries(paltest_duplicatehandle_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test4/test4.c b/src/pal/tests/palsuite/threading/DuplicateHandle/test4/test4.c
new file mode 100644
index 0000000000..14a72db461
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test4/test4.c
@@ -0,0 +1,239 @@
+// 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: test4.c (DuplicateHandle)
+**
+** Purpose: Tests the PAL implementation of the DuplicateHandle function.
+** This test duplication of a Mutex handle. The test will comprise
+** of creating a Mutex and its duplicate and create a thread that
+** will get ownership. Another thread will be create that will
+** attempt to get ownership of the duplicate Mutex, this will
+** fail, since the Mutex is owned by another thread. The Mutex
+** will be released and then the thread will attempt to get
+** ownership of the duplicate Mutex, this will succeed.
+**
+**
+**===================================================================*/
+#include <palsuite.h>
+
+enum wait_results
+{
+ WR_WAITING,
+ WR_GOT_MUTEX,
+ WR_TIMED_OUT,
+ WR_RELEASED
+};
+
+
+volatile int t1_result=WR_WAITING;
+volatile int t2_result=WR_WAITING;
+
+
+DWORD PALAPI ThreadTest1(LPVOID lpParam)
+{
+ DWORD dwWait;
+
+ dwWait = WaitForSingleObject((HANDLE)lpParam, 0);
+ if (dwWait == WAIT_OBJECT_0)
+ {
+ /* tell the main thread we got the mutex */
+ t1_result=WR_GOT_MUTEX;
+
+ /* wait for main thread to tell us to release the mutex */
+ while(WR_GOT_MUTEX == t1_result)
+ Sleep(1);
+ ReleaseMutex((HANDLE)lpParam);
+
+ /* tell the main thread we released the mutex */
+ t1_result = WR_RELEASED;
+ }
+ else
+ {
+ t1_result = WR_TIMED_OUT;
+ }
+ return 0;
+}
+
+DWORD PALAPI ThreadTest2(LPVOID lpParam)
+{
+ DWORD dwWait;
+
+ dwWait = WaitForSingleObject((HANDLE)lpParam, 0 );
+ if (dwWait == WAIT_OBJECT_0)
+ {
+ ReleaseMutex((HANDLE)lpParam);
+ t2_result = WR_GOT_MUTEX;
+ }
+ else
+ {
+ t2_result = WR_TIMED_OUT;
+ }
+
+ return 0;
+}
+
+
+int __cdecl main(int argc, char **argv)
+{
+
+ HANDLE hDupMutex;
+ HANDLE hMutex;
+ HANDLE hThread;
+ HANDLE hThread2;
+ BOOL bDupHandle=FALSE;
+ DWORD dwThreadId = 0;
+
+ if ((PAL_Initialize(argc,argv)) != 0)
+ {
+ return(FAIL);
+ }
+
+ /*Create Mutex without ownership*/
+ hMutex = CreateMutexW(NULL, // no security attributes
+ FALSE, // initially not owned
+ NULL); // name of mutex
+ if (hMutex == NULL)
+ {
+ Fail("ERROR:%u: Unable to create mutex\n",
+ GetLastError());
+ }
+
+ /*Create Duplicate of the Mutex above*/
+ bDupHandle = DuplicateHandle(GetCurrentProcess(),
+ hMutex,
+ GetCurrentProcess(),
+ &hDupMutex,
+ GENERIC_READ|GENERIC_WRITE,
+ FALSE,
+ DUPLICATE_SAME_ACCESS);
+ if (!bDupHandle)
+ {
+ Trace("ERROR:%u: Created the duplicate handle to "
+ "closed event handle hMutex=0x%lx\n",
+ GetLastError(),
+ hMutex);
+ CloseHandle(hMutex);
+ Fail("");
+ }
+
+ /*Create a thread to test the Mutex*/
+ hThread = CreateThread(NULL,
+ 0,
+ &ThreadTest1,
+ hMutex,
+ 0,
+ &dwThreadId);
+ if (hThread == NULL)
+ {
+ Trace("ERROR:%u: unable to create thread\n",
+ GetLastError());
+ CloseHandle(hMutex);
+ CloseHandle(hDupMutex);
+ Fail("");
+ }
+
+ /* wait until thread has taken the mutex */
+ while (WR_WAITING == t1_result)
+ Sleep(1);
+
+ if(WR_TIMED_OUT == t1_result)
+ {
+ Trace("ERROR: %u: thread 1 couldn't acquire the mutex\n");
+ CloseHandle(hMutex);
+ CloseHandle(hDupMutex);
+ CloseHandle(hThread);
+ Fail("");
+ }
+
+ /*Create a second thread to use the duplicate Mutex*/
+ /*This should fail since the Mutex is owned hThread*/
+ hThread2 = CreateThread(NULL,
+ 0,
+ &ThreadTest2,
+ hDupMutex,
+ 0,
+ &dwThreadId);
+
+ if (hThread2 == NULL)
+ {
+ Trace("ERROR:%u: unable to create thread\n",
+ GetLastError());
+ CloseHandle(hMutex);
+ CloseHandle(hDupMutex);
+ CloseHandle(hThread);
+ Fail("");
+ }
+
+ /* wait until thread has tried to take the mutex */
+ while (WR_WAITING == t2_result)
+ Sleep(1);
+
+ if (WR_TIMED_OUT != t2_result )
+ {
+ Trace("ERROR:%u: Able to take mutex %#x while its duplicate %#x is "
+ "held\n", hDupMutex, hMutex);
+ CloseHandle(hMutex);
+ CloseHandle(hDupMutex);
+ CloseHandle(hThread);
+ CloseHandle(hThread2);
+ Fail("");
+ }
+
+ /* reset second thread status */
+ t2_result = WR_WAITING;
+
+ /* tell thread 1 to release the mutex */
+ t1_result = WR_WAITING;
+
+ /* wait for thread 1 to release the mutex */
+ while (WR_WAITING == t1_result)
+ Sleep(1);
+
+ CloseHandle(hThread2);
+
+ /*Re-Create the second thread to reuse the duplicated Mutex*/
+ /*This test should pass, the Mutex has since been released*/
+ hThread2 = CreateThread(NULL,
+ 0,
+ &ThreadTest2,
+ hDupMutex,
+ 0,
+ &dwThreadId);
+
+ if (hThread2 == NULL)
+ {
+ Trace("ERROR:%u: unable to create thread\n",
+ GetLastError());
+ CloseHandle(hMutex);
+ CloseHandle(hDupMutex);
+ CloseHandle(hThread);
+ Fail("");
+ }
+
+ /* wait until thread has taken the mutex */
+ while (WR_WAITING == t2_result)
+ Sleep(1);
+
+ if (WR_GOT_MUTEX != t2_result )
+ {
+ Trace("ERROR:%u: Unable to take mutex %#x after its duplicate %#x was "
+ "released\n", hDupMutex, hMutex);
+ CloseHandle(hMutex);
+ CloseHandle(hDupMutex);
+ CloseHandle(hThread);
+ CloseHandle(hThread2);
+ Fail("");
+ }
+
+ /*Cleanup.*/
+ CloseHandle(hMutex);
+ CloseHandle(hDupMutex);
+ CloseHandle(hThread);
+ CloseHandle(hThread2);
+
+ PAL_Terminate();
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test4/testinfo.dat b/src/pal/tests/palsuite/threading/DuplicateHandle/test4/testinfo.dat
new file mode 100644
index 0000000000..64842f8713
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test4/testinfo.dat
@@ -0,0 +1,19 @@
+# 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.
+
+Version = 1.0
+Section = Threading
+Function = DuplicateHandle
+Name = Test for DuplicateHandle (CreateMutex)
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Tests the PAL implementation of the DuplicateHandle function.
+= This test duplication of a Mutex handle. The test will comprise
+= of creating a Mutex and its duplicate and create a thread that will
+= get ownership. Another thread will be create that will attempt to
+= get ownership of the duplicate Mutex, this will fail, since the
+= Mutex is owned by another thread. The Mutex will be released and
+= then the thread will attempt to get ownership of the duplicate
+= Mutex, this will succeed.
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test5/CMakeLists.txt b/src/pal/tests/palsuite/threading/DuplicateHandle/test5/CMakeLists.txt
new file mode 100644
index 0000000000..bc468a4a75
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_duplicatehandle_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_duplicatehandle_test5 coreclrpal)
+
+target_link_libraries(paltest_duplicatehandle_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test5/test5.c b/src/pal/tests/palsuite/threading/DuplicateHandle/test5/test5.c
new file mode 100644
index 0000000000..a588928f00
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test5/test5.c
@@ -0,0 +1,145 @@
+// 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: test5.c (DuplicateHandle)
+**
+** Purpose: Tests the PAL implementation of the DuplicateHandle function,
+** with CreatePipe. This test will create a pipe and write to it,
+** the duplicate the read handle and read what was written.
+**
+** Depends: WriteFile
+** ReadFile
+** memcmp
+** CloseHandle
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+const char* cTestString = "one fish, two fish, red fish, blue fish.";
+
+int __cdecl main(int argc, char **argv)
+{
+ HANDLE hReadPipe = NULL;
+ HANDLE hWritePipe = NULL;
+ HANDLE hDupPipe = NULL;
+ BOOL bRetVal = FALSE;
+ DWORD dwBytesWritten;
+ DWORD dwBytesRead;
+ char buffer[256];
+
+ SECURITY_ATTRIBUTES lpPipeAttributes;
+
+ /*Initialize the PAL*/
+ if ((PAL_Initialize(argc, argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+ /*Setup SECURITY_ATTRIBUTES structure for CreatePipe*/
+ lpPipeAttributes.nLength = sizeof(lpPipeAttributes);
+ lpPipeAttributes.lpSecurityDescriptor = NULL;
+ lpPipeAttributes.bInheritHandle = TRUE;
+
+ /*Create a Pipe*/
+ bRetVal = CreatePipe(&hReadPipe, /* read handle*/
+ &hWritePipe, /* write handle */
+ &lpPipeAttributes,/* security attributes*/
+ 0); /* pipe size*/
+ if (bRetVal == FALSE)
+ {
+ Fail("ERROR:%u:Unable to create pipe\n", GetLastError());
+ }
+
+ /*Write to the write pipe handle*/
+ bRetVal = WriteFile(hWritePipe, /* handle to write pipe*/
+ cTestString, /* buffer to write*/
+ strlen(cTestString),/* number of bytes to write*/
+ &dwBytesWritten, /* number of bytes written*/
+ NULL); /* overlapped buffer*/
+ if (bRetVal == FALSE)
+ {
+ Trace("ERROR:%u:unable to write to write pipe handle "
+ "hWritePipe=0x%lx\n", GetLastError(), hWritePipe);
+ CloseHandle(hReadPipe);
+ CloseHandle(hWritePipe);
+ Fail("");
+ }
+
+ /*Duplicate the pipe handle*/
+ if (!(DuplicateHandle(GetCurrentProcess(), /* source handle process*/
+ hReadPipe, /* handle to duplicate*/
+ GetCurrentProcess(), /* target process handle*/
+ &hDupPipe, /* duplicate handle*/
+ GENERIC_READ|GENERIC_WRITE,/* requested access*/
+ FALSE, /* handle inheritance*/
+ DUPLICATE_SAME_ACCESS))) /* optional actions*/
+ {
+ Trace("ERROR:%u:Fail to create the duplicate handle"
+ " to hReadPipe=0x%lx",
+ GetLastError(),
+ hReadPipe);
+ CloseHandle(hReadPipe);
+ CloseHandle(hWritePipe);
+ Fail("");
+ }
+
+ /*Read from the duplicated handle, 256 bytes, more bytes
+ than actually written. This will allow us to use the
+ value that ReadFile returns for comparision.*/
+ bRetVal = ReadFile(hDupPipe, /* handle to read pipe*/
+ buffer, /* buffer to write to*/
+ 256, /* number of bytes to read*/
+ &dwBytesRead, /* number of bytes read*/
+ NULL); /* overlapped buffer*/
+ if (bRetVal == FALSE)
+ {
+ Trace("ERROR:%u:unable read from the duplicated pipe "
+ "hDupPipe=0x%lx\n",
+ GetLastError(),
+ hDupPipe);
+ CloseHandle(hReadPipe);
+ CloseHandle(hWritePipe);
+ CloseHandle(hDupPipe);
+ Fail("");
+ }
+
+ /*Compare what was read with what was written.*/
+ if ((memcmp(cTestString, buffer, dwBytesRead)) != 0)
+ {
+ Trace("ERROR:%u: read \"%s\" expected \"%s\" \n",
+ GetLastError(),
+ buffer,
+ cTestString);
+ CloseHandle(hReadPipe);
+ CloseHandle(hWritePipe);
+ CloseHandle(hDupPipe);
+ Fail("");
+ }
+
+ /*Compare values returned from WriteFile and ReadFile.*/
+ if (dwBytesWritten != dwBytesRead)
+ {
+ Trace("ERROR:%u: WriteFile wrote \"%s\", but ReadFile read \"%s\","
+ " these should be the same\n",
+ GetLastError(),
+ buffer,
+ cTestString);
+ CloseHandle(hReadPipe);
+ CloseHandle(hWritePipe);
+ CloseHandle(hDupPipe);
+ Fail("");
+ }
+
+ /*Cleanup.*/
+ CloseHandle(hWritePipe);
+ CloseHandle(hReadPipe);
+ CloseHandle(hDupPipe);
+
+ PAL_Terminate();
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test5/testinfo.dat b/src/pal/tests/palsuite/threading/DuplicateHandle/test5/testinfo.dat
new file mode 100644
index 0000000000..97e42a9787
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test5/testinfo.dat
@@ -0,0 +1,14 @@
+# 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.
+
+Version = 1.0
+Section = Threading
+Function = DuplicateHandle
+Name = Test for DuplicateHandle (CreatePipe)
+TYPE = DEFAULT
+EXE1 = test5
+Description
+= Tests the PAL implementation of the DuplicateHandle function,
+= with CreatePipe. This test will create a pipe and write to it,
+= then duplicate the read handle and read what was written.
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test6/CMakeLists.txt b/src/pal/tests/palsuite/threading/DuplicateHandle/test6/CMakeLists.txt
new file mode 100644
index 0000000000..20f7822b1e
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test6.c
+)
+
+add_executable(paltest_duplicatehandle_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_duplicatehandle_test6 coreclrpal)
+
+target_link_libraries(paltest_duplicatehandle_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test6/test6.c b/src/pal/tests/palsuite/threading/DuplicateHandle/test6/test6.c
new file mode 100644
index 0000000000..026f315a44
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test6/test6.c
@@ -0,0 +1,146 @@
+// 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: test6.c (DuplicateHandle)
+**
+** Purpose: Tests the PAL implementation of the DuplicateHandle function,
+** with CreatePipe. This test will create a pipe, then duplicate
+** the write handle, write to the handle, and use the read to
+** verify.
+**
+** Depends: WriteFile
+** ReadFile
+** memcmp
+** CloseHandle
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+const char* cTestString = "one fish, two fish, red fish, blue fish.";
+
+int __cdecl main(int argc, char **argv)
+{
+ HANDLE hReadPipe = NULL;
+ HANDLE hWritePipe = NULL;
+ HANDLE hDupPipe = NULL;
+ BOOL bRetVal = FALSE;
+ DWORD dwBytesWritten;
+ DWORD dwBytesRead;
+ char buffer[256];
+
+ SECURITY_ATTRIBUTES lpPipeAttributes;
+
+ /*Initialize the PAL*/
+ if ((PAL_Initialize(argc, argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+ /*Setup SECURITY_ATTRIBUTES structure for CreatePipe*/
+ lpPipeAttributes.nLength = sizeof(lpPipeAttributes);
+ lpPipeAttributes.lpSecurityDescriptor = NULL;
+ lpPipeAttributes.bInheritHandle = TRUE;
+
+ /*Create a Pipe*/
+ bRetVal = CreatePipe(&hReadPipe, /* read handle*/
+ &hWritePipe, /* write handle */
+ &lpPipeAttributes,/* security attributes*/
+ 0); /* pipe size*/
+ if (bRetVal == FALSE)
+ {
+ Fail("ERROR: %ld :Unable to create pipe\n", GetLastError());
+ }
+
+ /*Duplicate the pipe handle*/
+ if (!(DuplicateHandle(GetCurrentProcess(), /* source handle process*/
+ hWritePipe, /* handle to duplicate*/
+ GetCurrentProcess(), /* target process handle*/
+ &hDupPipe, /* duplicate handle*/
+ GENERIC_READ|GENERIC_WRITE,/* requested access*/
+ FALSE, /* handle inheritance*/
+ DUPLICATE_SAME_ACCESS))) /* optional actions*/
+ {
+ Trace("ERROR: %ld :Fail to create the duplicate handle"
+ " to hWritePipe=0x%lx",
+ GetLastError(),
+ hWritePipe);
+ CloseHandle(hReadPipe);
+ CloseHandle(hWritePipe);
+ Fail("");
+ }
+
+ /*Write to the duplicate write pipe handle*/
+ bRetVal = WriteFile(hDupPipe, /* handle to write pipe*/
+ cTestString, /* buffer to write*/
+ strlen(cTestString),/* number of bytes to write*/
+ &dwBytesWritten, /* number of bytes written*/
+ NULL); /* overlapped buffer*/
+ if (bRetVal == FALSE)
+ {
+ Trace("ERROR: %ld :unable to write to duplicate write pipe handle "
+ "hDupPipe=0x%lx\n",
+ GetLastError(),
+ hDupPipe);
+ CloseHandle(hReadPipe);
+ CloseHandle(hWritePipe);
+ CloseHandle(hDupPipe);
+ Fail("");
+ }
+
+ /*Read from the read handle, 256 bytes, more bytes
+ then actually written. This will give allow us to use
+ the value that ReadFile returns for comparision.*/
+ bRetVal = ReadFile(hReadPipe, /* handle to read pipe*/
+ buffer, /* buffer to write to*/
+ 256, /* number of bytes to read*/
+ &dwBytesRead, /* number of bytes read*/
+ NULL); /* overlapped buffer*/
+ if (bRetVal == FALSE)
+ {
+ Trace("ERROR: %ld : unable read hReadPipe=0x%lx\n",
+ GetLastError(), hReadPipe);
+ CloseHandle(hReadPipe);
+ CloseHandle(hWritePipe);
+ CloseHandle(hDupPipe);
+ Fail("");
+ }
+
+ /*Compare what was read with what was written.*/
+ if ((memcmp(cTestString, buffer, dwBytesRead)) != 0)
+ {
+ Trace("ERROR: read \"%s\" expected \"%s\" \n",
+ buffer,
+ cTestString);
+ CloseHandle(hReadPipe);
+ CloseHandle(hWritePipe);
+ CloseHandle(hDupPipe);
+ Fail("");
+ }
+
+ /*Compare values returned from WriteFile and ReadFile.*/
+ if (dwBytesWritten != dwBytesRead)
+ {
+ Trace("ERROR: WriteFile wrote \"%s\", but ReadFile read \"%s\","
+ " these should be the same\n",
+ buffer,
+ cTestString);
+ CloseHandle(hReadPipe);
+ CloseHandle(hWritePipe);
+ CloseHandle(hDupPipe);
+ Fail("");
+ }
+
+ /*Cleanup.*/
+ CloseHandle(hReadPipe);
+ CloseHandle(hWritePipe);
+ CloseHandle(hDupPipe);
+
+
+ PAL_Terminate();
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test6/testinfo.dat b/src/pal/tests/palsuite/threading/DuplicateHandle/test6/testinfo.dat
new file mode 100644
index 0000000000..6c49d64f89
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test6/testinfo.dat
@@ -0,0 +1,15 @@
+# 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.
+
+Version = 1.0
+Section = Threading
+Function = DuplicateHandle
+Name = Test for DuplicateHandle (CreatePipe)
+TYPE = DEFAULT
+EXE1 = test6
+Description
+= Tests the PAL implementation of the DuplicateHandle function,
+= with CreatePipe. This test will create a pipe, then duplicate
+= the write handle, write to the handle, and use the read to
+= verify.
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test7/CMakeLists.txt b/src/pal/tests/palsuite/threading/DuplicateHandle/test7/CMakeLists.txt
new file mode 100644
index 0000000000..df3fdf9ae0
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test7.c
+)
+
+add_executable(paltest_duplicatehandle_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_duplicatehandle_test7 coreclrpal)
+
+target_link_libraries(paltest_duplicatehandle_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test7/test7.c b/src/pal/tests/palsuite/threading/DuplicateHandle/test7/test7.c
new file mode 100644
index 0000000000..0477291922
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test7/test7.c
@@ -0,0 +1,149 @@
+// 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: test7.c (DuplicateHandle)
+**
+** Purpose: Tests the PAL implementation of the DuplicateHandle function,
+** with a handle from CreateThread. The test will create a thread
+** handle and its duplicate. Then get the priorities of the threads,
+** set the priority of one and the change should be seen in the
+** other.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+DWORD PALAPI CreateTestThread(LPVOID lpParam);
+
+int __cdecl main(int argc, char* argv[])
+{
+ HANDLE hThread;
+ HANDLE hDupThread;
+ DWORD dwThreadId = 0;
+ LPTHREAD_START_ROUTINE lpStartAddress = &CreateTestThread;
+
+ int threadPriority;
+ int duplicatePriority;
+ int finalPriority;
+
+ /* Initialize the PAL.*/
+ if ((PAL_Initialize(argc, argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+ /* Create a thread.*/
+ hThread = CreateThread(NULL, /* SD*/
+ (DWORD)0, /* initial stack size*/
+ lpStartAddress, /* thread function*/
+ NULL, /* thread argument*/
+ (DWORD)0, /* creation option*/
+ &dwThreadId); /* thread identifier*/
+ if (hThread == NULL)
+ {
+ Fail("ERROR:%u: Unable to create thread.\n",
+ GetLastError());
+ }
+
+ /* Duplicate the thread handle.*/
+ if (!(DuplicateHandle(GetCurrentProcess(), /* source handle process*/
+ hThread, /* handle to duplicate*/
+ GetCurrentProcess(), /* target process handle*/
+ &hDupThread, /* duplicate handle*/
+ (DWORD)0, /* requested access*/
+ FALSE, /* handle inheritance*/
+ DUPLICATE_SAME_ACCESS))) /* optional actions*/
+ {
+ Trace("ERROR: %ld :Fail to create the duplicate handle"
+ " to hThread=0x%lx",
+ GetLastError(),
+ hThread);
+ CloseHandle(hThread);
+ Fail("");
+ }
+
+ /* Get the priority of the thread.*/
+ threadPriority = GetThreadPriority(hThread);
+ if(threadPriority != 0)
+ {
+ Trace("ERROR: Thread priority of hThread=0x%lx should be "
+ "set to normal THREAD_PRIORITY_NORMAL=%d\n",
+ hThread,
+ THREAD_PRIORITY_NORMAL);
+ CloseHandle(hThread);
+ CloseHandle(hDupThread);
+ Fail("");
+ }
+
+ /* Get the priority of the duplicated handle, and compare it to
+ * the priority of the original thread. Should be the same.*/
+ duplicatePriority = GetThreadPriority(hThread);
+ if(duplicatePriority != threadPriority)
+ {
+ Trace("ERROR: Expected priority of hThread=0x%lx and hDupThread=0x%lx"
+ " to be the same. Priorities:hThread=\"%d\":hDupThread=\"%d\"\n",
+ hThread,
+ hDupThread,
+ threadPriority,
+ duplicatePriority);
+ CloseHandle(hThread);
+ CloseHandle(hDupThread);
+ Fail("");
+ }
+
+ /* Set the priority of the duplicate thread.*/
+ if(!SetThreadPriority (hDupThread,THREAD_PRIORITY_HIGHEST))
+ {
+ Trace("ERROR:%u: SetThreadPriority failed on hThread=0x%lx\n",
+ GetLastError(),
+ hDupThread);
+ CloseHandle(hThread);
+ CloseHandle(hDupThread);
+ Fail("");
+ }
+
+ /* Get the priority of the origianl thread, and
+ * compare it to what the duplicate was set to.*/
+ finalPriority = GetThreadPriority(hThread);
+ if (finalPriority != THREAD_PRIORITY_HIGHEST)
+ {
+ Trace("ERROR: Expected priority of hThread=0x%lw and "
+ "hDupThread=0x%lw to be set the same. Priorities:"
+ "hThread=\"%d\":hDupThread=\"%d\".\n",
+ hThread,
+ hDupThread,
+ threadPriority,
+ duplicatePriority);
+ CloseHandle(hThread);
+ CloseHandle(hDupThread);
+ Fail("");
+ }
+
+ /* Wait on the original thread.*/
+ if((WaitForSingleObject(hThread, 100)) != WAIT_OBJECT_0)
+ {
+ Trace("ERROR:%u: hThread=0x%lx is in a non-signalled "
+ "mode, yet created signalled.\n",
+ GetLastError(),
+ hThread);
+ CloseHandle(hThread);
+ CloseHandle(hDupThread);
+ Fail("");
+ }
+
+ /* Clean-up thread and Terminate the PAL.*/
+ CloseHandle(hThread);
+ CloseHandle(hDupThread);
+ PAL_Terminate();
+ return PASS;
+}
+
+/*Thread testing function, only return '0'*/
+DWORD PALAPI CreateTestThread(LPVOID lpParam)
+{
+ return (DWORD)0;
+}
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test7/testinfo.dat b/src/pal/tests/palsuite/threading/DuplicateHandle/test7/testinfo.dat
new file mode 100644
index 0000000000..b8092d6152
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test7/testinfo.dat
@@ -0,0 +1,16 @@
+# 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.
+
+Version = 1.0
+Section = Threading
+Function = DuplicateHandle
+Name = Test for DuplicateHandle (CreateThread)
+TYPE = DEFAULT
+EXE1 = test7
+Description
+= Tests the PAL implementation of the DuplicateHandle function,
+= with a handle from CreateThread. The test will create a thread
+= handle and its duplicate. Then get the priorities of the threads,
+= set the priority of one and the change should be seen in the
+= other.
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test8/CMakeLists.txt b/src/pal/tests/palsuite/threading/DuplicateHandle/test8/CMakeLists.txt
new file mode 100644
index 0000000000..15ec23d272
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test8/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test8.c
+)
+
+add_executable(paltest_duplicatehandle_test8
+ ${SOURCES}
+)
+
+add_dependencies(paltest_duplicatehandle_test8 coreclrpal)
+
+target_link_libraries(paltest_duplicatehandle_test8
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test8/test8.c b/src/pal/tests/palsuite/threading/DuplicateHandle/test8/test8.c
new file mode 100644
index 0000000000..6748c5dffd
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test8/test8.c
@@ -0,0 +1,164 @@
+// 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: test8.c (DuplicateHandle)
+**
+** Purpose: Tests the PAL implementation of the DuplicateHandle function,
+** with a handle from GetCurrentThread. The test will create a thread
+** handle, get the current thread and its duplicate. Then get the
+** priorities of the threads, set the priority of one and the change
+** should be seen in the other.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+DWORD PALAPI CreateTestThread(LPVOID lpParam);
+
+int __cdecl main(int argc, char* argv[])
+{
+ HANDLE hThread;
+ HANDLE hCurrentThread;
+ HANDLE hDupThread;
+ DWORD dwThreadId = 0;
+ LPTHREAD_START_ROUTINE lpStartAddress = &CreateTestThread;
+
+ int threadPriority;
+ int duplicatePriority;
+ int finalPriority;
+
+ /* Initialize the PAL.*/
+ if ((PAL_Initialize(argc, argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+#if !HAVE_SCHED_OTHER_ASSIGNABLE
+ /* Defining thread priority for SCHED_OTHER is implementation defined.
+ Some platforms like NetBSD cannot reassign it as they are dynamic.
+ */
+ printf("paltest_duplicatehandle_test8 has been disabled on this platform\n");
+#else
+
+ /* Create a thread.*/
+ hThread = CreateThread(NULL, /* SD*/
+ (DWORD)0, /* initial stack size*/
+ lpStartAddress, /* thread function*/
+ NULL, /* thread argument*/
+ (DWORD)0, /* creation option*/
+ &dwThreadId); /* thread identifier*/
+ if (hThread == NULL)
+ {
+ Fail("ERROR:%u: Unable to create thread.\n",
+ GetLastError());
+ }
+
+ /*Get a psuedo handle to the current thread.*/
+ hCurrentThread = GetCurrentThread();
+
+ /* Duplicate the psuedo thread handle.*/
+ if (!(DuplicateHandle(GetCurrentProcess(), /* source handle process*/
+ hCurrentThread, /* handle to duplicate*/
+ GetCurrentProcess(), /* target process handle*/
+ &hDupThread, /* duplicate handle*/
+ (DWORD)0, /* requested access*/
+ FALSE, /* handle inheritance*/
+ DUPLICATE_SAME_ACCESS))) /* optional actions*/
+ {
+ Trace("ERROR: %ld :Fail to create the duplicate handle"
+ " to hThread=0x%lx",
+ GetLastError(),
+ hThread);
+ CloseHandle(hThread);
+ Fail("");
+ }
+
+ /* Get the priority of the thread.*/
+ threadPriority = GetThreadPriority(hCurrentThread);
+ if(threadPriority != 0)
+ {
+ Trace("ERROR: Thread priority of hCurrentThread=0x%lx should be "
+ "set to normal THREAD_PRIORITY_NORMAL=%d\n",
+ hCurrentThread,
+ THREAD_PRIORITY_NORMAL);
+ CloseHandle(hThread);
+ CloseHandle(hDupThread);
+ Fail("");
+ }
+
+ /* Get the priority of the duplicated handle, and compare it to
+ * the priority of the original thread. Should be the same.*/
+ duplicatePriority = GetThreadPriority(hCurrentThread);
+ if(duplicatePriority != threadPriority)
+ {
+ Trace("ERROR: Expected priority of hCurrentThread=0x%lx and "
+ "hDupThread=0x%lx to be the same. Priorities:hThread="
+ "\"%d\":hDupThread=\"%d\"\n",
+ hCurrentThread,
+ hDupThread,
+ threadPriority,
+ duplicatePriority);
+ CloseHandle(hThread);
+ CloseHandle(hDupThread);
+ Fail("");
+ }
+
+ /* Set the priority of the original thread.*/
+ if(!SetThreadPriority (hCurrentThread,THREAD_PRIORITY_HIGHEST))
+ {
+ Trace("ERROR:%u: SetThreadPriority failed on hCurrentThread=0x%lx\n",
+ GetLastError(),
+ hCurrentThread);
+ CloseHandle(hThread);
+ CloseHandle(hDupThread);
+ Fail("");
+ }
+
+ /* Get the priority of the duplicate thread, and
+ * compare it to what the original was set to.*/
+ finalPriority = GetThreadPriority(hDupThread);
+ if (finalPriority != THREAD_PRIORITY_HIGHEST)
+ {
+ Trace("ERROR: Expected priority of hCurrentThread=0x%lw and "
+ "hDupThread=0x%lw to be set the same. Priorities:"
+ "hCurrentThread=\"%d\":hDupThread=\"%d\".\n",
+ hCurrentThread,
+ hDupThread,
+ threadPriority,
+ duplicatePriority);
+ CloseHandle(hThread);
+ CloseHandle(hDupThread);
+ Fail("");
+ }
+
+ /* Wait on the original thread.*/
+ if((WaitForSingleObject(hThread, 100)) != WAIT_OBJECT_0)
+ {
+ Trace("ERROR:%u: hCurrentThread=0x%lx is in a non-signalled "
+ "mode, yet created signalled.\n",
+ GetLastError(),
+ hThread);
+ CloseHandle(hThread);
+ CloseHandle(hDupThread);
+ Fail("");
+ }
+
+ /* Clean-up thread and Terminate the PAL.*/
+ CloseHandle(hThread);
+ CloseHandle(hDupThread);
+
+#endif
+
+ PAL_Terminate();
+ return PASS;
+}
+
+/*Thread testing function, only return '0'*/
+DWORD PALAPI CreateTestThread(LPVOID lpParam)
+{
+ return (DWORD)0;
+}
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test8/testinfo.dat b/src/pal/tests/palsuite/threading/DuplicateHandle/test8/testinfo.dat
new file mode 100644
index 0000000000..ae1353af18
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test8/testinfo.dat
@@ -0,0 +1,16 @@
+# 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.
+
+Version = 1.0
+Section = Threading
+Function = DuplicateHandle
+Name = Test for DuplicateHandle (GetCurrentThread)
+TYPE = DEFAULT
+EXE1 = test8
+Description
+=Tests the PAL implementation of the DuplicateHandle function,
+=with a handle from GetCurrentThread. The test will create a thread
+=handle, get the current thread and its duplicate. Then get the
+=priorities of the threads, set the priority of one and the change
+=should be seen in the other.
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test9/CMakeLists.txt b/src/pal/tests/palsuite/threading/DuplicateHandle/test9/CMakeLists.txt
new file mode 100644
index 0000000000..e4442e327c
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test9/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test9.c
+)
+
+add_executable(paltest_duplicatehandle_test9
+ ${SOURCES}
+)
+
+add_dependencies(paltest_duplicatehandle_test9 coreclrpal)
+
+target_link_libraries(paltest_duplicatehandle_test9
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test9/test9.c b/src/pal/tests/palsuite/threading/DuplicateHandle/test9/test9.c
new file mode 100644
index 0000000000..f15871c57d
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test9/test9.c
@@ -0,0 +1,127 @@
+// 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: test9.c (DuplicateHandle)
+**
+** Purpose: Tests the PAL implementation of the DuplicateHandle function,
+** with a handle from GetCurrentProcess. The test will create a
+** process, duplicate it, then using ReadProcessMemory will
+** read from the memory location of the CreateProcess process
+** memory and the DuplicateHandle process memory. If the
+** duplication is correct the memory will be the same for both.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char* argv[])
+{
+ HANDLE hProcess;
+ HANDLE hDupProcess;
+ char lpBuffer[64];
+ char lpDupBuffer[64];
+ SIZE_T lpNumberOfBytesRead;
+ SIZE_T lpDupNumberOfBytesRead;
+ char lpTestBuffer[] = "abcdefghijklmnopqrstuvwxyz";
+
+ /* Initalize the PAL.
+ */
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Initalize the buffers.
+ */
+ ZeroMemory( &lpBuffer, sizeof(lpBuffer) );
+ ZeroMemory( &lpDupBuffer, sizeof(lpDupBuffer) );
+
+ /* Get current proces, this will be duplicated.
+ */
+ hProcess = GetCurrentProcess();
+ if(hProcess == NULL)
+ {
+ Fail("ERROR: Unable to get the current process\n");
+ }
+
+ /* Duplicate the current process handle.
+ */
+ if (!(DuplicateHandle(GetCurrentProcess(), /* source handle process*/
+ hProcess, /* handle to duplicate*/
+ GetCurrentProcess(), /* target process handle*/
+ &hDupProcess, /* duplicate handle*/
+ (DWORD)0, /* requested access*/
+ FALSE, /* handle inheritance*/
+ DUPLICATE_SAME_ACCESS))) /* optional actions*/
+ {
+ Trace("ERROR:%u: Failed to create the duplicate handle"
+ " to hProcess=0x%lx",
+ GetLastError(),
+ hProcess);
+ CloseHandle(hProcess);
+ Fail("");
+ }
+
+ /* Get memory read of the current process.
+ */
+ if ((ReadProcessMemory(hDupProcess, &lpTestBuffer,
+ lpDupBuffer, sizeof(lpDupBuffer), &lpDupNumberOfBytesRead)) == 0)
+ {
+ Trace("ERROR:%u: Unable to read the process memory of "
+ "hDupProcess=0x%lx.\n",
+ GetLastError(),
+ hDupProcess);
+ CloseHandle(hProcess);
+ CloseHandle(hDupProcess);
+ Fail("");
+ }
+
+ /* Get read memory of the created process.
+ */
+ if ((ReadProcessMemory(hProcess, &lpTestBuffer,
+ lpBuffer, sizeof(lpBuffer), &lpNumberOfBytesRead)) == 0)
+ {
+ Trace("ERROR:%u: Unable to read the process memory of "
+ "hProcess=0x%lx.\n",
+ GetLastError(),
+ hProcess);
+ CloseHandle(hProcess);
+ CloseHandle(hDupProcess);
+ Fail("");
+ }
+
+ /* Compare the number of bytes that were read by each
+ * ReadProcessMemory.*/
+ if (lpDupNumberOfBytesRead != lpNumberOfBytesRead)
+ {
+ Trace("ERROR: ReadProcessMemory read different numbers of bytes "
+ "from duplicate process handles.\n");
+ CloseHandle(hProcess);
+ CloseHandle(hDupProcess);
+ Fail("");
+ }
+
+ /* Compare the two buffers to make sure they are equal.
+ */
+ if ((strcmp(lpBuffer, lpDupBuffer)) != 0)
+ {
+ Trace("ERROR: ReadProcessMemory read different numbers of bytes "
+ "from duplicate process handles. hProcess read \"%s\" and "
+ "hDupProcess read \"%s\"\n",
+ lpBuffer,
+ lpDupBuffer);
+ CloseHandle(hProcess);
+ CloseHandle(hDupProcess);
+ Fail("");
+ }
+
+ /* Clean-up thread and Terminate the PAL.*/
+ CloseHandle(hProcess);
+ CloseHandle(hDupProcess);
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test9/testinfo.dat b/src/pal/tests/palsuite/threading/DuplicateHandle/test9/testinfo.dat
new file mode 100644
index 0000000000..c7122908fd
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test9/testinfo.dat
@@ -0,0 +1,17 @@
+# 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.
+
+Version = 1.0
+Section = Threading
+Function = DuplicateHandle
+Name = Test for DuplicateHandle (GetCurrentProcess)
+TYPE = DEFAULT
+EXE1 = test9
+Description
+= Tests the PAL implementation of the DuplicateHandle function,
+= with a handle from GetCurrentProcess. The test will create a
+= process, duplicate it, then using ReadProcessMemory will
+= read from the memory location of the CreateProcess process
+= memory and the DuplicateHandle process memory. If the
+= duplication is correct the memory will be the same for both.