diff options
Diffstat (limited to 'src/pal/tests/palsuite/threading/OpenProcess')
6 files changed, 430 insertions, 0 deletions
diff --git a/src/pal/tests/palsuite/threading/OpenProcess/CMakeLists.txt b/src/pal/tests/palsuite/threading/OpenProcess/CMakeLists.txt new file mode 100644 index 0000000000..f6aa0cb2d9 --- /dev/null +++ b/src/pal/tests/palsuite/threading/OpenProcess/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +add_subdirectory(test1) + diff --git a/src/pal/tests/palsuite/threading/OpenProcess/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/OpenProcess/test1/CMakeLists.txt new file mode 100644 index 0000000000..26d30547a9 --- /dev/null +++ b/src/pal/tests/palsuite/threading/OpenProcess/test1/CMakeLists.txt @@ -0,0 +1,36 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(TESTSOURCES + test1.c +) + +add_executable(paltest_openprocess_test1 + ${TESTSOURCES} +) + +add_dependencies(paltest_openprocess_test1 coreclrpal) + +target_link_libraries(paltest_openprocess_test1 + pthread + m + coreclrpal +) + + +set(HELPERSOURCES + childProcess.c +) + +add_executable(paltest_openprocess_test1_child + ${HELPERSOURCES} +) + +add_dependencies(paltest_openprocess_test1_child coreclrpal) + +target_link_libraries(paltest_openprocess_test1_child + pthread + m + coreclrpal +) diff --git a/src/pal/tests/palsuite/threading/OpenProcess/test1/childProcess.c b/src/pal/tests/palsuite/threading/OpenProcess/test1/childProcess.c new file mode 100644 index 0000000000..9ef07433fd --- /dev/null +++ b/src/pal/tests/palsuite/threading/OpenProcess/test1/childProcess.c @@ -0,0 +1,75 @@ +// 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 OpenProcess works properly. +** All this program does is return a predefined value. +** +** 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','\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/OpenProcess/test1/myexitcode.h b/src/pal/tests/palsuite/threading/OpenProcess/test1/myexitcode.h new file mode 100644 index 0000000000..66b8f43a97 --- /dev/null +++ b/src/pal/tests/palsuite/threading/OpenProcess/test1/myexitcode.h @@ -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. + +/*============================================================================ +** +** Source: myexitcode.h +** +** Purpose: Define an exit code. +** +** +**==========================================================================*/ + +#define TEST_EXIT_CODE 317 diff --git a/src/pal/tests/palsuite/threading/OpenProcess/test1/test1.c b/src/pal/tests/palsuite/threading/OpenProcess/test1/test1.c new file mode 100644 index 0000000000..d0f9019646 --- /dev/null +++ b/src/pal/tests/palsuite/threading/OpenProcess/test1/test1.c @@ -0,0 +1,282 @@ +// 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 +** +** Purpose: Test to ensure OpenProcess works properly. +** +** 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; + + char rgchDirName[_MAX_DIR]; + char absPathBuf[_MAX_PATH]; + char* rgchAbsPathName; + + BOOL ret = FAIL; + BOOL bChildDone = FALSE; + WCHAR wszMutexName[] = { 'T','E','S','T','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 cleanup2; + } + + /* release the mutex so the child can proceed */ + if( ReleaseMutex( hMutex ) == 0 ) + { + Trace( "ERROR:%lu:ReleaseMutex() call failed\n", GetLastError() ); + goto cleanup; + } + + /* wait for the child process to complete, using the new handle */ + dwRet = WaitForSingleObject( hChildProcess, 10000 ); + if( dwRet != WAIT_OBJECT_0 ) + { + Trace( "ERROR:WaitForSingleObject call returned %lu, " + "expected WAIT_OBJECT_0", + dwRet ); + goto cleanup; + } + + /* 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( hChildProcess, &dwExitCode ) ) + { + Trace( "ERROR:%lu:GetExitCodeProcess call failed\n", GetLastError() ); + goto cleanup; + } + + /* 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 cleanup; + } + + /* success if we get here */ + ret = PASS; + + +cleanup: + /* 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 all our handles */ + if( CloseHandle ( hChildProcess ) == 0 ) + { + Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() ); + ret = FAIL; + } + +cleanup2: + 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/OpenProcess/test1/testinfo.dat b/src/pal/tests/palsuite/threading/OpenProcess/test1/testinfo.dat new file mode 100644 index 0000000000..dd6b2c0ffe --- /dev/null +++ b/src/pal/tests/palsuite/threading/OpenProcess/test1/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 = OpenProcess +Name = Test for OpenProcess +TYPE = DEFAULT +EXE1 = test1 +EXE2 = childprocess +Description += Test to ensure proper operation of the OpenProcess API. += The test launches a trivial child process, then opens += a handle to it using OpenProcess. It uses that handle += 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. |