From 4b4aad7217d3292650e77eec2cf4c198ea9c3b4b Mon Sep 17 00:00:00 2001 From: Jiyoung Yun Date: Wed, 23 Nov 2016 19:09:09 +0900 Subject: Imported Upstream version 1.1.0 --- .../threading/DuplicateHandle/CMakeLists.txt | 15 + .../threading/DuplicateHandle/test1/CMakeLists.txt | 19 ++ .../threading/DuplicateHandle/test1/test1.c | 152 +++++++++ .../threading/DuplicateHandle/test1/testinfo.dat | 15 + .../DuplicateHandle/test10/CMakeLists.txt | 19 ++ .../threading/DuplicateHandle/test10/test10.c | 239 ++++++++++++++ .../threading/DuplicateHandle/test10/testinfo.dat | 17 + .../DuplicateHandle/test11/CMakeLists.txt | 36 ++ .../DuplicateHandle/test11/childprocess.c | 74 +++++ .../threading/DuplicateHandle/test11/myexitcode.h | 13 + .../threading/DuplicateHandle/test11/test11.c | 364 +++++++++++++++++++++ .../threading/DuplicateHandle/test11/testinfo.dat | 19 ++ .../DuplicateHandle/test12/CMakeLists.txt | 19 ++ .../threading/DuplicateHandle/test12/test12.c | 129 ++++++++ .../threading/DuplicateHandle/test12/testinfo.dat | 15 + .../threading/DuplicateHandle/test2/CMakeLists.txt | 19 ++ .../threading/DuplicateHandle/test2/test2.c | 96 ++++++ .../threading/DuplicateHandle/test2/testinfo.dat | 17 + .../threading/DuplicateHandle/test3/CMakeLists.txt | 19 ++ .../threading/DuplicateHandle/test3/test3.c | 123 +++++++ .../threading/DuplicateHandle/test3/testinfo.dat | 17 + .../threading/DuplicateHandle/test4/CMakeLists.txt | 19 ++ .../threading/DuplicateHandle/test4/test4.c | 239 ++++++++++++++ .../threading/DuplicateHandle/test4/testinfo.dat | 19 ++ .../threading/DuplicateHandle/test5/CMakeLists.txt | 19 ++ .../threading/DuplicateHandle/test5/test5.c | 145 ++++++++ .../threading/DuplicateHandle/test5/testinfo.dat | 14 + .../threading/DuplicateHandle/test6/CMakeLists.txt | 19 ++ .../threading/DuplicateHandle/test6/test6.c | 146 +++++++++ .../threading/DuplicateHandle/test6/testinfo.dat | 15 + .../threading/DuplicateHandle/test7/CMakeLists.txt | 19 ++ .../threading/DuplicateHandle/test7/test7.c | 149 +++++++++ .../threading/DuplicateHandle/test7/testinfo.dat | 16 + .../threading/DuplicateHandle/test8/CMakeLists.txt | 19 ++ .../threading/DuplicateHandle/test8/test8.c | 164 ++++++++++ .../threading/DuplicateHandle/test8/testinfo.dat | 16 + .../threading/DuplicateHandle/test9/CMakeLists.txt | 19 ++ .../threading/DuplicateHandle/test9/test9.c | 127 +++++++ .../threading/DuplicateHandle/test9/testinfo.dat | 17 + 39 files changed, 2617 insertions(+) create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/CMakeLists.txt create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test1/CMakeLists.txt create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test1/test1.c create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test1/testinfo.dat create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test10/CMakeLists.txt create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test10/test10.c create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test10/testinfo.dat create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test11/CMakeLists.txt create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test11/childprocess.c create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test11/myexitcode.h create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test11/test11.c create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test11/testinfo.dat create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test12/CMakeLists.txt create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test12/test12.c create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test12/testinfo.dat create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test2/CMakeLists.txt create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test2/test2.c create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test2/testinfo.dat create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test3/CMakeLists.txt create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test3/test3.c create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test3/testinfo.dat create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test4/CMakeLists.txt create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test4/test4.c create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test4/testinfo.dat create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test5/CMakeLists.txt create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test5/test5.c create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test5/testinfo.dat create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test6/CMakeLists.txt create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test6/test6.c create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test6/testinfo.dat create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test7/CMakeLists.txt create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test7/test7.c create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test7/testinfo.dat create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test8/CMakeLists.txt create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test8/test8.c create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test8/testinfo.dat create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test9/CMakeLists.txt create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test9/test9.c create mode 100644 src/pal/tests/palsuite/threading/DuplicateHandle/test9/testinfo.dat (limited to 'src/pal/tests/palsuite/threading/DuplicateHandle') 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 + +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 + +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 +#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 +#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 + +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 + +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 + +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 + +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 + +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 + +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 + +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 + +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 + +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. -- cgit v1.2.3