diff options
Diffstat (limited to 'src/pal/tests/palsuite/composite/object_management')
23 files changed, 3788 insertions, 0 deletions
diff --git a/src/pal/tests/palsuite/composite/object_management/CMakeLists.txt b/src/pal/tests/palsuite/composite/object_management/CMakeLists.txt new file mode 100644 index 0000000000..5fd88b0046 --- /dev/null +++ b/src/pal/tests/palsuite/composite/object_management/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +add_subdirectory(event) +add_subdirectory(mutex) +add_subdirectory(semaphore) + diff --git a/src/pal/tests/palsuite/composite/object_management/event/CMakeLists.txt b/src/pal/tests/palsuite/composite/object_management/event/CMakeLists.txt new file mode 100644 index 0000000000..2534564f95 --- /dev/null +++ b/src/pal/tests/palsuite/composite/object_management/event/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +add_subdirectory(nonshared) +add_subdirectory(shared) + diff --git a/src/pal/tests/palsuite/composite/object_management/event/nonshared/CMakeLists.txt b/src/pal/tests/palsuite/composite/object_management/event/nonshared/CMakeLists.txt new file mode 100644 index 0000000000..c6c00377e1 --- /dev/null +++ b/src/pal/tests/palsuite/composite/object_management/event/nonshared/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(SOURCES + event.c + main.c +) + +add_executable(paltest_event_nonshared + ${SOURCES} +) + +add_dependencies(paltest_event_nonshared coreclrpal) + +target_link_libraries(paltest_event_nonshared + pthread + rt + m + coreclrpal +) diff --git a/src/pal/tests/palsuite/composite/object_management/event/nonshared/event.c b/src/pal/tests/palsuite/composite/object_management/event/nonshared/event.c new file mode 100644 index 0000000000..69ad9a30e3 --- /dev/null +++ b/src/pal/tests/palsuite/composite/object_management/event/nonshared/event.c @@ -0,0 +1,358 @@ +// 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 Code: main.c and event.c +** main.c creates process and waits for all processes to get over +** event.c creates a event and then calls threads which will contend for the event +** +** This test is for Object Management Test case for event where Object type is shareable. +** Algorithm +** o Main Process Creates OBJECT_TYPE Object +** o Create PROCESS_COUNT processes aware of the Shared Object +** +** Author: ShamitP +** +** +**============================================================ +*/ + +#include <palsuite.h> +#include "resultbuffer.h" +#include "resulttime.h" + +#define TIMEOUT 5000 +/* Test Input Variables */ +unsigned int USE_PROCESS_COUNT = 0; +unsigned int THREAD_COUNT = 0; +unsigned int REPEAT_COUNT = 0; +unsigned int RELATION_ID= 0; + +/* Event variables */ +//unsigned long lInitialCount = 1; /* Signaled */ +//unsigned long lMaximumCount = 1; /* Maximum value of 1 */ + +/* Capture statistics at per thread basis */ +struct statistics{ + unsigned int processId; + unsigned int operationsFailed; + unsigned int operationsPassed; + unsigned int operationsTotal; + DWORD operationTime; + unsigned int relationId; +}; + +struct ProcessStats{ + unsigned int processId; + DWORD operationTime; + unsigned int relationId; +}; + +HANDLE StartTestsEvHandle = NULL; +HANDLE hEventHandle = NULL; + +/* Results Buffer */ +ResultBuffer *resultBuffer = NULL; + +int testStatus; + +const char sTmpEventName[MAX_PATH_FNAME] = "StartTestEvent"; + +void PALAPI Run_Thread(LPVOID lpParam); + +int GetParameters( int argc, char **argv) +{ + if( (argc != 5) || ((argc == 1) && !strcmp(argv[1],"/?")) + || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H")) + { + printf("PAL -Composite Object Management Event Test\n"); + printf("Usage:\n"); + printf("Event\n\t[USE_PROCESS_COUNT [greater than 1] \n"); + printf("\t[THREAD_COUNT [greater than 1] \n"); + printf("\t[REPEAT_COUNT [greater than 1]\n"); + printf("\t[RELATION_ID [greater than or Equal to 1]\n"); + + return -1; + } + + // Trace("Args 1 is [%s], Arg 2 is [%s], Arg 3 is [%s]\n", argv[1], argv[2], argv[3]); + + USE_PROCESS_COUNT = atoi(argv[1]); + if( USE_PROCESS_COUNT < 0) + { + printf("\nInvalid USE_PROCESS_COUNT number, Pass greater than 1\n"); + return -1; + } + + THREAD_COUNT = atoi(argv[2]); + if( (THREAD_COUNT < 1) || (THREAD_COUNT > MAXIMUM_WAIT_OBJECTS) ) + { + printf("\nInvalid THREAD_COUNT number, Pass greater than 1 and less than %d\n", MAXIMUM_WAIT_OBJECTS); + return -1; + } + + REPEAT_COUNT = atoi(argv[3]); + if( REPEAT_COUNT < 1) + { + printf("\nInvalid REPEAT_COUNT number, Pass greater than 1\n"); + return -1; + } + + RELATION_ID = atoi(argv[4]); + if( RELATION_ID < 1) + { + printf("\nMain Process:Invalid RELATION_ID number, Pass greater than 1\n"); + return -1; + } + + + return 0; +} + + int __cdecl main(INT argc, CHAR **argv) +{ + unsigned int i = 0; + HANDLE hThread[MAXIMUM_WAIT_OBJECTS]; + DWORD threadId[MAXIMUM_WAIT_OBJECTS]; + int returnCode = 0; + + DWORD dwParam = 0; + + /* Variables to capture the file name and the file pointer at thread level*/ + char fileName[MAX_LONGPATH]; + FILE *pFile = NULL; + struct statistics* buffer = NULL; + int statisticsSize = 0; + + /* Variables to capture the file name and the file pointer at process level*/ + char processFileName[MAX_LONGPATH]; + FILE *pProcessFile = NULL; + struct ProcessStats processStats; + DWORD dwStartTime; + + testStatus = PASS; + + if(0 != (PAL_Initialize(argc, argv))) + { + return ( FAIL ); + } + + if(GetParameters(argc, argv)) + { + Fail("Error in obtaining the parameters\n"); + } +// Trace("Process created, value of process count is [%d]\n", USE_PROCESS_COUNT); + + /* Register the start time */ + dwStartTime = GetTickCount(); + processStats.relationId = RELATION_ID; + processStats.processId = USE_PROCESS_COUNT; + + _snprintf(processFileName, MAX_LONGPATH, "%d_process_event_%d_.txt", USE_PROCESS_COUNT, RELATION_ID); + pProcessFile = fopen(processFileName, "w+"); + if(pProcessFile == NULL) + { + Fail("Error in opening process File file for write for process [%d]\n", USE_PROCESS_COUNT); + } + + statisticsSize = sizeof(struct statistics); + + _snprintf(fileName, MAX_LONGPATH, "%d_thread_event_%d_.txt", USE_PROCESS_COUNT, RELATION_ID); + pFile = fopen(fileName, "w+"); + + if(pFile == NULL) + { + Fail("Error in opening thread File for write for process [%d]\n", USE_PROCESS_COUNT); + } + // For each thread we will log operations failed (int), passed (int), total (int) + // and number of ticks (DWORD) for the operations + resultBuffer = new ResultBuffer( THREAD_COUNT, statisticsSize); + + StartTestsEvHandle = CreateEvent( + NULL, /* lpEventAttributes*/ + TRUE, /* bManualReset */ + FALSE, /* bInitialState */ + NULL /* name of Event */ + ); + + if( StartTestsEvHandle == NULL ) + { + Fail("Error:%d: Unexpected failure " + "to create %s Event for process count %d\n", GetLastError(), sTmpEventName, USE_PROCESS_COUNT ); + + } + + /* Create StartTest Event */ + + hEventHandle = CreateEvent( + NULL, /* lpEventAttributes, inheritable to child processes*/ + TRUE, /* bAutomaticReset */ + TRUE, /* bInitialState */ + NULL + ); + + if( hEventHandle == NULL) + { + Fail("Unable to create Event handle for process id [%d], returned error [%d]\n", i, GetLastError()); + } + /* We already assume that the Event was created previously*/ + + for( i = 0; i < THREAD_COUNT; i++ ) + { + dwParam = (int) i; + //Create thread + hThread[i] = CreateThread( + NULL, /* no security attributes */ + 0, /* use default stack size */ + (LPTHREAD_START_ROUTINE)Run_Thread,/* thread function */ + (LPVOID)dwParam, /* argument to thread function */ + 0, /* use default creation flags */ + &threadId[i] /* returns the thread identifier*/ + ); + + + if(hThread[i] == NULL) + { + Fail("Create Thread failed for %d process, and GetLastError value is %d\n", USE_PROCESS_COUNT, GetLastError()); + } + + } + + if (!SetEvent(StartTestsEvHandle)) + { + Fail("Set Event for Start Tests failed for %d process, and GetLastError value is %d\n", USE_PROCESS_COUNT, GetLastError()); + } + /* Test running */ + returnCode = WaitForMultipleObjects( THREAD_COUNT, hThread, TRUE, INFINITE); + + if( WAIT_OBJECT_0 != returnCode ) + { + Trace("Wait for Object(s) for %d process returned %d, and GetLastError value is %d\n", USE_PROCESS_COUNT, returnCode, GetLastError()); + testStatus = FAIL; + } + + processStats.operationTime = GetTimeDiff(dwStartTime); + + /* Write to a file*/ + if(pFile!= NULL) + { + for( i = 0; i < THREAD_COUNT; i++ ) + { + buffer = (struct statistics *)resultBuffer->getResultBuffer(i); + returnCode = fprintf(pFile, "%d,%d,%d,%d,%lu,%d\n", buffer->processId, buffer->operationsFailed, buffer->operationsPassed, buffer->operationsTotal, buffer->operationTime, buffer->relationId ); + //Trace("Iteration %d over\n", i); + + } + } + if(fclose(pFile)) + { + Trace("Error: fclose failed for pFile\n"); + testStatus = FAIL; + } + + fprintf(pProcessFile, "%d,%d,%d\n", USE_PROCESS_COUNT, processStats.operationTime, processStats.relationId ); + if(fclose(pProcessFile)) + { + Trace("Error: fclose failed for pProcessFile at Process %d\n", USE_PROCESS_COUNT); + testStatus = FAIL; + } + + /* Logging for the test case over, clean up the handles */ + +// Trace("Test Thread %d done\n", USE_PROCESS_COUNT); + /* Clean Up */ + for( i = 0; i < THREAD_COUNT; i++ ) + { + if(!CloseHandle(hThread[i]) ) + { + Trace("Error:%d: CloseHandle failed for Process [%d] hThread[%d]\n", GetLastError(), USE_PROCESS_COUNT, i); + testStatus = FAIL; + } + } + + if(!CloseHandle(StartTestsEvHandle)) + { + Trace("Error:%d: CloseHandle failed for Process [%d] StartTestsEvHandle\n", GetLastError(), USE_PROCESS_COUNT); + testStatus = FAIL; + } + + if(!CloseHandle(hEventHandle)) + { + Trace("Error:%d: CloseHandle failed for Process [%d] hEventHandle\n", GetLastError(), USE_PROCESS_COUNT); + testStatus = FAIL; + } + + PAL_Terminate(); + return testStatus; + +} + +void PALAPI Run_Thread (LPVOID lpParam) +{ + unsigned int i = 0; + DWORD dwWaitResult; + + struct statistics stats; + DWORD dwStartTime; + + stats.relationId = RELATION_ID; + stats.processId = USE_PROCESS_COUNT; + stats.operationsFailed = 0; + stats.operationsPassed = 0; + stats.operationsTotal = 0; + stats.operationTime = 0; + + int Id=(int)lpParam; + + dwWaitResult = WaitForSingleObject( + StartTestsEvHandle, // handle to start test handle + TIMEOUT); + + if(dwWaitResult != WAIT_OBJECT_0) + { + Fail("Error while waiting for StartTest Event@ thread %d, RC is %d, Error is %d\n", Id, dwWaitResult, GetLastError()); + } + + dwStartTime = GetTickCount(); + + for( i = 0; i < REPEAT_COUNT; i++ ) + { + dwWaitResult = WaitForSingleObject( + hEventHandle, // handle to Event + TIMEOUT); + + if(dwWaitResult != WAIT_OBJECT_0) + { +// Trace("Error while waiting for onject @ thread %d, # iter %d, RC is %d, Error is %d\n", Id, i, dwWaitResult, GetLastError()); + stats.operationsFailed += 1; + stats.operationsTotal += 1; + testStatus = FAIL; + continue; + } + + if (! SetEvent(hEventHandle)) + { + // Deal with error. +// Trace("Error while setting Event @ thread %d # iter %d\n", Id, i); + stats.operationsFailed += 1; + stats.operationsTotal += 1; + // Do we need to have while true loop to attempt to set event? + testStatus = FAIL; + continue; + } + + stats.operationsTotal += 1; + stats.operationsPassed += 1; +// Trace("Successs while setting Event @ iteration %d -> thread %d -> Process %d\n", i, Id, USE_PROCESS_COUNT); + + } + + stats.operationTime = GetTimeDiff(dwStartTime); + if(resultBuffer->LogResult(Id, (char *)&stats)) + { + Fail("Error:%d: while writing to shared memory, Thread Id is[%d] and Process id is [%d]\n", GetLastError(), Id, USE_PROCESS_COUNT); + } + //Trace("Thread %d over for process %d\n", Id, USE_PROCESS_COUNT); +} diff --git a/src/pal/tests/palsuite/composite/object_management/event/nonshared/main.c b/src/pal/tests/palsuite/composite/object_management/event/nonshared/main.c new file mode 100644 index 0000000000..7b61e91737 --- /dev/null +++ b/src/pal/tests/palsuite/composite/object_management/event/nonshared/main.c @@ -0,0 +1,228 @@ +// 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 Code: main.c and event.c +** main.c creates process and waits for all processes to get over +** event.c creates a event and then calls threads which will contend for the event +** +** This test is for Object Management Test case for event where Object type is not shareable. +** Algorithm +** o Create PROCESS_COUNT processes. +** o Main Thread of each process creates OBJECT_TYPE Object +** +** Author: ShamitP +**============================================================ +*/ + +#include <palsuite.h> +#include "resulttime.h" + +/* Test Input Variables */ +unsigned int PROCESS_COUNT = 10; +unsigned int THREAD_COUNT = 20; +unsigned int REPEAT_COUNT = 20000; +unsigned int RELATION_ID = 1001; + + +struct TestStats{ + DWORD operationTime; + unsigned int relationId; + unsigned int processCount; + unsigned int threadCount; + unsigned int repeatCount; + char* buildNumber; + +}; + + +int GetParameters( int argc, char **argv) +{ + if( (argc != 5) || ((argc == 1) && !strcmp(argv[1],"/?")) + || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H")) + { + printf("PAL -Composite Object Management event Test\n"); + printf("Usage:\n"); + printf("main\n\t[PROCESS_COUNT [greater than 1] \n"); + printf("\t[THREAD_COUNT [greater than 1] \n"); + printf("\t[REPEAT_COUNT [greater than 1]\n"); + printf("\t[RELATION_ID [greater than or Equal to 1]\n"); + return -1; + } + + PROCESS_COUNT = atoi(argv[1]); + if( (PROCESS_COUNT < 1) || (PROCESS_COUNT > MAXIMUM_WAIT_OBJECTS) ) + { + printf("\nMain Process:Invalid PROCESS_COUNT number, Pass greater than 1 and less than PROCESS_COUNT %d\n", MAXIMUM_WAIT_OBJECTS); + return -1; + } + + THREAD_COUNT = atoi(argv[2]); + if( (THREAD_COUNT < 1) || (THREAD_COUNT > MAXIMUM_WAIT_OBJECTS) ) + { + printf("\nInvalid THREAD_COUNT number, Pass greater than 1 and less than %d\n", MAXIMUM_WAIT_OBJECTS); + return -1; + } + + REPEAT_COUNT = atoi(argv[3]); + if( REPEAT_COUNT < 1) + { + printf("\nMain Process:Invalid REPEAT_COUNT number, Pass greater than 1\n"); + return -1; + } + + RELATION_ID = atoi(argv[4]); + if( RELATION_ID < 1) + { + printf("\nMain Process:Invalid RELATION_ID number, Pass greater than 1\n"); + return -1; + } + + + return 0; +} + + int __cdecl main(INT argc, CHAR **argv) +{ + unsigned int i = 0; + HANDLE hProcess[MAXIMUM_WAIT_OBJECTS]; + + STARTUPINFO si[MAXIMUM_WAIT_OBJECTS]; + PROCESS_INFORMATION pi[MAXIMUM_WAIT_OBJECTS]; + + char lpCommandLine[MAX_LONGPATH] = ""; + const char *ObjName = "Event"; + + int returnCode = 0; + DWORD processReturnCode = 0; + int testReturnCode = PASS; + + char fileName[MAX_LONGPATH]; + FILE *pFile = NULL; + DWORD dwStartTime = 0; + struct TestStats testStats; + + if(0 != (PAL_Initialize(argc, argv))) + { + return ( FAIL ); + } + + if(GetParameters(argc, argv)) + { + Fail("Error in obtaining the parameters\n"); + } + + /* Register the start time */ + dwStartTime = GetTickCount(); + testStats.relationId = RELATION_ID; + testStats.processCount = PROCESS_COUNT; + testStats.threadCount = THREAD_COUNT; + testStats.repeatCount = REPEAT_COUNT; + testStats.buildNumber = getBuildNumber(); + + + _snprintf(fileName, MAX_LONGPATH, "main_event_%d_.txt", RELATION_ID); + pFile = fopen(fileName, "w+"); + if(pFile == NULL) + { + Fail("Error in opening main file for write\n"); + } + + for( i = 0; i < PROCESS_COUNT; i++ ) + { + + ZeroMemory( lpCommandLine, MAX_PATH ); + if ( _snprintf( lpCommandLine, MAX_LONGPATH-1, "event %d %d %d %d", i, THREAD_COUNT, REPEAT_COUNT, RELATION_ID) < 0 ) + { + Fail ("Error: Insufficient Event name string length for %s for iteration [%d]\n", ObjName, i); + } + + /* Zero the data structure space */ + ZeroMemory ( &pi[i], sizeof(pi[i]) ); + ZeroMemory ( &si[i], sizeof(si[i]) ); + + /* Set the process flags and standard io handles */ + si[i].cb = sizeof(si[i]); + + //Create Process + if(!CreateProcess( NULL, /* lpApplicationName*/ + lpCommandLine, /* lpCommandLine */ + NULL, /* lpProcessAttributes */ + NULL, /* lpThreadAttributes */ + TRUE, /* bInheritHandles */ + 0, /* dwCreationFlags, */ + NULL, /* lpEnvironment */ + NULL, /* pCurrentDirectory */ + &si[i], /* lpStartupInfo */ + &pi[i] /* lpProcessInformation */ + )) + { + Fail("Process Not created for [%d], the error code is [%d]\n", i, GetLastError()); + } + else + { + hProcess[i] = pi[i].hProcess; + //Trace("Process created for [%d]\n", i); + + } + + } + + returnCode = WaitForMultipleObjects( PROCESS_COUNT, hProcess, TRUE, INFINITE); + if( WAIT_OBJECT_0 != returnCode ) + { + Trace("Wait for Object(s) @ Main thread for %d processes returned %d, and GetLastError value is %d\n", PROCESS_COUNT, returnCode, GetLastError()); + testReturnCode = FAIL; + } + + for( i = 0; i < PROCESS_COUNT; i++ ) + { + /* check the exit code from the process */ + if( ! GetExitCodeProcess( pi[i].hProcess, &processReturnCode ) ) + { + Trace( "GetExitCodeProcess call failed for iteration %d with error code %u\n", + i, GetLastError() ); + + testReturnCode = FAIL; + } + + if(processReturnCode == FAIL) + { + Trace( "Process [%d] failed and returned FAIL\n", i); + testReturnCode = FAIL; + } + + if(!CloseHandle(pi[i].hThread)) + { + Trace("Error:%d: CloseHandle failed for Process [%d] hThread\n", GetLastError(), i); + testReturnCode = FAIL; + } + + if(!CloseHandle(pi[i].hProcess) ) + { + Trace("Error:%d: CloseHandle failed for Process [%d] hProcess\n", GetLastError(), i); + testReturnCode = FAIL; + } + } + + testStats.operationTime = GetTimeDiff(dwStartTime); + fprintf(pFile, "%d,%d,%d,%d,%d,%s\n", testStats.operationTime, testStats.relationId, testStats.processCount, testStats.threadCount, testStats.repeatCount, testStats.buildNumber); + if(fclose(pFile)) + { + Trace("Error: fclose failed for pFile\n"); + testReturnCode = FAIL; + } + + if( testReturnCode == PASS) + { + Trace("Test Passed\n"); + } + else + { + Trace("Test Failed\n"); + } + PAL_Terminate(); + return testReturnCode; +} diff --git a/src/pal/tests/palsuite/composite/object_management/event/shared/CMakeLists.txt b/src/pal/tests/palsuite/composite/object_management/event/shared/CMakeLists.txt new file mode 100644 index 0000000000..d326e3a42b --- /dev/null +++ b/src/pal/tests/palsuite/composite/object_management/event/shared/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(SOURCES + event.c + main.c +) + +add_executable(paltest_event_shared + ${SOURCES} +) + +add_dependencies(paltest_event_shared coreclrpal) + +target_link_libraries(paltest_event_shared + pthread + rt + m + coreclrpal +) diff --git a/src/pal/tests/palsuite/composite/object_management/event/shared/event.c b/src/pal/tests/palsuite/composite/object_management/event/shared/event.c new file mode 100644 index 0000000000..83d5fce27e --- /dev/null +++ b/src/pal/tests/palsuite/composite/object_management/event/shared/event.c @@ -0,0 +1,373 @@ +// 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 Code: main.c and event.c +** main.c creates process and waits for all processes to get over +** event.c creates a event and then calls threads which will contend for the event +** +** This test is for Object Management Test case for event where Object type is shareable. +** Algorithm +** o Main Process Creates OBJECT_TYPE Object +** o Create PROCESS_COUNT processes aware of the Shared Object +** +** Author: ShamitP +** Author: ShamitP +** +** +**============================================================ +*/ + +#include <palsuite.h> +#include "resultbuffer.h" +#include "resulttime.h" + +#define TIMEOUT 5000 +/* Test Input Variables */ +unsigned int USE_PROCESS_COUNT = 0; +unsigned int THREAD_COUNT = 0; +unsigned int REPEAT_COUNT = 0; +unsigned int RELATION_ID = 0; + +/* Capture statistics at per thread basis */ +struct statistics{ + unsigned int processId; + unsigned int operationsFailed; + unsigned int operationsPassed; + unsigned int operationsTotal; + DWORD operationTime; + unsigned int relationId; +}; + +struct ProcessStats{ + unsigned int processId; + DWORD operationTime; + unsigned int relationId; +}; + +HANDLE StartTestsEvHandle = NULL; +HANDLE hEventHandle = NULL; + +/* Results Buffer */ +ResultBuffer *resultBuffer= NULL; + +int testStatus; + +const char sTmpEventName[MAX_PATH] = "StartTestEvent"; +char objectSuffix[MAX_PATH]; + +void PALAPI Run_Thread(LPVOID lpParam); + +int GetParameters( int argc, char **argv) +{ + if( (!((argc == 5) || (argc == 6) ) )|| ((argc == 1) && !strcmp(argv[1],"/?")) + || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H")) + { + printf("PAL -Composite Object Management event Test\n"); + printf("Usage:\n"); + printf("main\n\t[USE_PROCESS_COUNT (greater than 1)] \n"); + printf("\t[THREAD_COUNT (greater than 1)] \n"); + printf("\t[REPEAT_COUNT (greater than 1)]\n"); + printf("\t[RELATION_ID [greater than or equal to 1]\n"); + printf("\t[Object Name Suffix]\n"); + + return -1; + } + + // Trace("Args 1 is [%s], Arg 2 is [%s], Arg 3 is [%s]\n", argv[1], argv[2], argv[3]); + + USE_PROCESS_COUNT = atoi(argv[1]); + if( USE_PROCESS_COUNT < 0) + { + printf("\nInvalid USE_PROCESS_COUNT number, Pass greater than 1\n"); + return -1; + } + + THREAD_COUNT = atoi(argv[2]); + if( (THREAD_COUNT < 1) || (THREAD_COUNT > MAXIMUM_WAIT_OBJECTS) ) + { + printf("\nInvalid THREAD_COUNT number, Pass greater than 1 and less than %d\n", MAXIMUM_WAIT_OBJECTS); + return -1; + } + + REPEAT_COUNT = atoi(argv[3]); + if( REPEAT_COUNT < 1) + { + printf("\nInvalid REPEAT_COUNT number, Pass greater than 1\n"); + return -1; + } + + RELATION_ID = atoi(argv[4]); + if( RELATION_ID < 1) + { + printf("\nMain Process:Invalid RELATION_ID number, Pass greater than 1\n"); + return -1; + } + + if(argc == 6) + { + strncpy(objectSuffix, argv[5], MAX_PATH-1); + } + + return 0; +} + + int __cdecl main(INT argc, CHAR **argv) +{ + unsigned int i = 0; + HANDLE hThread[MAXIMUM_WAIT_OBJECTS]; + DWORD threadId[MAXIMUM_WAIT_OBJECTS]; + + WCHAR *wcObjName = NULL; + + char ObjName[MAX_PATH] = "SHARED_EVENT"; + DWORD dwParam = 0; + + int returnCode = 0; + + /* Variables to capture the file name and the file pointer at thread level*/ + char fileName[MAX_PATH]; + FILE *pFile = NULL; + struct statistics* buffer = NULL; + int statisticsSize = 0; + + /* Variables to capture the file name and the file pointer at process level*/ + char processFileName[MAX_PATH]; + FILE *pProcessFile = NULL; + struct ProcessStats processStats; + DWORD dwStartTime; + + testStatus = PASS; + + if(0 != (PAL_Initialize(argc, argv))) + { + return ( FAIL ); + } + + ZeroMemory( objectSuffix, MAX_PATH ); + + if(GetParameters(argc, argv)) + { + Fail("Error in obtaining the parameters\n"); + } +// Trace("Process created, value of process count is [%d]\n", USE_PROCESS_COUNT); + + if(argc == 5) + { + strncat(ObjName, objectSuffix, MAX_PATH - (sizeof(ObjName) + 1) ); + } + + /* Register the start time */ + dwStartTime = GetTickCount(); + processStats.relationId = RELATION_ID; + processStats.processId = USE_PROCESS_COUNT; + + _snprintf(processFileName, MAX_PATH, "%d_process_event_%d_.txt", USE_PROCESS_COUNT, RELATION_ID); + pProcessFile = fopen(processFileName, "w+"); + if(pProcessFile == NULL) + { + Fail("Error:%d: in opening Process File for write for process [%d]\n", GetLastError(), USE_PROCESS_COUNT); + } + + statisticsSize = sizeof(struct statistics); + + _snprintf(fileName, MAX_PATH, "%d_thread_event_%d_.txt", USE_PROCESS_COUNT, RELATION_ID); + pFile = fopen(fileName, "w+"); + + if(pFile == NULL) + { + Fail("Error:%d: in opening thread file for write for process [%d]\n", GetLastError(), USE_PROCESS_COUNT); + } + // For each thread we will log operations failed (int), passed (int), total (int) + // and number of ticks (DWORD) for the operations + resultBuffer = new ResultBuffer( THREAD_COUNT, statisticsSize); + + wcObjName = convert(ObjName); + + StartTestsEvHandle = CreateEvent( NULL, /* lpEventAttributes*/ + TRUE, /* bManualReset */ + FALSE, /* bInitialState */ + NULL); /* name of Event */ + + if( StartTestsEvHandle == NULL ) + { + Fail("Error:%d: Unexpected failure " + "to create %s Event for process count %d\n", GetLastError(), sTmpEventName, USE_PROCESS_COUNT ); + + } + + /* Create StartTest Event */ + + hEventHandle = OpenEventW( + EVENT_ALL_ACCESS, /* lpEventAttributes, inheritable to child processes*/ + FALSE, /* bAutomaticReset */ + wcObjName + ); + + if( hEventHandle == NULL) + { + Fail("Unable to create Event handle for process id [%d], returned error [%d]\n", i, GetLastError()); + } + /* We already assume that the Event was created previously*/ + + for( i = 0; i < THREAD_COUNT; i++ ) + { + dwParam = (int) i; + //Create thread + hThread[i] = CreateThread( + NULL, /* no security attributes */ + 0, /* use default stack size */ + (LPTHREAD_START_ROUTINE)Run_Thread,/* thread function */ + (LPVOID)dwParam, /* argument to thread function */ + 0, /* use default creation flags */ + &threadId[i] /* returns the thread identifier*/ + ); + + if(hThread[i] == NULL) + { + Fail("Create Thread failed for %d process, and GetLastError value is %d\n", USE_PROCESS_COUNT, GetLastError()); + } + + } + + if (!SetEvent(StartTestsEvHandle)) + { + Fail("Set Event for Start Tests failed for %d process, and GetLastError value is %d\n", USE_PROCESS_COUNT, GetLastError()); + } + + /* Test running */ + returnCode = WaitForMultipleObjects( THREAD_COUNT, hThread, TRUE, INFINITE); + + if( WAIT_OBJECT_0 != returnCode ) + { + Trace("Wait for Object(s) for %d process returned %d, and GetLastError value is %d\n", USE_PROCESS_COUNT, returnCode, GetLastError()); + testStatus = FAIL; + } + + processStats.operationTime = GetTimeDiff(dwStartTime); + + /* Write to a file*/ + if(pFile!= NULL) + { + for( i = 0; i < THREAD_COUNT; i++ ) + { + buffer = (struct statistics *)resultBuffer->getResultBuffer(i); + returnCode = fprintf(pFile, "%d,%d,%d,%d,%lu,%d\n", buffer->processId, buffer->operationsFailed, buffer->operationsPassed, buffer->operationsTotal, buffer->operationTime, buffer->relationId ); +// Trace("Iteration %d over\n", i); + + } + } + + if(fclose(pFile)) + { + Trace("Error: fclose failed for pFile at Process %d\n", USE_PROCESS_COUNT); + testStatus = FAIL; + } + + fprintf(pProcessFile, "%d,%d,%d\n", USE_PROCESS_COUNT, processStats.operationTime, processStats.relationId ); + if(fclose(pProcessFile)) + { + Trace("Error: fclose failed for pProcessFile at Process %d\n", USE_PROCESS_COUNT); + testStatus = FAIL; + } + /* Logging for the test case over, clean up the handles */ + +// Trace("Test Thread %d done\n", USE_PROCESS_COUNT); + + for( i = 0; i < THREAD_COUNT; i++ ) + { + if(!CloseHandle(hThread[i]) ) + { + Trace("Error:%d: CloseHandle failed for Process [%d] hThread[%d]\n", GetLastError(), USE_PROCESS_COUNT, i); + testStatus = FAIL; + } + } + + if(!CloseHandle(StartTestsEvHandle)) + { + Trace("Error:%d: CloseHandle failed for Process [%d] StartTestsEvHandle\n", GetLastError(), USE_PROCESS_COUNT); + testStatus = FAIL; + } + + if(!CloseHandle(hEventHandle)) + { + Trace("Error:%d: CloseHandle failed for Process [%d] hEventHandle\n", GetLastError(), USE_PROCESS_COUNT); + testStatus = FAIL; + } + + free(wcObjName); + PAL_Terminate(); + return testStatus; +} + +void PALAPI Run_Thread (LPVOID lpParam) +{ + unsigned int i = 0; + DWORD dwWaitResult; + + struct statistics stats; + DWORD dwStartTime; + + stats.relationId = RELATION_ID; + stats.processId = USE_PROCESS_COUNT; + stats.operationsFailed = 0; + stats.operationsPassed = 0; + stats.operationsTotal = 0; + stats.operationTime = 0; + + int Id=(int)lpParam; + + dwWaitResult = WaitForSingleObject( + StartTestsEvHandle, // handle to start test handle + TIMEOUT); + + if(dwWaitResult != WAIT_OBJECT_0) + { + Trace("Error:%d: while waiting for StartTest Event@ thread %d\n", GetLastError(), Id); + testStatus = FAIL; + } + + dwStartTime = GetTickCount(); + + for( i = 0; i < REPEAT_COUNT; i++ ) + { + dwWaitResult = WaitForSingleObject( + hEventHandle, // handle to Event + TIMEOUT); + + if(dwWaitResult != WAIT_OBJECT_0) + { + //Trace("Error:%d: while waiting for onject @ thread %d, # iter %d\n", GetLastError(), Id, i); + stats.operationsFailed += 1; + stats.operationsTotal += 1; + testStatus = FAIL; + continue; + } + + if (! SetEvent(hEventHandle)) + { + // Deal with error. +// Trace("Error while setting Event @ thread %d # iter %d\n", Id, i); + stats.operationsFailed += 1; + stats.operationsTotal += 1; + // do we need to have while true loop to attempt to set event...? + testStatus = FAIL; + continue; + } + + stats.operationsTotal += 1; + stats.operationsPassed += 1; + // Trace("Successs while setting Event @ iteration %d -> thread %d -> Process %d for handle %d\n", i, Id, USE_PROCESS_COUNT, hEventHandle); + + } + + stats.operationTime = GetTimeDiff(dwStartTime); + //Trace("OPeration time is %d", stats.operationTime ); + if(resultBuffer->LogResult(Id, (char *)&stats)) + { + Fail("Error:%d: while writing to shared memory, Thread Id is[%d] and Process id is [%d]\n", GetLastError(), Id, USE_PROCESS_COUNT); + } + //Trace("Thread %d over for process %d\n", Id, USE_PROCESS_COUNT); +} diff --git a/src/pal/tests/palsuite/composite/object_management/event/shared/main.c b/src/pal/tests/palsuite/composite/object_management/event/shared/main.c new file mode 100644 index 0000000000..c4a4067b5d --- /dev/null +++ b/src/pal/tests/palsuite/composite/object_management/event/shared/main.c @@ -0,0 +1,265 @@ +// 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 Code: main.c and event.c +** main.c creates process and waits for all processes to get over +** event.c creates a event and then calls threads which will contend for the event +** +** This test is for Object Management Test case for event where Object type is shareable. +** Algorithm +** o Main Process Creates OBJECT_TYPE Object +** o Create PROCESS_COUNT processes aware of the Shared Object +** +** Author: ShamitP +** +** +**============================================================ +*/ +#include <palsuite.h> +#include "resulttime.h" + +/* Test Input Variables */ +unsigned int PROCESS_COUNT = 2; +unsigned int THREAD_COUNT = 20; +unsigned int REPEAT_COUNT = 200; +unsigned int RELATION_ID = 1001; + + +char objectSuffix[MAX_PATH_FNAME]; + +struct TestStats{ + DWORD operationTime; + unsigned int relationId; + unsigned int processCount; + unsigned int threadCount; + unsigned int repeatCount; + char* buildNumber; + +}; + +int GetParameters( int argc, char **argv) +{ + if( (!((argc == 5) || (argc == 6) ) )|| ((argc == 1) && !strcmp(argv[1],"/?")) + || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H")) + { + printf("PAL -Composite Object Management event Test\n"); + printf("Usage:\n"); + printf("main\n\t[PROCESS_COUNT (greater than 1)] \n"); + printf("\t[THREAD_COUNT (greater than 1)] \n"); + printf("\t[REPEAT_COUNT (greater than 1)]\n"); + printf("\t[RELATION_ID [greater than or equal to 1]\n"); + printf("\t[Object Name Suffix]\n"); + return -1; + } + + PROCESS_COUNT = atoi(argv[1]); + if( (PROCESS_COUNT < 1) || (PROCESS_COUNT > MAXIMUM_WAIT_OBJECTS) ) + { + printf("\nMain Process:Invalid PROCESS_COUNT number, Pass greater than 1 and less than PROCESS_COUNT %d\n", MAXIMUM_WAIT_OBJECTS); + return -1; + } + + THREAD_COUNT = atoi(argv[2]); + if( (THREAD_COUNT < 1) || (THREAD_COUNT > MAXIMUM_WAIT_OBJECTS) ) + { + printf("\nInvalid THREAD_COUNT number, Pass greater than 1 and less than %d\n", MAXIMUM_WAIT_OBJECTS); + return -1; + } + + REPEAT_COUNT = atoi(argv[3]); + if( REPEAT_COUNT < 1) + { + printf("\nMain Process:Invalid REPEAT_COUNT number, Pass greater than 1\n"); + return -1; + } + + RELATION_ID = atoi(argv[4]); + if( RELATION_ID < 1) + { + printf("\nMain Process:Invalid RELATION_ID number, Pass greater than 1\n"); + return -1; + } + + + if(argc == 6) + { + strncpy(objectSuffix, argv[5], MAX_PATH_FNAME-1); + } + + return 0; +} + + int __cdecl main(INT argc, CHAR **argv) +{ + unsigned int i = 0; + HANDLE hProcess[MAXIMUM_WAIT_OBJECTS]; + HANDLE hEventHandle; + + STARTUPINFO si[MAXIMUM_WAIT_OBJECTS]; + PROCESS_INFORMATION pi[MAXIMUM_WAIT_OBJECTS]; + + char lpCommandLine[MAX_LONGPATH] = ""; + char ObjName[MAX_PATH_FNAME] = "SHARED_EVENT"; + + int returnCode = 0; + DWORD processReturnCode = 0; + int testReturnCode = PASS; + + char fileName[MAX_PATH_FNAME]; + FILE *pFile = NULL; + DWORD dwStartTime; + struct TestStats testStats; + + if(0 != (PAL_Initialize(argc, argv))) + { + return ( FAIL ); + } + + ZeroMemory( objectSuffix, MAX_PATH_FNAME ); + + if(GetParameters(argc, argv)) + { + Fail("Error in obtaining the parameters\n"); + } + + if(argc == 5) + { + strncat(ObjName, objectSuffix, MAX_PATH_FNAME - (sizeof(ObjName) + 1) ); + } + + /* Register the start time */ + dwStartTime = GetTickCount(); + testStats.relationId = RELATION_ID; + testStats.processCount = PROCESS_COUNT; + testStats.threadCount = THREAD_COUNT; + testStats.repeatCount = REPEAT_COUNT; + testStats.buildNumber = getBuildNumber(); + + + _snprintf(fileName, MAX_PATH_FNAME, "main_event_%d_.txt", RELATION_ID); + pFile = fopen(fileName, "w+"); + if(pFile == NULL) + { + Fail("Error in opening main file for write\n"); + } + + hEventHandle = CreateEvent( + NULL, /* lpEventAttributes, inheritable to child processes*/ + TRUE, /* bAutomaticReset */ + TRUE, /* bInitialState */ + ObjName + ); + + if( hEventHandle == NULL) + { + Fail("Unable to create Event handle, returned error [%d]\n", GetLastError()); + } + + for( i = 0; i < PROCESS_COUNT; i++ ) + { + + ZeroMemory( lpCommandLine, MAX_PATH_FNAME ); + if ( _snprintf( lpCommandLine, MAX_PATH_FNAME-1, "event %d %d %d %d %s", i, THREAD_COUNT, REPEAT_COUNT, RELATION_ID, objectSuffix) < 0 ) + { + Fail ("Error: Insufficient Event name string length for %s for iteration [%d]\n", ObjName, i); + } + + /* Zero the data structure space */ + ZeroMemory ( &pi[i], sizeof(pi[i]) ); + ZeroMemory ( &si[i], sizeof(si[i]) ); + + /* Set the process flags and standard io handles */ + si[i].cb = sizeof(si[i]); + + if(!CreateProcess( NULL, /* lpApplicationName*/ + lpCommandLine, /* lpCommandLine */ + NULL, /* lpProcessAttributes */ + NULL, /* lpThreadAttributes */ + TRUE, /* bInheritHandles */ + 0, /* dwCreationFlags, */ + NULL, /* lpEnvironment */ + NULL, /* pCurrentDirectory */ + &si[i], /* lpStartupInfo */ + &pi[i] /* lpProcessInformation */ + )) + { + Fail("Process Not created for [%d], the error code is [%d]\n", i, GetLastError()); + } + else + { + hProcess[i] = pi[i].hProcess; +// Trace("Process created for [%d]\n", i); + + } + + //Create Process + + } + + returnCode = WaitForMultipleObjects( PROCESS_COUNT, hProcess, TRUE, INFINITE); + if( WAIT_OBJECT_0 != returnCode ) + { + Trace("Wait for Object(s) @ Main thread for %d processes returned %d, and GetLastError value is %d\n", PROCESS_COUNT, returnCode, GetLastError()); + testReturnCode = FAIL; + } + +// Trace("Test over\n"); + for( i = 0; i < PROCESS_COUNT; i++ ) + { + /* check the exit code from the process */ + if( ! GetExitCodeProcess( pi[i].hProcess, &processReturnCode ) ) + { + Trace( "GetExitCodeProcess call failed for iteration %d with error code %u\n", + i, GetLastError() ); + + testReturnCode = FAIL; + } + + if(processReturnCode == FAIL) + { + Trace( "Process [%d] failed and returned FAIL\n", i); + testReturnCode = FAIL; + } + + if(!CloseHandle(pi[i].hThread)) + { + Trace("Error:%d: CloseHandle failed for Process [%d] hThread\n", GetLastError(), i); + testReturnCode = FAIL; + } + + if(!CloseHandle(pi[i].hProcess) ) + { + Trace("Error:%d: CloseHandle failed for Process [%d] hProcess\n", GetLastError(), i); + testReturnCode = FAIL; + } + } + + testStats.operationTime = GetTimeDiff(dwStartTime); + fprintf(pFile, "%d,%d,%d,%d,%d,%s\n", testStats.operationTime, testStats.relationId, testStats.processCount, testStats.threadCount, testStats.repeatCount, testStats.buildNumber); + if(fclose(pFile)) + { + Trace("Error: fclose failed for pFile\n"); + testReturnCode = FAIL; + } + + if(!CloseHandle(hEventHandle)) + { + Trace("Error:%d: CloseHandle failed for hEventHandle\n", GetLastError()); + testReturnCode = FAIL; + } + + if( testReturnCode == PASS) + { + Trace("Test Passed\n"); + } + else + { + Trace("Test Failed\n"); + } + + PAL_Terminate(); + return testReturnCode; +} diff --git a/src/pal/tests/palsuite/composite/object_management/mutex/CMakeLists.txt b/src/pal/tests/palsuite/composite/object_management/mutex/CMakeLists.txt new file mode 100644 index 0000000000..2534564f95 --- /dev/null +++ b/src/pal/tests/palsuite/composite/object_management/mutex/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +add_subdirectory(nonshared) +add_subdirectory(shared) + diff --git a/src/pal/tests/palsuite/composite/object_management/mutex/nonshared/CMakeLists.txt b/src/pal/tests/palsuite/composite/object_management/mutex/nonshared/CMakeLists.txt new file mode 100644 index 0000000000..7859cd4653 --- /dev/null +++ b/src/pal/tests/palsuite/composite/object_management/mutex/nonshared/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(SOURCES + main.c + mutex.c +) + +add_executable(paltest_mutex_nonshared + ${SOURCES} +) + +add_dependencies(paltest_mutex_nonshared coreclrpal) + +target_link_libraries(paltest_mutex_nonshared + pthread + rt + m + coreclrpal +) diff --git a/src/pal/tests/palsuite/composite/object_management/mutex/nonshared/main.c b/src/pal/tests/palsuite/composite/object_management/mutex/nonshared/main.c new file mode 100644 index 0000000000..80f31aad6e --- /dev/null +++ b/src/pal/tests/palsuite/composite/object_management/mutex/nonshared/main.c @@ -0,0 +1,230 @@ +// 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 Code: main.c and mutex.c +** main.c creates process and waits for all processes to get over +** mutex.c creates a mutex and then calls threads which will contend for the mutex +** +** This test is for Object Management Test case for Mutex where Object type is not shareable. +** Algorithm +** o Create PROCESS_COUNT processes. +** o Main Thread of each process creates OBJECT_TYPE Object +** +** Author: ShamitP +**============================================================ +*/ + +#include <palsuite.h> +#include "resulttime.h" + +/* Test Input Variables */ +unsigned int PROCESS_COUNT = 2; +unsigned int THREAD_COUNT = 20; +unsigned int REPEAT_COUNT = 4000; +unsigned int RELATION_ID = 1001; + + +struct TestStats{ + DWORD operationTime; + unsigned int relationId; + unsigned int processCount; + unsigned int threadCount; + unsigned int repeatCount; + char* buildNumber; + +}; + +int GetParameters( int argc, char **argv) +{ + if( (argc != 5) || ((argc == 1) && !strcmp(argv[1],"/?")) + || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H")) + { + printf("PAL -Composite Object Management Mutex Test\n"); + printf("Usage:\n"); + printf("main\n\t[PROCESS_COUNT [greater than 1] \n"); + printf("\t[THREAD_COUNT [greater than 1] \n"); + printf("\t[REPEAT_COUNT [greater than 1]\n"); + printf("\t[RELATION_ID [greater than 1]\n"); + + + return -1; + } + + PROCESS_COUNT = atoi(argv[1]); + if( (PROCESS_COUNT < 1) || (PROCESS_COUNT > MAXIMUM_WAIT_OBJECTS) ) + { + printf("\nMain Process:Invalid PROCESS_COUNT number, Pass greater than 1 and less than PROCESS_COUNT %d\n", MAXIMUM_WAIT_OBJECTS); + return -1; + } + + THREAD_COUNT = atoi(argv[2]); + if( (THREAD_COUNT < 1) || (THREAD_COUNT > MAXIMUM_WAIT_OBJECTS) ) + { + printf("\nInvalid THREAD_COUNT number, Pass greater than 1 and less than %d\n", MAXIMUM_WAIT_OBJECTS); + return -1; + } + + REPEAT_COUNT = atoi(argv[3]); + if( REPEAT_COUNT < 1) + { + printf("\nMain Process:Invalid REPEAT_COUNT number, Pass greater than 1\n"); + return -1; + } + + RELATION_ID = atoi(argv[4]); + if( RELATION_ID < 1) + { + printf("\nMain Process:Invalid RELATION_ID number, Pass greater than 1\n"); + return -1; + } + + return 0; +} + + int __cdecl main(INT argc, CHAR **argv) +{ + unsigned int i = 0; + HANDLE hProcess[MAXIMUM_WAIT_OBJECTS]; + HANDLE hMutexHandle[MAXIMUM_WAIT_OBJECTS]; + + STARTUPINFO si[MAXIMUM_WAIT_OBJECTS]; + PROCESS_INFORMATION pi[MAXIMUM_WAIT_OBJECTS]; + + const char *ObjName = "Mutex"; + char lpCommandLine[MAX_PATH] = ""; + + int returnCode = 0; + DWORD processReturnCode = 0; + int testReturnCode = PASS; + + char fileName[MAX_PATH]; + FILE *pFile = NULL; + DWORD dwStartTime; + struct TestStats testStats; + + if(0 != (PAL_Initialize(argc, argv))) + { + return ( FAIL ); + } + + if(GetParameters(argc, argv)) + { + Fail("Error in obtaining the parameters\n"); + } + + /* Register the start time */ + dwStartTime = GetTickCount(); + testStats.relationId = RELATION_ID; + testStats.processCount = PROCESS_COUNT; + testStats.threadCount = THREAD_COUNT; + testStats.repeatCount = REPEAT_COUNT; + testStats.buildNumber = getBuildNumber(); + + + _snprintf(fileName, MAX_PATH, "main_mutex_%d_.txt", RELATION_ID); + pFile = fopen(fileName, "w+"); + if(pFile == NULL) + { + Fail("Error in opening main file for write\n"); + } + + for( i = 0; i < PROCESS_COUNT; i++ ) + { + ZeroMemory( lpCommandLine, MAX_PATH ); + if ( _snprintf( lpCommandLine, MAX_PATH-1, "mutex %d %d %d %d", i, THREAD_COUNT, REPEAT_COUNT, RELATION_ID) < 0 ) + { + Fail("Error Insufficient mutex name string length for %s for iteration [%d]\n", ObjName, i); + } + + /* Zero the data structure space */ + ZeroMemory ( &pi[i], sizeof(pi[i]) ); + ZeroMemory ( &si[i], sizeof(si[i]) ); + + /* Set the process flags and standard io handles */ + si[i].cb = sizeof(si[i]); + + if(!CreateProcess( NULL, /* lpApplicationName*/ + lpCommandLine, /* lpCommandLine */ + NULL, /* lpProcessAttributes */ + NULL, /* lpThreadAttributes */ + TRUE, /* bInheritHandles */ + 0, /* dwCreationFlags, */ + NULL, /* lpEnvironment */ + NULL, /* pCurrentDirectory */ + &si[i], /* lpStartupInfo */ + &pi[i] /* lpProcessInformation */ + )) + { + Fail("Process Not created for [%d], the error code is [%d]\n", i, GetLastError()); + } + else + { + hProcess[i] = pi[i].hProcess; +// Trace("Process created for [%d]\n", i); + + } + + //Create Process + + } + + returnCode = WaitForMultipleObjects( PROCESS_COUNT, hProcess, TRUE, INFINITE); + if( WAIT_OBJECT_0 != returnCode ) + { + Trace("Wait for Object(s) @ Main thread for %d processes returned %d, and GetLastError value is %d\n", PROCESS_COUNT, returnCode, GetLastError()); + testReturnCode = FAIL; + } + + for( i = 0; i < PROCESS_COUNT; i++ ) + { + /* check the exit code from the process */ + if( ! GetExitCodeProcess( pi[i].hProcess, &processReturnCode ) ) + { + Trace( "GetExitCodeProcess call failed for iteration %d with error code %u\n", + i, GetLastError() ); + + testReturnCode = FAIL; + } + + if(processReturnCode == FAIL) + { + Trace( "Process [%d] failed and returned FAIL\n", i); + testReturnCode = FAIL; + } + + if(!CloseHandle(pi[i].hThread)) + { + Trace("Error:%d: CloseHandle failed for Process [%d] hThread\n", GetLastError(), i); + testReturnCode = FAIL; + } + + if(!CloseHandle(pi[i].hProcess) ) + { + Trace("Error:%d: CloseHandle failed for Process [%d] hProcess\n", GetLastError(), i); + testReturnCode = FAIL; + } + } + + testStats.operationTime = GetTimeDiff(dwStartTime); + fprintf(pFile, "%d,%d,%d,%d,%d,%s\n", testStats.operationTime, testStats.relationId, testStats.processCount, testStats.threadCount, testStats.repeatCount, testStats.buildNumber); + if(fclose(pFile)) + { + Trace("Error: fclose failed for pFile\n"); + testReturnCode = FAIL; + } + + if( testReturnCode == PASS) + { + Trace("Test Passed\n"); + } + else + { + Trace("Test Failed\n"); + } + + PAL_Terminate(); + return testReturnCode; +} diff --git a/src/pal/tests/palsuite/composite/object_management/mutex/nonshared/mutex.c b/src/pal/tests/palsuite/composite/object_management/mutex/nonshared/mutex.c new file mode 100644 index 0000000000..7f1f659f92 --- /dev/null +++ b/src/pal/tests/palsuite/composite/object_management/mutex/nonshared/mutex.c @@ -0,0 +1,340 @@ +// 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 Code: main.c and mutex.c +** main.c creates process and waits for all processes to get over +** mutex.c creates a mutex and then calls threads which will contend for the mutex +** +** This test is for Object Management Test case for Mutex where Object type is not shareable. +** Algorithm +** o Create PROCESS_COUNT processes. +** o Main Thread of each process creates OBJECT_TYPE Object +** +** Author: ShamitP +**============================================================ +*/ + +#include <palsuite.h> +#include "resultbuffer.h" +#include "resulttime.h" + +#define TIMEOUT 5000 +/* Test Input Variables */ +unsigned int USE_PROCESS_COUNT = 0; +unsigned int THREAD_COUNT = 0; +unsigned int REPEAT_COUNT = 0; +unsigned int RELATION_ID = 1001; + +/* Capture statistics at per thread basis */ +struct statistics{ + unsigned int processId; + unsigned int operationsFailed; + unsigned int operationsPassed; + unsigned int operationsTotal; + DWORD operationTime; + unsigned int relationId; +}; + +struct ProcessStats{ + unsigned int processId; + DWORD operationTime; + unsigned int relationId; +}; + +HANDLE StartTestsEvHandle = NULL; +HANDLE hMutexHandle = NULL; + +/* Results Buffer */ +ResultBuffer *resultBuffer = NULL; + +int testStatus; + +void PALAPI Run_Thread(LPVOID lpParam); + +int GetParameters( int argc, char **argv) +{ + if( (argc != 5) || ((argc == 1) && !strcmp(argv[1],"/?")) + || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H")) + { + printf("PAL -Composite Object Management Mutex Test\n"); + printf("Usage:\n"); + printf("mutex\n\t[USE_PROCESS_COUNT ( greater than 1] \n"); + printf("\t[THREAD_COUNT ( greater than 1] \n"); + printf("\t[REPEAT_COUNT ( greater than 1]\n"); + printf("\t[RELATION_ID [greater than 1]\n"); + return -1; + } + + // Trace("Args 1 is [%s], Arg 2 is [%s], Arg 3 is [%s]\n", argv[1], argv[2], argv[3]); + + USE_PROCESS_COUNT = atoi(argv[1]); + if( USE_PROCESS_COUNT < 0) + { + printf("\nInvalid USE_PROCESS_COUNT number, Pass greater than 1\n"); + return -1; + } + + THREAD_COUNT = atoi(argv[2]); + if( (THREAD_COUNT < 1) || (THREAD_COUNT > MAXIMUM_WAIT_OBJECTS) ) + { + printf("\nInvalid THREAD_COUNT number, Pass greater than 1 and less than %d\n", MAXIMUM_WAIT_OBJECTS); + return -1; + } + + REPEAT_COUNT = atoi(argv[3]); + if( REPEAT_COUNT < 1) + { + printf("\nInvalid REPEAT_COUNT number, Pass greater than 1\n"); + return -1; + } + + RELATION_ID = atoi(argv[4]); + if( RELATION_ID < 1) + { + printf("\nMain Process:Invalid RELATION_ID number, Pass greater than 1\n"); + return -1; + } + + return 0; +} + + int __cdecl main(INT argc, CHAR **argv) +{ + unsigned int i = 0; + HANDLE hThread[MAXIMUM_WAIT_OBJECTS]; + DWORD threadId[MAXIMUM_WAIT_OBJECTS]; + + const char sTmpEventName[MAX_PATH] = "StartTestEvent"; + + DWORD dwParam = 0; + + int returnCode = 0; + + /* Variables to capture the file name and the file pointer at thread level*/ + char fileName[MAX_PATH]; + FILE *pFile = NULL; + struct statistics* buffer = NULL; + int statisticsSize = 0; + + /* Variables to capture the file name and the file pointer at process level*/ + char processFileName[MAX_PATH]; + FILE *pProcessFile = NULL; + struct ProcessStats processStats; + DWORD dwStartTime; + + testStatus = PASS; + + if(0 != (PAL_Initialize(argc, argv))) + { + return ( FAIL ); + } + + if(GetParameters(argc, argv)) + { + Fail("Error in obtaining the parameters\n"); + } +// Trace("Process created, value of process count is [%d]\n", USE_PROCESS_COUNT); + + /* Register the start time */ + dwStartTime = GetTickCount(); + processStats.relationId = RELATION_ID; + processStats.processId = USE_PROCESS_COUNT; + + _snprintf(processFileName, MAX_PATH, "%d_process_mutex_%d_.txt", USE_PROCESS_COUNT,RELATION_ID); + pProcessFile = fopen(processFileName, "w+"); + if(pProcessFile == NULL) + { + Fail("Error in opening process File file for write for process [%d]\n", USE_PROCESS_COUNT); + } + + statisticsSize = sizeof(struct statistics); + + _snprintf(fileName, MAX_PATH, "%d_thread_mutex_%d_.txt", USE_PROCESS_COUNT, RELATION_ID); + pFile = fopen(fileName, "w+"); + if(pFile == NULL) + { + Fail("Error in opening file for write for process [%d]\n", USE_PROCESS_COUNT); + } + // For each thread we will log operations failed (int), passed (int), total (int) + // and number of ticks (DWORD) for the operations + resultBuffer = new ResultBuffer( THREAD_COUNT, statisticsSize); + + StartTestsEvHandle = CreateEvent( NULL, /* lpEventAttributes*/ + TRUE, /* bManualReset */ + FALSE, /* bInitialState */ + NULL + ); /* name of Event */ + + if( StartTestsEvHandle == NULL ) + { + Fail("Error:%d: Unexpected failure " + "to create %s Event for process count %d\n", GetLastError(), sTmpEventName, USE_PROCESS_COUNT ); + + } + + /* Create StartTest Event */ + + hMutexHandle = CreateMutex( + NULL, + FALSE, /* bInitialOwner, owns initially */ + NULL + ); + + if( hMutexHandle == NULL) + { + Fail("Unable to create Mutex handle for process id [%d], returned error [%d]\n", i, GetLastError()); + } + /* We already assume that the mutex was created previously*/ + + for( i = 0; i < THREAD_COUNT; i++ ) + { + dwParam = (int) i; + //Create thread + hThread[i] = CreateThread( + NULL, /* no security attributes */ + 0, /* use default stack size */ + (LPTHREAD_START_ROUTINE)Run_Thread,/* thread function */ + (LPVOID)dwParam, /* argument to thread function */ + 0, /* use default creation flags */ + &threadId[i] /* returns the thread identifier*/ + ); + + if(hThread[i] == NULL) + { + Fail("Create Thread failed for %d process, and GetLastError value is %d\n", USE_PROCESS_COUNT, GetLastError()); + } + + } + + if (!SetEvent(StartTestsEvHandle)) + { + Fail("Set Event for Start Tests failed for %d process, and GetLastError value is %d\n", USE_PROCESS_COUNT, GetLastError()); + } + + /* Test running */ + returnCode = WaitForMultipleObjects( THREAD_COUNT, hThread, TRUE, INFINITE); + + if( WAIT_OBJECT_0 != returnCode ) + { + Trace("Wait for Object(s) for %d process returned %d, and GetLastError value is %d\n", USE_PROCESS_COUNT, returnCode, GetLastError()); + testStatus = FAIL; + } + + processStats.operationTime = GetTimeDiff(dwStartTime); + + /* Write to a file*/ + if(pFile!= NULL) + { + for( i = 0; i < THREAD_COUNT; i++ ) + { + buffer = (struct statistics *)resultBuffer->getResultBuffer(i); + returnCode = fprintf(pFile, "%d,%d,%d,%d,%lu,%d\n", buffer->processId, buffer->operationsFailed, buffer->operationsPassed, buffer->operationsTotal, buffer->operationTime, buffer->relationId ); +// Trace("Iteration %d over\n", i); + + } + } + fclose(pFile); + + fprintf(pProcessFile, "%d,%d,%d\n", USE_PROCESS_COUNT, processStats.operationTime, processStats.relationId ); + fclose(pProcessFile); + + /* Logging for the test case over, clean up the handles */ + +// Trace("Test Thread %d done\n", USE_PROCESS_COUNT); + + + for( i = 0; i < THREAD_COUNT; i++ ) + { + if(!CloseHandle(hThread[i]) ) + { + Trace("Error:%d: CloseHandle failed for Process [%d] hThread[%d]\n", GetLastError(), USE_PROCESS_COUNT, i); + testStatus = FAIL; + } + } + + if(!CloseHandle(StartTestsEvHandle)) + { + Trace("Error:%d: CloseHandle failed for Process [%d] StartTestsEvHandle\n", GetLastError(), USE_PROCESS_COUNT); + testStatus = FAIL; + } + + if(!CloseHandle(hMutexHandle)) + { + Trace("Error:%d: CloseHandle failed for Process [%d] hMutexHandle\n", GetLastError(), USE_PROCESS_COUNT); + testStatus = FAIL; + } + + PAL_Terminate(); + return testStatus; +} + +void PALAPI Run_Thread (LPVOID lpParam) +{ + unsigned int i = 0; + DWORD dwWaitResult; + + struct statistics stats; + DWORD dwStartTime; + + stats.relationId = RELATION_ID; + stats.processId = USE_PROCESS_COUNT; + stats.operationsFailed = 0; + stats.operationsPassed = 0; + stats.operationsTotal = 0; + stats.operationTime = 0; + + int Id=(int)lpParam; + + dwWaitResult = WaitForSingleObject( + StartTestsEvHandle, // handle to mutex + TIMEOUT); + + if(dwWaitResult != WAIT_OBJECT_0) + { + Trace("Error while waiting for StartTest Event@ thread %d\n", Id); + testStatus = FAIL; + } + + dwStartTime = GetTickCount(); + + for( i = 0; i < REPEAT_COUNT; i++ ) + { + dwWaitResult = WaitForSingleObject( + hMutexHandle, // handle to mutex + TIMEOUT); + + if(dwWaitResult != WAIT_OBJECT_0) + { +// Trace("Error while waiting for onject @ thread %d, # iter %d\n", Id, i); + stats.operationsFailed += 1; + stats.operationsTotal += 1; + testStatus = FAIL; + continue; + } + if (! ReleaseMutex(hMutexHandle)) + { + // Deal with error. +// Trace("Error while releasing mutex @ thread %d # iter %d\n", Id, i); + stats.operationsFailed += 1; + stats.operationsTotal += 1; + // Probably need to have while true loop to attempt to release mutex... + testStatus = FAIL; + continue; + } + + stats.operationsTotal += 1; + stats.operationsPassed += 1; + // Trace("Successs while releasing mutex @ iteration %d -> thread %d -> Process %d\n", i, Id, USE_PROCESS_COUNT); + + } + + stats.operationTime = GetTimeDiff(dwStartTime); + //Trace("OPeration time is %d", stats.operationTime ); + if(resultBuffer->LogResult(Id, (char *)&stats)) + { + Fail("Error:%d: while writing to shared memory, Thread Id is[%d] and Process id is [%d]\n", GetLastError(), Id, USE_PROCESS_COUNT); + } +} diff --git a/src/pal/tests/palsuite/composite/object_management/mutex/shared/CMakeLists.txt b/src/pal/tests/palsuite/composite/object_management/mutex/shared/CMakeLists.txt new file mode 100644 index 0000000000..cf33d0b464 --- /dev/null +++ b/src/pal/tests/palsuite/composite/object_management/mutex/shared/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(SOURCES + main.c + mutex.c +) + +add_executable(paltest_mutex_shared + ${SOURCES} +) + +add_dependencies(paltest_mutex_shared coreclrpal) + +target_link_libraries(paltest_mutex_shared + pthread + rt + m + coreclrpal +) diff --git a/src/pal/tests/palsuite/composite/object_management/mutex/shared/main.c b/src/pal/tests/palsuite/composite/object_management/mutex/shared/main.c new file mode 100644 index 0000000000..aa98855565 --- /dev/null +++ b/src/pal/tests/palsuite/composite/object_management/mutex/shared/main.c @@ -0,0 +1,265 @@ +// 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. + +/*============================================================ +** +** This test is for Object Management Test case for Mutex where Object type is shareable. +** +** Source Code: main.c and mutex.c +** main.c creates a mutex, creates processes and waits for all processes to get over +** mutex.c create threads which will contend for the mutex +** +** This test is for Object Management Test case for Mutex where Object type is not shareable. +** Algorithm +** o Main Process Creates OBJECT_TYPE Object +** o Create PROCESS_COUNT processes aware of the Shared Object +** +** Author: ShamitP +** +** +**============================================================ +*/ + +#include <palsuite.h> +#include "resulttime.h" + +/* Test Input Variables */ +unsigned int PROCESS_COUNT = 2; +unsigned int THREAD_COUNT = 2; +unsigned int REPEAT_COUNT = 40000; +unsigned int RELATION_ID = 1001; + + +char objectSuffix[MAX_PATH]; + +struct TestStats{ + DWORD operationTime; + unsigned int relationId; + unsigned int processCount; + unsigned int threadCount; + unsigned int repeatCount; + char* buildNumber; + +}; + +int GetParameters( int argc, char **argv) +{ + if( (!((argc == 5) || (argc == 6) ) )|| ((argc == 1) && !strcmp(argv[1],"/?")) + || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H")) + { + printf("PAL -Composite Object Management event Test\n"); + printf("Usage:\n"); + printf("main\n\t[PROCESS_COUNT (greater than 1)] \n"); + printf("\t[THREAD_COUNT (greater than 1)] \n"); + printf("\t[REPEAT_COUNT (greater than 1)]\n"); + printf("\t[RELATION_ID [greater than 1]\n"); + printf("\t[Object Name Suffix]\n"); + return -1; + } + + PROCESS_COUNT = atoi(argv[1]); + if( (PROCESS_COUNT < 1) || (PROCESS_COUNT > MAXIMUM_WAIT_OBJECTS) ) + { + printf("\nMain Process:Invalid PROCESS_COUNT number, Pass greater than 1 and less than PROCESS_COUNT %d\n", MAXIMUM_WAIT_OBJECTS); + return -1; + } + + THREAD_COUNT = atoi(argv[2]); + if( (THREAD_COUNT < 1) || (THREAD_COUNT > MAXIMUM_WAIT_OBJECTS) ) + { + printf("\nInvalid THREAD_COUNT number, Pass greater than 1 and less than %d\n", MAXIMUM_WAIT_OBJECTS); + return -1; + } + + REPEAT_COUNT = atoi(argv[3]); + if( REPEAT_COUNT < 1) + { + printf("\nMain Process:Invalid REPEAT_COUNT number, Pass greater than 1\n"); + return -1; + } + + RELATION_ID = atoi(argv[4]); + if( RELATION_ID < 1) + { + printf("\nMain Process:Invalid RELATION_ID number, Pass greater than 1\n"); + return -1; + } + + if(argc == 6) + { + strncpy(objectSuffix, argv[5], MAX_PATH-1); + } + + return 0; +} + + int __cdecl main(INT argc, CHAR **argv) +{ + unsigned int i = 0; + HANDLE hProcess[MAXIMUM_WAIT_OBJECTS]; + HANDLE hMutexHandle; + + STARTUPINFO si[MAXIMUM_WAIT_OBJECTS]; + PROCESS_INFORMATION pi[MAXIMUM_WAIT_OBJECTS]; + + char ObjName[MAX_PATH] = "SHARED_MUTEX"; + char lpCommandLine[MAX_PATH] = ""; + + int returnCode = 0; + DWORD processReturnCode = 0; + int testReturnCode = PASS; + + char fileName[MAX_PATH]; + FILE *pFile = NULL; + DWORD dwStartTime; + struct TestStats testStats; + + if(0 != (PAL_Initialize(argc, argv))) + { + return ( FAIL ); + } + + ZeroMemory( objectSuffix, MAX_PATH ); + + if(GetParameters(argc, argv)) + { + Fail("Error in obtaining the parameters\n"); + } + + if(argc == 5) + { + strncat(ObjName, objectSuffix, MAX_PATH - (sizeof(ObjName) + 1) ); + } + + /* Register the start time */ + dwStartTime = GetTickCount(); + testStats.relationId = RELATION_ID; + testStats.processCount = PROCESS_COUNT; + testStats.threadCount = THREAD_COUNT; + testStats.repeatCount = REPEAT_COUNT; + testStats.buildNumber = getBuildNumber(); + + + _snprintf(fileName, MAX_PATH, "main_mutex_%d_.txt", RELATION_ID); + pFile = fopen(fileName, "w+"); + if(pFile == NULL) + { + Fail("Error in opening main file for write\n"); + } + + hMutexHandle = CreateMutex( + NULL, + FALSE, /* bInitialOwner, owns initially */ + ObjName + ); + + if( hMutexHandle == NULL) + { + Fail("Unable to create Mutex handle for Main thread returned error [%d]\n", GetLastError()); + } + + for( i = 0; i < PROCESS_COUNT; i++ ) + { + ZeroMemory( lpCommandLine, MAX_PATH ); + if ( _snprintf( lpCommandLine, MAX_PATH-1, "mutex %d %d %d %d %s", i, THREAD_COUNT, REPEAT_COUNT, RELATION_ID, objectSuffix) < 0 ) + { + Fail ("Error Insufficient mutex name string length for %s for iteration [%d]\n", ObjName, i); + } + + + /* Zero the data structure space */ + ZeroMemory ( &pi[i], sizeof(pi[i]) ); + ZeroMemory ( &si[i], sizeof(si[i]) ); + + /* Set the process flags and standard io handles */ + si[i].cb = sizeof(si[i]); + + //Create Process + if(!CreateProcess( NULL, /* lpApplicationName*/ + lpCommandLine, /* lpCommandLine */ + NULL, /* lpProcessAttributes */ + NULL, /* lpThreadAttributes */ + TRUE, /* bInheritHandles */ + 0, /* dwCreationFlags, */ + NULL, /* lpEnvironment */ + NULL, /* pCurrentDirectory */ + &si[i], /* lpStartupInfo */ + &pi[i] /* lpProcessInformation */ + )) + { + Fail("Process Not created for [%d], the error code is [%d]\n", i, GetLastError()); + } + else + { + hProcess[i] = pi[i].hProcess; +// Trace("Process created for [%d]\n", i); + + } + } + + returnCode = WaitForMultipleObjects( PROCESS_COUNT, hProcess, TRUE, INFINITE); + if( WAIT_OBJECT_0 != returnCode ) + { + Trace("Wait for Object(s) @ Main thread for %d processes returned %d, and GetLastError value is %d\n", PROCESS_COUNT, returnCode, GetLastError()); + testReturnCode = FAIL; + } + + for( i = 0; i < PROCESS_COUNT; i++ ) + { + /* check the exit code from the process */ + if( ! GetExitCodeProcess( pi[i].hProcess, &processReturnCode ) ) + { + Trace( "GetExitCodeProcess call failed for iteration %d with error code %u\n", + i, GetLastError() ); + + testReturnCode = FAIL; + } + + if(processReturnCode == FAIL) + { + Trace( "Process [%d] failed and returned FAIL\n", i); + testReturnCode = FAIL; + } + + if(!CloseHandle(pi[i].hThread)) + { + Trace("Error:%d: CloseHandle failed for Process [%d] hThread\n", GetLastError(), i); + testReturnCode = FAIL; + } + + if(!CloseHandle(pi[i].hProcess) ) + { + Trace("Error:%d: CloseHandle failed for Process [%d] hProcess\n", GetLastError(), i); + testReturnCode = FAIL; + } + } + + testStats.operationTime = GetTimeDiff(dwStartTime); + fprintf(pFile, "%d,%d,%d,%d,%d,%s\n", testStats.operationTime, testStats.relationId, testStats.processCount, testStats.threadCount, testStats.repeatCount, testStats.buildNumber ); + if(fclose(pFile)) + { + Trace("Error: fclose failed for pFile\n"); + testReturnCode = FAIL; + } + + if(!CloseHandle(hMutexHandle)) + { + Trace("Error:%d: CloseHandle failed for hMutexHandle\n", GetLastError()); + testReturnCode = FAIL; + + } + + if( testReturnCode == PASS) + { + Trace("Test Passed\n"); + } + else + { + Trace("Test Failed\n"); + } + + PAL_Terminate(); + return testReturnCode; +} + diff --git a/src/pal/tests/palsuite/composite/object_management/mutex/shared/mutex.c b/src/pal/tests/palsuite/composite/object_management/mutex/shared/mutex.c new file mode 100644 index 0000000000..ec5d9b37ac --- /dev/null +++ b/src/pal/tests/palsuite/composite/object_management/mutex/shared/mutex.c @@ -0,0 +1,354 @@ +// 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. + +/*============================================================ +** +** This test is for Object Management Test case for Mutex where Object type is shareable. +** +** Source Code: main.c and mutex.c +** main.c creates a mutex, creates processes and waits for all processes to get over +** mutex.c create threads which will contend for the mutex +** +** This test is for Object Management Test case for Mutex where Object type is not shareable. +** Algorithm +** o Main Process Creates OBJECT_TYPE Object +** o Create PROCESS_COUNT processes aware of the Shared Object +** +** Author: ShamitP +** +** +**============================================================ +*/ + +#include <palsuite.h> +#include "resultbuffer.h" +#include "resulttime.h" + +#define TIMEOUT 5000 +/* Test Input Variables */ +unsigned int USE_PROCESS_COUNT = 0; +unsigned int THREAD_COUNT = 0; +unsigned int REPEAT_COUNT = 0; +unsigned int RELATION_ID = 0; + + +/* Capture statistics at per thread basis */ +struct statistics{ + unsigned int processId; + unsigned int operationsFailed; + unsigned int operationsPassed; + unsigned int operationsTotal; + DWORD operationTime; + unsigned int relationId; +}; + +struct ProcessStats{ + unsigned int processId; + DWORD operationTime; + unsigned int relationId; +}; + +HANDLE StartTestsEvHandle = NULL; +HANDLE hMutexHandle = NULL; + +/* Results Buffer */ +ResultBuffer *resultBuffer = NULL; + +int testStatus; + +const char sTmpEventName[MAX_PATH] = "StartTestEvent"; +char objectSuffix[MAX_PATH]; + +void PALAPI Run_Thread(LPVOID lpParam); + +int GetParameters( int argc, char **argv) +{ + if( (!((argc == 5) || (argc == 6) ) )|| ((argc == 1) && !strcmp(argv[1],"/?")) + || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H")) + { + printf("PAL -Composite Object Management event Test\n"); + printf("Usage:\n"); + printf("main\n\t[USE_PROCESS_COUNT (greater than 1)] \n"); + printf("\t[THREAD_COUNT (greater than 1)] \n"); + printf("\t[REPEAT_COUNT (greater than 1)]\n"); + printf("\t[RELATION_ID [greater than 1]\n"); + printf("\t[Object Name Suffix]\n"); + + return -1; + } + + // Trace("Args 1 is [%s], Arg 2 is [%s], Arg 3 is [%s]\n", argv[1], argv[2], argv[3]); + + USE_PROCESS_COUNT = atoi(argv[1]); + if( USE_PROCESS_COUNT < 0) + { + printf("\nInvalid USE_PROCESS_COUNT number, Pass greater than 1\n"); + return -1; + } + + THREAD_COUNT = atoi(argv[2]); + if( (THREAD_COUNT < 1) || (THREAD_COUNT > MAXIMUM_WAIT_OBJECTS) ) + { + printf("\nInvalid THREAD_COUNT number, Pass greater than 1 and less than %d\n", MAXIMUM_WAIT_OBJECTS); + return -1; + } + + REPEAT_COUNT = atoi(argv[3]); + if( REPEAT_COUNT < 1) + { + printf("\nInvalid REPEAT_COUNT number, Pass greater than 1\n"); + return -1; + } + + RELATION_ID = atoi(argv[4]); + if( RELATION_ID < 1) + { + printf("\nMain Process:Invalid RELATION_ID number, Pass greater than 1\n"); + return -1; + } + + if(argc == 6) + { + strncpy(objectSuffix, argv[5], MAX_PATH-1); + } + + return 0; +} + + int __cdecl main(INT argc, CHAR **argv) +{ + unsigned int i = 0; + HANDLE hThread[MAXIMUM_WAIT_OBJECTS]; + DWORD threadId[MAXIMUM_WAIT_OBJECTS]; + + char ObjName[MAX_PATH] = "SHARED_MUTEX"; + DWORD dwParam = 0; + + int returnCode = 0; + + /* Variables to capture the file name and the file pointer*/ + char fileName[MAX_PATH]; + FILE *pFile = NULL; + struct statistics* buffer = NULL; + int statisticsSize = 0; + + /* Variables to capture the file name and the file pointer at process level*/ + char processFileName[MAX_PATH]; + FILE *pProcessFile = NULL; + struct ProcessStats processStats; + DWORD dwStartTime; + + testStatus = PASS; + + if(0 != (PAL_Initialize(argc, argv))) + { + return ( FAIL ); + } + + ZeroMemory( objectSuffix, MAX_PATH ); + + if(GetParameters(argc, argv)) + { + Fail("Error in obtaining the parameters\n"); + } +// Trace("Process created, value of process count is [%d]\n", USE_PROCESS_COUNT); + + if(argc == 5) + { + strncat(ObjName, objectSuffix, MAX_PATH - (sizeof(ObjName) + 1) ); + } + + /* Register the start time */ + dwStartTime = GetTickCount(); + processStats.relationId = RELATION_ID; + processStats.processId = USE_PROCESS_COUNT; + + _snprintf(processFileName, MAX_PATH, "%d_process_mutex_%d_.txt", USE_PROCESS_COUNT, RELATION_ID); + pProcessFile = fopen(processFileName, "w+"); + if(pProcessFile == NULL) + { + Fail("Error in opening process File file for write for process [%d]\n", USE_PROCESS_COUNT); + } statisticsSize = sizeof(struct statistics); + + _snprintf(fileName, MAX_PATH, "%d_thread_mutex_%d_.txt", USE_PROCESS_COUNT, RELATION_ID); + pFile = fopen(fileName, "w+"); + if(pFile == NULL) + { + Fail("Error in opening file for write for process [%d]\n", USE_PROCESS_COUNT); + } + // For each thread we will log operations failed (int), passed (int), total (int) + // and number of ticks (DWORD) for the operations + resultBuffer = new ResultBuffer( THREAD_COUNT, statisticsSize); + + /* Create StartTest Event */ + StartTestsEvHandle = CreateEvent( NULL, /* lpEventAttributes*/ + TRUE, /* bManualReset */ + FALSE, /* bInitialState */ + NULL); /* name of Event */ + + if( StartTestsEvHandle == NULL ) + { + Fail("Error:%d: Unexpected failure " + "to create %s Event for process count %d\n", GetLastError(), sTmpEventName, USE_PROCESS_COUNT ); + + } + + hMutexHandle = CreateMutex( + NULL, + FALSE, /* bInitialOwner, owns initially */ + ObjName + ); + + if( (hMutexHandle == NULL)|| (GetLastError() != ERROR_ALREADY_EXISTS)) + { + Fail("Unable to create Mutex handle for process id [%d], returned error [%d], expected ERROR_ALREADY_EXISTS\n", i, GetLastError()); + } + /* We already assume that the mutex was created previously*/ + + for( i = 0; i < THREAD_COUNT; i++ ) + { + dwParam = (int) i; + //Create thread + hThread[i] = CreateThread( + NULL, /* no security attributes */ + 0, /* use default stack size */ + (LPTHREAD_START_ROUTINE)Run_Thread,/* thread function */ + (LPVOID)dwParam, /* argument to thread function */ + 0, /* use default creation flags */ + &threadId[i] /* returns the thread identifier*/ + ); + + if(hThread[i] == NULL) + { + Fail("Create Thread failed for %d process, and GetLastError value is %d\n", USE_PROCESS_COUNT, GetLastError()); + } + + } + + if (!SetEvent(StartTestsEvHandle)) + { + Fail("Set Event for Start Tests failed for %d process, and GetLastError value is %d\n", USE_PROCESS_COUNT, GetLastError()); + } + + /* Test running */ + returnCode = WaitForMultipleObjects( THREAD_COUNT, hThread, TRUE, INFINITE); + + if( WAIT_OBJECT_0 != returnCode ) + { + Trace("Wait for Object(s) for %d process returned %d, and GetLastError value is %d\n", USE_PROCESS_COUNT, returnCode, GetLastError()); + testStatus = FAIL; + } + + processStats.operationTime = GetTimeDiff(dwStartTime); + + /* Write to a file*/ + if(pFile!= NULL) + { + for( i = 0; i < THREAD_COUNT; i++ ) + { + buffer = (struct statistics *)resultBuffer->getResultBuffer(i); + returnCode = fprintf(pFile, "%d,%d,%d,%d,%lu,%d\n", buffer->processId, buffer->operationsFailed, buffer->operationsPassed, buffer->operationsTotal, buffer->operationTime, buffer->relationId ); +// Trace("Iteration %d over\n", i); + + } + } + fclose(pFile); + + fprintf(pProcessFile, "%d,%d,%d\n", USE_PROCESS_COUNT, processStats.operationTime, processStats.relationId ); + fclose(pProcessFile); + + /* Logging for the test case over, clean up the handles */ + +// Trace("Process Count %d over\n",USE_PROCESS_COUNT); + + for( i = 0; i < THREAD_COUNT; i++ ) + { + if(!CloseHandle(hThread[i]) ) + { + Trace("Error:%d: CloseHandle failed for Process [%d] hThread[%d]\n", GetLastError(), USE_PROCESS_COUNT, i); + testStatus = FAIL; + } + } + + if(!CloseHandle(StartTestsEvHandle)) + { + Trace("Error:%d: CloseHandle failed for Process [%d] StartTestsEvHandle\n", GetLastError(), USE_PROCESS_COUNT); + testStatus = FAIL; + } + + if(!CloseHandle(hMutexHandle)) + { + Trace("Error:%d: CloseHandle failed for Process [%d] hMutexHandle\n", GetLastError(), USE_PROCESS_COUNT); + testStatus = FAIL; + } + + PAL_Terminate(); + return testStatus; +} + +void PALAPI Run_Thread (LPVOID lpParam) +{ + unsigned int i = 0; + DWORD dwWaitResult; + + struct statistics stats; + DWORD dwStartTime; + + stats.relationId = RELATION_ID; + stats.processId = USE_PROCESS_COUNT; + stats.operationsFailed = 0; + stats.operationsPassed = 0; + stats.operationsTotal = 0; + stats.operationTime = 0; + + int Id=(int)lpParam; + + dwWaitResult = WaitForSingleObject( + StartTestsEvHandle, // handle to mutex + TIMEOUT); + + if(dwWaitResult != WAIT_OBJECT_0) + { + Trace("Error while waiting for StartTest Event@ thread %d\n", Id); + testStatus = FAIL; + } + + dwStartTime = GetTickCount(); + + for( i = 0; i < REPEAT_COUNT; i++ ) + { + dwWaitResult = WaitForSingleObject( + hMutexHandle, // handle to mutex + TIMEOUT); + + if(dwWaitResult != WAIT_OBJECT_0) + { +// Trace("Error while waiting for onject @ thread %d, # iter %d, Error Returned [%d]\n", Id, i, GetLastError()); + stats.operationsFailed += 1; + stats.operationsTotal += 1; + testStatus = FAIL; + continue; + } + if (! ReleaseMutex(hMutexHandle)) + { + // Deal with error. +// Trace("Error while releasing mutex @ thread %d # iter %d\n", Id, i); + stats.operationsFailed += 1; + stats.operationsTotal += 1; + // Probably need to have while true loop to attempt to release mutex... + testStatus = FAIL; + continue; + } + + stats.operationsTotal += 1; + stats.operationsPassed += 1; +// Trace("Successs while releasing mutex @ iteration %d -> thread %d -> Process count %d\n", i, Id, USE_PROCESS_COUNT); + + } + stats.operationTime = GetTimeDiff(dwStartTime); + if(resultBuffer->LogResult(Id, (char *)&stats)) + { + Fail("Error:%d: while writing to shared memory, Thread Id is[%d] and Process id is [%d]\n", GetLastError(), Id, USE_PROCESS_COUNT); + } +} diff --git a/src/pal/tests/palsuite/composite/object_management/readme.txt b/src/pal/tests/palsuite/composite/object_management/readme.txt new file mode 100644 index 0000000000..6bae5f105d --- /dev/null +++ b/src/pal/tests/palsuite/composite/object_management/readme.txt @@ -0,0 +1,29 @@ +To compile: + +1) create a dat file (say object_management.dat) with contents: + +PAL,Composite,palsuite\composite\object_management\mutex\nonshared,mutex=main.c mutex.c,<SUPPORTEXE>,<TESTLANGCPP>,<COMPILEONLY> +PAL,Composite,palsuite\composite\object_management\mutex\shared,mutex=main.c mutex.c,<SUPPORTEXE>,<TESTLANGCPP>,<COMPILEONLY> +PAL,Composite,palsuite\composite\object_management\semaphore\nonshared,semaphore=main.c semaphore.c,<SUPPORTEXE>,<TESTLANGCPP>,<COMPILEONLY> +PAL,Composite,palsuite\composite\object_management\semaphore\shared,semaphore=main.c semaphore.c,<SUPPORTEXE>,<TESTLANGCPP>,<COMPILEONLY> +PAL,Composite,palsuite\composite\object_management\event\nonshared,event=main.c event.c,<SUPPORTEXE>,<TESTLANGCPP>,<COMPILEONLY> +PAL,Composite,palsuite\composite\object_management\event\shared,event=main.c event.c,<SUPPORTEXE>,<TESTLANGCPP>,<COMPILEONLY> + + +2) perl rrunmod.pl -r object_management.dat + + +To execute: +For each of the test cases, +main [PROCESS_COUNT] [THREAD_COUNT] [REPEAT_COUNT] + + +Output: +The performance numbers will be in <process_logical_id>_[event|semaphore|mutex].txt +(will be at palsuite\composite\object_management\[mutex|event|semaphore]\[shared|nonshared]\obj[r|c|d] directory if u use rrunmod.pl) + +So if process_count is 3, you will have files 0_mutex.txt, 1_mutex.txt and so on… + +For each process txt file created, +each row represents a thread data (process id, number of failures, number of pass, total number of repeated operations and an integer that will be used to identify a run +(currently zero)). diff --git a/src/pal/tests/palsuite/composite/object_management/semaphore/CMakeLists.txt b/src/pal/tests/palsuite/composite/object_management/semaphore/CMakeLists.txt new file mode 100644 index 0000000000..2534564f95 --- /dev/null +++ b/src/pal/tests/palsuite/composite/object_management/semaphore/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +add_subdirectory(nonshared) +add_subdirectory(shared) + diff --git a/src/pal/tests/palsuite/composite/object_management/semaphore/nonshared/CMakeLists.txt b/src/pal/tests/palsuite/composite/object_management/semaphore/nonshared/CMakeLists.txt new file mode 100644 index 0000000000..6efa228fbb --- /dev/null +++ b/src/pal/tests/palsuite/composite/object_management/semaphore/nonshared/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(SOURCES + main.c + semaphore.c +) + +add_executable(paltest_semaphore_nonshared + ${SOURCES} +) + +add_dependencies(paltest_semaphore_nonshared coreclrpal) + +target_link_libraries(paltest_semaphore_nonshared + pthread + rt + m + coreclrpal +) diff --git a/src/pal/tests/palsuite/composite/object_management/semaphore/nonshared/main.c b/src/pal/tests/palsuite/composite/object_management/semaphore/nonshared/main.c new file mode 100644 index 0000000000..854809c8f8 --- /dev/null +++ b/src/pal/tests/palsuite/composite/object_management/semaphore/nonshared/main.c @@ -0,0 +1,228 @@ +// 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 Code: main.c and semaphore.c +** main.c creates process and waits for all processes to get over +** semaphore.c creates a semaphore and then calls threads which will contend for the semaphore +** +** This test is for Object Management Test case for semaphore where Object type is not shareable. +** Algorithm +** o Create PROCESS_COUNT processes. +** o Main Thread of each process creates OBJECT_TYPE Object +** +** Author: ShamitP +** +** +**============================================================ +*/ + +#include <palsuite.h> +#include "resulttime.h" + +/* Test Input Variables */ +unsigned int PROCESS_COUNT = 2; +unsigned int THREAD_COUNT = 15; +unsigned int REPEAT_COUNT = 40000; +unsigned int RELATION_ID = 1001; + + + +struct TestStats{ + DWORD operationTime; + unsigned int relationId; + unsigned int processCount; + unsigned int threadCount; + unsigned int repeatCount; + char* buildNumber; +}; + +int GetParameters( int argc, char **argv) +{ + if( (argc != 5) || ((argc == 1) && !strcmp(argv[1],"/?")) + || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H")) + { + printf("PAL -Composite Object Management Semaphore Test\n"); + printf("Usage:\n"); + printf("main\n\t[PROCESS_COUNT [greater than 1] \n"); + printf("\t[THREAD_COUNT [greater than 1] \n"); + printf("\t[REPEAT_COUNT [greater than 1]\n"); + printf("\t[RELATION_ID [greater than 1]\n"); + return -1; + } + + PROCESS_COUNT = atoi(argv[1]); + if( (PROCESS_COUNT < 1) || (PROCESS_COUNT > MAXIMUM_WAIT_OBJECTS) ) + { + printf("\nMain Process:Invalid PROCESS_COUNT number, Pass greater than 1 and less than PROCESS_COUNT %d\n", MAXIMUM_WAIT_OBJECTS); + return -1; + } + + THREAD_COUNT = atoi(argv[2]); + if( (THREAD_COUNT < 1) || (THREAD_COUNT > MAXIMUM_WAIT_OBJECTS) ) + { + printf("\nInvalid THREAD_COUNT number, Pass greater than 1 and less than %d\n", MAXIMUM_WAIT_OBJECTS); + return -1; + } + + REPEAT_COUNT = atoi(argv[3]); + if( REPEAT_COUNT < 1) + { + printf("\nMain Process:Invalid REPEAT_COUNT number, Pass greater than 1\n"); + return -1; + } + + RELATION_ID = atoi(argv[4]); + if( RELATION_ID < 1) + { + printf("\nMain Process:Invalid RELATION_ID number, Pass greater than or Equal to 1\n"); + return -1; + } + + return 0; +} + + int __cdecl main(INT argc, CHAR **argv) +{ + unsigned int i = 0; + HANDLE hProcess[MAXIMUM_WAIT_OBJECTS]; + HANDLE hSemaphoreHandle[MAXIMUM_WAIT_OBJECTS]; + + STARTUPINFO si[MAXIMUM_WAIT_OBJECTS]; + PROCESS_INFORMATION pi[MAXIMUM_WAIT_OBJECTS]; + + const char *ObjName = "Semaphore"; + char lpCommandLine[MAX_PATH] = ""; + + int returnCode = 0; + DWORD processReturnCode = 0; + int testReturnCode = PASS; + + char fileName[MAX_PATH]; + FILE *pFile = NULL; + DWORD dwStartTime; + struct TestStats testStats; + + if(0 != (PAL_Initialize(argc, argv))) + { + return ( FAIL ); + } + + if(GetParameters(argc, argv)) + { + Fail("Error in obtaining the parameters\n"); + } + + /* Register the start time */ + dwStartTime = GetTickCount(); + testStats.relationId = RELATION_ID; + testStats.processCount = PROCESS_COUNT; + testStats.threadCount = THREAD_COUNT; + testStats.repeatCount = REPEAT_COUNT; + testStats.buildNumber = getBuildNumber(); + + + _snprintf(fileName, MAX_PATH, "main_semaphore_%d_.txt", RELATION_ID); + pFile = fopen(fileName, "w+"); + if(pFile == NULL) + { + Fail("Error in opening main file for write\n"); + } + + for( i = 0; i < PROCESS_COUNT; i++ ) + { + ZeroMemory( lpCommandLine, MAX_PATH ); + if ( _snprintf( lpCommandLine, MAX_PATH-1, "semaphore %d %d %d %d", i, THREAD_COUNT, REPEAT_COUNT, RELATION_ID) < 0 ) + { + Fail("Error Insufficient semaphore name string length for %s for iteration [%d]\n", ObjName, i); + } + + /* Zero the data structure space */ + ZeroMemory ( &pi[i], sizeof(pi[i]) ); + ZeroMemory ( &si[i], sizeof(si[i]) ); + + /* Set the process flags and standard io handles */ + si[i].cb = sizeof(si[i]); + + //Create Process + if(!CreateProcess( NULL, /* lpApplicationName*/ + lpCommandLine, /* lpCommandLine */ + NULL, /* lpProcessAttributes */ + NULL, /* lpThreadAttributes */ + TRUE, /* bInheritHandles */ + 0, /* dwCreationFlags, */ + NULL, /* lpEnvironment */ + NULL, /* pCurrentDirectory */ + &si[i], /* lpStartupInfo */ + &pi[i] /* lpProcessInformation */ + )) + { + Fail("Process Not created for [%d], the error code is [%d]\n", i, GetLastError()); + } + else + { + hProcess[i] = pi[i].hProcess; +// Trace("Process created for [%d]\n", i); + + } + } + + returnCode = WaitForMultipleObjects( PROCESS_COUNT, hProcess, TRUE, INFINITE); + if( WAIT_OBJECT_0 != returnCode ) + { + Trace("Wait for Object(s) @ Main thread for %d processes returned %d, and GetLastError value is %d\n", PROCESS_COUNT, returnCode, GetLastError()); + testReturnCode = FAIL; + } + + for( i = 0; i < PROCESS_COUNT; i++ ) + { + /* check the exit code from the process */ + if( ! GetExitCodeProcess( pi[i].hProcess, &processReturnCode ) ) + { + Trace( "GetExitCodeProcess call failed for iteration %d with error code %u\n", + i, GetLastError() ); + + testReturnCode = FAIL; + } + + if(processReturnCode == FAIL) + { + Trace( "Process [%d] failed and returned FAIL\n", i); + testReturnCode = FAIL; + } + + if(!CloseHandle(pi[i].hThread)) + { + Trace("Error:%d: CloseHandle failed for Process [%d] hThread\n", GetLastError(), i); + testReturnCode = FAIL; + } + + if(!CloseHandle(pi[i].hProcess) ) + { + Trace("Error:%d: CloseHandle failed for Process [%d] hProcess\n", GetLastError(), i); + testReturnCode = FAIL; + } + } + + testStats.operationTime = GetTimeDiff(dwStartTime); + fprintf(pFile, "%d,%d,%d,%d,%d,%s\n", testStats.operationTime, testStats.relationId,testStats.processCount, testStats.threadCount, testStats.repeatCount, testStats.buildNumber ); + if(fclose(pFile)) + { + Trace("Error: fclose failed for pFile\n"); + testReturnCode = FAIL; + } + + if( testReturnCode == PASS) + { + Trace("Test Passed\n"); + } + else + { + Trace("Test Failed\n"); + } + + PAL_Terminate(); + return testReturnCode; +} diff --git a/src/pal/tests/palsuite/composite/object_management/semaphore/nonshared/semaphore.c b/src/pal/tests/palsuite/composite/object_management/semaphore/nonshared/semaphore.c new file mode 100644 index 0000000000..0e487f2c17 --- /dev/null +++ b/src/pal/tests/palsuite/composite/object_management/semaphore/nonshared/semaphore.c @@ -0,0 +1,342 @@ +// 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 Code: main.c and semaphore.c +** main.c creates process and waits for all processes to get over +** semaphore.c creates a semaphore and then calls threads which will contend for the semaphore +** +** This test is for Object Management Test case for semaphore where Object type is not shareable. +** Algorithm +** o Create PROCESS_COUNT processes. +** o Main Thread of each process creates OBJECT_TYPE Object +** +** Author: ShamitP +** +** +**============================================================ +*/ + +#include <palsuite.h> +#include "resultbuffer.h" +#include "resulttime.h" + +#define TIMEOUT 5000 +/* Test Input Variables */ +unsigned int USE_PROCESS_COUNT = 0; +unsigned int THREAD_COUNT = 0; +unsigned int REPEAT_COUNT = 0; +unsigned int RELATION_ID = 0; + +/* Capture statistics at per thread basis */ +struct statistics{ + unsigned int processId; + unsigned int operationsFailed; + unsigned int operationsPassed; + unsigned int operationsTotal; + DWORD operationTime; + unsigned int relationId; +}; + +struct ProcessStats{ + unsigned int processId; + DWORD operationTime; + unsigned int relationId; +}; + +/* Semaphore variables */ +unsigned long lInitialCount = 1; /* Signaled */ +unsigned long lMaximumCount = 1; /* Maximum value of 1 */ + +HANDLE StartTestsEvHandle = NULL; +HANDLE hSemaphoreHandle = NULL; + +/* Results Buffer */ +ResultBuffer *resultBuffer = NULL; + +int testStatus; + +const char sTmpEventName[MAX_PATH] = "StartTestEvent"; + +void PALAPI Run_Thread(LPVOID lpParam); + +int GetParameters( int argc, char **argv) +{ + if( (argc != 5) || ((argc == 1) && !strcmp(argv[1],"/?")) + || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H")) + { + printf("PAL -Composite Object Management Semaphore Test\n"); + printf("Usage:\n"); + printf("semaphore\n\t[USE_PROCESS_COUNT ( greater than 1] \n"); + printf("\t[THREAD_COUNT ( greater than 1] \n"); + printf("\t[REPEAT_COUNT ( greater than 1]\n"); + printf("\t[RELATION_ID [greater than 1]\n"); + return -1; + } + + // Trace("Args 1 is [%s], Arg 2 is [%s], Arg 3 is [%s]\n", argv[1], argv[2], argv[3]); + + USE_PROCESS_COUNT = atoi(argv[1]); + if( USE_PROCESS_COUNT < 0) + { + printf("\nInvalid USE_PROCESS_COUNT number, Pass greater than 1\n"); + return -1; + } + + THREAD_COUNT = atoi(argv[2]); + if( (THREAD_COUNT < 1) || (THREAD_COUNT > MAXIMUM_WAIT_OBJECTS) ) + { + printf("\nInvalid THREAD_COUNT number, Pass greater than 1 and less than %d\n", MAXIMUM_WAIT_OBJECTS); + return -1; + } + + REPEAT_COUNT = atoi(argv[3]); + if( REPEAT_COUNT < 1) + { + printf("\nInvalid REPEAT_COUNT number, Pass greater than 1\n"); + return -1; + } + + RELATION_ID = atoi(argv[4]); + if( RELATION_ID < 1) + { + printf("\nMain Process:Invalid RELATION_ID number, Pass greater than or Equal to 1\n"); + return -1; + } + + return 0; +} + + int __cdecl main(INT argc, CHAR **argv) +{ + unsigned int i = 0; + HANDLE hThread[MAXIMUM_WAIT_OBJECTS]; + DWORD threadId[MAXIMUM_WAIT_OBJECTS]; + + const char *ObjName = "Semaphore"; + + DWORD dwParam = 0; + + int returnCode = 0; + + /* Variables to capture the file name and the file pointer at thread level*/ + char fileName[MAX_PATH]; + FILE *pFile = NULL; + struct statistics* buffer = NULL; + int statisticsSize = 0; + + /* Variables to capture the file name and the file pointer at process level*/ + char processFileName[MAX_PATH]; + FILE *pProcessFile = NULL; + struct ProcessStats processStats; + DWORD dwStartTime; + + testStatus = PASS; + + if(0 != (PAL_Initialize(argc, argv))) + { + return ( FAIL ); + } + + if(GetParameters(argc, argv)) + { + Fail("Error in obtaining the parameters\n"); + } + // Trace("Process created, value of process count is [%d]\n", USE_PROCESS_COUNT); + + /* Register the start time */ + dwStartTime = GetTickCount(); + processStats.relationId = RELATION_ID; + processStats.processId = USE_PROCESS_COUNT; + + _snprintf(processFileName, MAX_PATH, "%d_process_semaphore_%d_.txt", USE_PROCESS_COUNT, RELATION_ID); + pProcessFile = fopen(processFileName, "w+"); + if(pProcessFile == NULL) + { + Fail("Error in opening process File file for write for process [%d]\n", USE_PROCESS_COUNT); + } + + statisticsSize = sizeof(struct statistics); + + _snprintf(fileName, MAX_PATH, "%d_thread_semaphore_%d_.txt", USE_PROCESS_COUNT, RELATION_ID); + pFile = fopen(fileName, "w+"); + if(pFile == NULL) + { + Fail("Error in opening file for write for process [%d]\n", USE_PROCESS_COUNT); + } + // For each thread we will log operations failed (int), passed (int), total (int) + // and number of ticks (DWORD) for the operations + resultBuffer = new ResultBuffer( THREAD_COUNT, statisticsSize); + + StartTestsEvHandle = CreateEvent( NULL, /* lpEventAttributes*/ + TRUE, /* bManualReset */ + FALSE, /* bInitialState */ + NULL); /* name of Event */ + + if( StartTestsEvHandle == NULL ) + { + Fail("Error:%d: Unexpected failure " + "to create %s Event for process count %d\n", GetLastError(), sTmpEventName, USE_PROCESS_COUNT ); + + } + + /* Create StartTest Event */ + hSemaphoreHandle = CreateSemaphore( + NULL, /* lpSemaphoreAttributes */ + lInitialCount, /*lInitialCount*/ + lMaximumCount, /*lMaximumCount */ + NULL + ); + + if( hSemaphoreHandle == NULL) + { + Fail("Unable to create Semaphore handle for process id [%d], returned error [%d]\n", i, GetLastError()); + } + /* We already assume that the Semaphore was created previously*/ + + for( i = 0; i < THREAD_COUNT; i++ ) + { + dwParam = (int) i; + //Create thread + hThread[i] = CreateThread( + NULL, /* no security attributes */ + 0, /* use default stack size */ + (LPTHREAD_START_ROUTINE)Run_Thread,/* thread function */ + (LPVOID)dwParam, /* argument to thread function */ + 0, /* use default creation flags */ + &threadId[i] /* returns the thread identifier*/ + ); + + + if(hThread[i] == NULL) + { + Fail("Create Thread failed for %d process, and GetLastError value is %d\n", USE_PROCESS_COUNT, GetLastError()); + } + + } + + if (!SetEvent(StartTestsEvHandle)) + { + Fail("Set Event for Start Tests failed for %d process, and GetLastError value is %d\n", USE_PROCESS_COUNT, GetLastError()); + } + + /* Test running */ + returnCode = WaitForMultipleObjects( THREAD_COUNT, hThread, TRUE, INFINITE); + + if( WAIT_OBJECT_0 != returnCode ) + { + Trace("Wait for Object(s) for %d process returned %d, and GetLastError value is %d\n", USE_PROCESS_COUNT, returnCode, GetLastError()); + testStatus = FAIL; + } + + processStats.operationTime = GetTimeDiff(dwStartTime); + + /* Write to a file*/ + if(pFile!= NULL) + { + for( i = 0; i < THREAD_COUNT; i++ ) + { + buffer = (struct statistics *)resultBuffer->getResultBuffer(i); + returnCode = fprintf(pFile, "%d,%d,%d,%d,%lu,%d\n", buffer->processId, buffer->operationsFailed, buffer->operationsPassed, buffer->operationsTotal, buffer->operationTime, buffer->relationId ); + //Trace("Iteration %d over\n", i); + + } + } + fclose(pFile); + /* Logging for the test case over, clean up the handles */ + +// Trace("Test Thread %d done\n", USE_PROCESS_COUNT); + + for( i = 0; i < THREAD_COUNT; i++ ) + { + if(!CloseHandle(hThread[i]) ) + { + Trace("Error:%d: CloseHandle failed for Process [%d] hThread[%d]\n", GetLastError(), USE_PROCESS_COUNT, i); + testStatus = FAIL; + } + } + + if(!CloseHandle(StartTestsEvHandle)) + { + Trace("Error:%d: CloseHandle failed for Process [%d] StartTestsEvHandle\n", GetLastError(), USE_PROCESS_COUNT); + testStatus = FAIL; + } + + if(!CloseHandle(hSemaphoreHandle)) + { + Trace("Error:%d: CloseHandle failed for Process [%d] hSemaphoreHandle\n", GetLastError(), USE_PROCESS_COUNT); + testStatus = FAIL; + } + + PAL_Terminate(); + return PASS; +} + +void PALAPI Run_Thread (LPVOID lpParam) +{ + unsigned int i = 0; + DWORD dwWaitResult; + + int Id=(int)lpParam; + + struct statistics stats; + DWORD dwStartTime; + + stats.relationId = RELATION_ID; + stats.processId = USE_PROCESS_COUNT; + stats.operationsFailed = 0; + stats.operationsPassed = 0; + stats.operationsTotal = 0; + stats.operationTime = 0; + + dwWaitResult = WaitForSingleObject( + StartTestsEvHandle, // handle to start test handle + TIMEOUT); + + if(dwWaitResult != WAIT_OBJECT_0) + { + Fail("Error while waiting for StartTest Event@ thread %d, RC is %d, Error is %d\n", Id, dwWaitResult, GetLastError()); + } + + dwStartTime = GetTickCount(); + + for( i = 0; i < REPEAT_COUNT; i++ ) + { + dwWaitResult = WaitForSingleObject( + hSemaphoreHandle, // handle to Semaphore + TIMEOUT); + + if(dwWaitResult != WAIT_OBJECT_0) + { +// Trace("Error while waiting for onject @ thread %d, # iter %d, RC is %d, Error is %d\n", Id, i, dwWaitResult, GetLastError()); + stats.operationsFailed += 1; + stats.operationsTotal += 1; + testStatus = FAIL; + continue; + } + if (! ReleaseSemaphore(hSemaphoreHandle, 1, NULL)) + { + // Deal with error. + // Trace("Error while releasing Semaphore @ thread %d # iter %d\n", Id, i); + stats.operationsFailed += 1; + stats.operationsTotal += 1; + // Probably need to have while true loop to attempt to release semaphore... + testStatus = FAIL; + continue; + } + + stats.operationsTotal += 1; + stats.operationsPassed += 1; +// Trace("Successs while releasing Semaphore @ iteration %d -> thread %d -> Process %d\n", i, Id, USE_PROCESS_COUNT); + + } + + stats.operationTime = GetTimeDiff(dwStartTime); + if(resultBuffer->LogResult(Id, (char *)&stats)) + { + Fail("Error:%d: while writing to shared memory, Thread Id is[%d] and Process id is [%d]\n", GetLastError(), Id, USE_PROCESS_COUNT); + } + // Trace("Thread %d over for process %d\n", Id, USE_PROCESS_COUNT); +} diff --git a/src/pal/tests/palsuite/composite/object_management/semaphore/shared/CMakeLists.txt b/src/pal/tests/palsuite/composite/object_management/semaphore/shared/CMakeLists.txt new file mode 100644 index 0000000000..12d3ca867e --- /dev/null +++ b/src/pal/tests/palsuite/composite/object_management/semaphore/shared/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(SOURCES + main.c + semaphore.c +) + +add_executable(paltest_semaphore_shared + ${SOURCES} +) + +add_dependencies(paltest_semaphore_shared coreclrpal) + +target_link_libraries(paltest_semaphore_shared + pthread + rt + m + coreclrpal +) diff --git a/src/pal/tests/palsuite/composite/object_management/semaphore/shared/main.c b/src/pal/tests/palsuite/composite/object_management/semaphore/shared/main.c new file mode 100644 index 0000000000..deb8252b70 --- /dev/null +++ b/src/pal/tests/palsuite/composite/object_management/semaphore/shared/main.c @@ -0,0 +1,278 @@ +// 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 Code: main.c and semaphore.c +** main.c creates process and waits for all processes to get over +** semaphore.c creates a semaphore and then calls threads which will contend for the semaphore +** +** This test is for Object Management Test case for semaphore where Object type is shareable. +** Algorithm +** o Main Process Creates OBJECT_TYPE Object +** o Create PROCESS_COUNT processes aware of the Shared Object +** +** +** +**============================================================ +*/ + +#include <palsuite.h> +#include "resulttime.h" + +/* Test Input Variables */ +unsigned int PROCESS_COUNT = 1; +unsigned int THREAD_COUNT = 1; +unsigned int REPEAT_COUNT = 4; +unsigned int RELATION_ID = 1001; + + +unsigned long lInitialCount = 1; /* Signaled */ +unsigned long lMaximumCount = 1; /* Maximum value of 1 */ + +char objectSuffix[MAX_PATH]; + +struct TestStats{ + DWORD operationTime; + unsigned int relationId; + unsigned int processCount; + unsigned int threadCount; + unsigned int repeatCount; + char* buildNumber; + +}; + +int GetParameters( int argc, char **argv) +{ + if( (!((argc == 5) || (argc == 6) ) )|| ((argc == 1) && !strcmp(argv[1],"/?")) + || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H")) + { + printf("PAL -Composite Object Management event Test\n"); + printf("Usage:\n"); + printf("main\n\t[PROCESS_COUNT (greater than 1)] \n"); + printf("\t[THREAD_COUNT (greater than 1)] \n"); + printf("\t[REPEAT_COUNT (greater than 1)]\n"); + printf("\t[RELATION_ID [greater than or equal to 1]\n"); + printf("\t[Object Name Suffix]\n"); + return -1; + } + + PROCESS_COUNT = atoi(argv[1]); + if( (PROCESS_COUNT < 1) || (PROCESS_COUNT > MAXIMUM_WAIT_OBJECTS) ) + { + printf("\nMain Process:Invalid PROCESS_COUNT number, Pass greater than 1 and less than PROCESS_COUNT %d\n", MAXIMUM_WAIT_OBJECTS); + return -1; + } + + THREAD_COUNT = atoi(argv[2]); + if( (THREAD_COUNT < 1) || (THREAD_COUNT > MAXIMUM_WAIT_OBJECTS) ) + { + printf("\nInvalid THREAD_COUNT number, Pass greater than 1 and less than %d\n", MAXIMUM_WAIT_OBJECTS); + return -1; + } + + REPEAT_COUNT = atoi(argv[3]); + if( REPEAT_COUNT < 1) + { + printf("\nMain Process:Invalid REPEAT_COUNT number, Pass greater than 1\n"); + return -1; + } + + RELATION_ID = atoi(argv[4]); + if( RELATION_ID < 1) + { + printf("\nMain Process:Invalid RELATION_ID number, Pass greater than 1\n"); + return -1; + } + + + if(argc == 6) + { + strncpy(objectSuffix, argv[5], MAX_PATH-1); + } + + return 0; +} + + int __cdecl main(INT argc, CHAR **argv) +{ + unsigned int i = 0; + HANDLE hProcess[MAXIMUM_WAIT_OBJECTS]; + HANDLE hSemaphoreHandle; + + STARTUPINFO si[MAXIMUM_WAIT_OBJECTS]; + PROCESS_INFORMATION pi[MAXIMUM_WAIT_OBJECTS]; + + char lpCommandLine[MAX_PATH] = ""; + char ObjName[MAX_PATH] = "SHARED_SEMAPHORE"; + + int returnCode = 0; + DWORD processReturnCode = 0; + int testReturnCode = PASS; + + char fileName[MAX_PATH]; + FILE *pFile = NULL; + DWORD dwStartTime; + struct TestStats testStats; + + if(0 != (PAL_Initialize(argc, argv))) + { + return ( FAIL ); + } + +/* +"While the new PAL does support named semaphore it's unclear +if we should change the Windows PAL, since we share that w/ Rotor +and they are still using the old PAL. For the time being it may +make the most sense to just skip the named semaphore test on Windows +- from an object management perspective it doesn't really gain +us anything over what we already have." +*/ +#ifdef PLATFORM_UNIX + + ZeroMemory( objectSuffix, MAX_PATH ); + + if(GetParameters(argc, argv)) + { + Fail("Error in obtaining the parameters\n"); + } + + if(argc == 6) + { + strncat(ObjName, objectSuffix, MAX_PATH - (sizeof(ObjName) + 1) ); + } + + /* Register the start time */ + dwStartTime = GetTickCount(); + testStats.relationId = RELATION_ID; + testStats.processCount = PROCESS_COUNT; + testStats.threadCount = THREAD_COUNT; + testStats.repeatCount = REPEAT_COUNT; + testStats.buildNumber = getBuildNumber(); + + _snprintf(fileName, MAX_PATH, "main_semaphore_%d_.txt", RELATION_ID); + pFile = fopen(fileName, "w+"); + if(pFile == NULL) + { + Fail("Error in opening main file for write\n"); + } + + hSemaphoreHandle = CreateSemaphore( + NULL, /* lpSemaphoreAttributes */ + lInitialCount, /*lInitialCount*/ + lMaximumCount, /*lMaximumCount */ + ObjName + ); + + if( hSemaphoreHandle == NULL) + { + Fail("Unable to create shared Semaphore handle @ Main returned error [%d]\n", GetLastError()); + } + + for( i = 0; i < PROCESS_COUNT; i++ ) + { + + + ZeroMemory( lpCommandLine, MAX_PATH ); + if ( _snprintf( lpCommandLine, MAX_PATH-1, "semaphore %d %d %d %d %s", i, THREAD_COUNT, REPEAT_COUNT, RELATION_ID, objectSuffix) < 0 ) + { + Fail("Error: Insufficient semaphore name string length for %s for iteration [%d]\n", ObjName, i); + } + + + /* Zero the data structure space */ + ZeroMemory ( &pi[i], sizeof(pi[i]) ); + ZeroMemory ( &si[i], sizeof(si[i]) ); + + /* Set the process flags and standard io handles */ + si[i].cb = sizeof(si[i]); + + if(!CreateProcess( NULL, /* lpApplicationName*/ + lpCommandLine, /* lpCommandLine */ + NULL, /* lpProcessAttributes */ + NULL, /* lpThreadAttributes */ + TRUE, /* bInheritHandles */ + 0, /* dwCreationFlags, */ + NULL, /* lpEnvironment */ + NULL, /* pCurrentDirectory */ + &si[i], /* lpStartupInfo */ + &pi[i] /* lpProcessInformation */ + )) + { + Fail("Process Not created for [%d], the error code is [%d]\n", i, GetLastError()); + } + else + { + hProcess[i] = pi[i].hProcess; +// Trace("Process created for [%d]\n", i); + + } + + } + + returnCode = WaitForMultipleObjects( PROCESS_COUNT, hProcess, TRUE, INFINITE); + if( WAIT_OBJECT_0 != returnCode ) + { + Trace("Wait for Object(s) @ Main thread for %d processes returned %d, and GetLastError value is %d\n", PROCESS_COUNT, returnCode, GetLastError()); + testReturnCode = FAIL; + } + + for( i = 0; i < PROCESS_COUNT; i++ ) + { + /* check the exit code from the process */ + if( ! GetExitCodeProcess( pi[i].hProcess, &processReturnCode ) ) + { + Trace( "GetExitCodeProcess call failed for iteration %d with error code %u\n", + i, GetLastError() ); + + testReturnCode = FAIL; + } + + if(processReturnCode == FAIL) + { + Trace( "Process [%d] failed and returned FAIL\n", i); + testReturnCode = FAIL; + } + + if(!CloseHandle(pi[i].hThread)) + { + Trace("Error:%d: CloseHandle failed for Process [%d] hThread\n", GetLastError(), i); + testReturnCode = FAIL; + } + + if(!CloseHandle(pi[i].hProcess) ) + { + Trace("Error:%d: CloseHandle failed for Process [%d] hProcess\n", GetLastError(), i); + testReturnCode = FAIL; + } + } + + testStats.operationTime = GetTimeDiff(dwStartTime); + fprintf(pFile, "%d,%d,%d,%d,%d,%s\n", testStats.operationTime, testStats.relationId, testStats.processCount, testStats.threadCount, testStats.repeatCount, testStats.buildNumber); + if(fclose(pFile)) + { + Trace("Error: fclose failed for pFile\n"); + testReturnCode = FAIL; + }; + + if(!CloseHandle(hSemaphoreHandle)) + { + Trace("Error:%d: CloseHandle failed for hSemaphoreHandle\n", GetLastError()); + testReturnCode = FAIL; + + } + + if( testReturnCode == PASS) + { + Trace("Test Passed\n"); + } + else + { + Trace("Test Failed\n"); + } + +#endif //PLATFORM_UNIX + PAL_Terminate(); + return testReturnCode; +} diff --git a/src/pal/tests/palsuite/composite/object_management/semaphore/shared/semaphore.c b/src/pal/tests/palsuite/composite/object_management/semaphore/shared/semaphore.c new file mode 100644 index 0000000000..5143c55143 --- /dev/null +++ b/src/pal/tests/palsuite/composite/object_management/semaphore/shared/semaphore.c @@ -0,0 +1,351 @@ +// 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 Code: main.c and semaphore.c +** main.c creates process and waits for all processes to get over +** semaphore.c creates a semaphore and then calls threads which will contend for the semaphore +** +** This test is for Object Management Test case for semaphore where Object type is shareable. +** Algorithm +** o Main Process Creates OBJECT_TYPE Object +** o Create PROCESS_COUNT processes aware of the Shared Object +** +** +** +**============================================================ +*/ + +#include <palsuite.h> +#include "resultbuffer.h" +#include "resulttime.h" + +#define TIMEOUT 5000 +/* Test Input Variables */ +unsigned int USE_PROCESS_COUNT = 0; +unsigned int THREAD_COUNT = 0; +unsigned int REPEAT_COUNT = 0; +unsigned int RELATION_ID= 0; + +/* Capture statistics at per thread basis */ +struct statistics{ + unsigned int processId; + unsigned int operationsFailed; + unsigned int operationsPassed; + unsigned int operationsTotal; + DWORD operationTime; + unsigned int relationId; +}; + +struct ProcessStats{ + unsigned int processId; + DWORD operationTime; + unsigned int relationId; +}; + +/* Semaphore variables */ +unsigned long lInitialCount = 1; /* Signaled */ +unsigned long lMaximumCount = 1; /* Maximum value of 1 */ + +HANDLE StartTestsEvHandle = NULL; +HANDLE hSemaphoreHandle = NULL; + +/* Results Buffer */ +ResultBuffer *resultBuffer = NULL; + +int testStatus; + +const char sTmpEventName[MAX_PATH] = "StartTestEvent"; +char objectSuffix[MAX_PATH]; + +void PALAPI Run_Thread(LPVOID lpParam); + +int GetParameters( int argc, char **argv) +{ + if( (!((argc == 5) || (argc == 6) ) )|| ((argc == 1) && !strcmp(argv[1],"/?")) + || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H")) + { + printf("PAL -Composite Object Management event Test\n"); + printf("Usage:\n"); + printf("main\n\t[PROCESS_COUNT (greater than 1)] \n"); + printf("\t[THREAD_COUNT (greater than 1)] \n"); + printf("\t[REPEAT_COUNT (greater than 1)]\n"); + printf("\t[RELATION_ID [greater than or equal to 1]\n"); + printf("\t[Object Name Suffix]\n"); + return -1; + } + + USE_PROCESS_COUNT = atoi(argv[1]); + if(USE_PROCESS_COUNT < 0) + { + printf("\nMain Process:Invalid PROCESS_COUNT number, Pass greater than 0 \n"); + return -1; + } + + THREAD_COUNT = atoi(argv[2]); + if( (THREAD_COUNT < 1) || (THREAD_COUNT > MAXIMUM_WAIT_OBJECTS) ) + { + printf("\nInvalid THREAD_COUNT number, Pass greater than 1 and less than %d\n", MAXIMUM_WAIT_OBJECTS); + return -1; + } + + REPEAT_COUNT = atoi(argv[3]); + if( REPEAT_COUNT < 1) + { + printf("\nMain Process:Invalid REPEAT_COUNT number, Pass greater than 1\n"); + return -1; + } + + RELATION_ID = atoi(argv[4]); + if( RELATION_ID < 1) + { + printf("\nMain Process:Invalid RELATION_ID number, Pass greater than 1\n"); + return -1; + } + + if(argc == 6) + { + strncpy(objectSuffix, argv[5], MAX_PATH-1); + } + + return 0; +} + + int __cdecl main(INT argc, CHAR **argv) +{ + unsigned int i = 0; + HANDLE hThread[MAXIMUM_WAIT_OBJECTS]; + DWORD threadId[MAXIMUM_WAIT_OBJECTS]; + + char ObjName[MAX_PATH] = "SHARED_SEMAPHORE"; + DWORD dwParam = 0; + + int returnCode = 0; + + /* Variables to capture the file name and the file pointer at thread level*/ + char fileName[MAX_PATH]; + FILE *pFile = NULL; + struct statistics* buffer = NULL; + int statisticsSize = 0; + + /* Variables to capture the file name and the file pointer at process level*/ + char processFileName[MAX_PATH]; + FILE *pProcessFile = NULL; + struct ProcessStats processStats; + DWORD dwStartTime; + + testStatus = PASS; + + ZeroMemory( objectSuffix, MAX_PATH ); + + if(0 != (PAL_Initialize(argc, argv))) + { + return ( FAIL ); + } + + if(GetParameters(argc, argv)) + { + Fail("Error in obtaining the parameters\n"); + } +// Trace("Process created, value of process count is [%d]\n", USE_PROCESS_COUNT); + + if(argc == 6) + { + strncat(ObjName , objectSuffix, MAX_PATH - (sizeof(ObjName) + 1) ); + } + + /* Register the start time */ + dwStartTime = GetTickCount(); + processStats.relationId = RELATION_ID; + processStats.processId = USE_PROCESS_COUNT; + + _snprintf(processFileName, MAX_PATH, "%d_process_semaphore_%d_.txt", USE_PROCESS_COUNT, RELATION_ID); + pProcessFile = fopen(processFileName, "w+"); + if(pProcessFile == NULL) + { + Fail("Error in opening process File file for write for process [%d]\n", USE_PROCESS_COUNT); + } + + statisticsSize = sizeof(struct statistics); + + _snprintf(fileName, MAX_PATH, "%d_thread_semaphore_%d_.txt", USE_PROCESS_COUNT, RELATION_ID); + pFile = fopen(fileName, "w+"); + if(pFile == NULL) + { + Fail("Error in opening file for write for process [%d]\n", USE_PROCESS_COUNT); + } + // For each thread we will log operations failed (int), passed (int), total (int) + // and number of ticks (DWORD) for the operations + resultBuffer = new ResultBuffer( THREAD_COUNT, statisticsSize); + + /* Create Start Tests event */ + StartTestsEvHandle = CreateEvent( NULL, /* lpEventAttributes*/ + TRUE, /* bManualReset */ + FALSE, /* bInitialState */ + NULL); /* name of Event */ + + if( StartTestsEvHandle == NULL ) + { + Fail("Error:%d: Unexpected failure " + "to create %s Event for process count %d\n", GetLastError(), sTmpEventName, USE_PROCESS_COUNT ); + + } + + hSemaphoreHandle = CreateSemaphore( + NULL, /* lpSemaphoreAttributes */ + lInitialCount, /*lInitialCount*/ + lMaximumCount, /*lMaximumCount */ + ObjName + ); + + + if( (hSemaphoreHandle == NULL) || (GetLastError() != ERROR_ALREADY_EXISTS) ) + { + Fail("Unable to create Semaphore handle for process id [%d], returned error [%d], expected ERROR_ALREADY_EXISTS\n", i, GetLastError()); + } + + /* We already assume that the Semaphore was created previously*/ + + for( i = 0; i < THREAD_COUNT; i++ ) + { + dwParam = (int) i; + //Create thread + hThread[i] = CreateThread( + NULL, /* no security attributes */ + 0, /* use default stack size */ + (LPTHREAD_START_ROUTINE)Run_Thread,/* thread function */ + (LPVOID)dwParam, /* argument to thread function */ + 0, /* use default creation flags */ + &threadId[i] /* returns the thread identifier*/ + ); + + if(hThread[i] == NULL) + { + Fail("Create Thread failed for %d process, and GetLastError value is %d\n", USE_PROCESS_COUNT, GetLastError()); + } + } + + if (!SetEvent(StartTestsEvHandle)) + { + Fail("Set Event for Start Tests failed for %d process, and GetLastError value is %d\n", USE_PROCESS_COUNT, GetLastError()); + } + + /* Test running */ + returnCode = WaitForMultipleObjects( THREAD_COUNT, hThread, TRUE, INFINITE); + + if( WAIT_OBJECT_0 != returnCode ) + { + Trace("Wait for Object(s) for %d process returned %d, and GetLastError value is %d\n", USE_PROCESS_COUNT, returnCode, GetLastError()); + testStatus = FAIL; + } + + processStats.operationTime = GetTimeDiff(dwStartTime); + + /* Write to a file*/ + if(pFile!= NULL) + { + for( i = 0; i < THREAD_COUNT; i++ ) + { + buffer = (struct statistics *)resultBuffer->getResultBuffer(i); + returnCode = fprintf(pFile, "%d,%d,%d,%d,%lu,%d\n", buffer->processId, buffer->operationsFailed, buffer->operationsPassed, buffer->operationsTotal, buffer->operationTime, buffer->relationId ); +// Trace("Iteration %d over\n", i); + + } + } + fclose(pFile); + /* Logging for the test case over, clean up the handles */ + +// Trace("Test Thread %d done\n", USE_PROCESS_COUNT); + for( i = 0; i < THREAD_COUNT; i++ ) + { + if(!CloseHandle(hThread[i]) ) + { + Trace("Error:%d: CloseHandle failed for Process [%d] hThread[%d]\n", GetLastError(), USE_PROCESS_COUNT, i); + testStatus = FAIL; + } + } + + if(!CloseHandle(StartTestsEvHandle)) + { + Trace("Error:%d: CloseHandle failed for Process [%d] StartTestsEvHandle\n", GetLastError(), USE_PROCESS_COUNT); + testStatus = FAIL; + } + + if(!CloseHandle(hSemaphoreHandle)) + { + Trace("Error:%d: CloseHandle failed for Process [%d] hSemaphoreHandle\n", GetLastError(), USE_PROCESS_COUNT); + testStatus = FAIL; + } + + PAL_Terminate(); + return PASS; +} + +void PALAPI Run_Thread (LPVOID lpParam) +{ + unsigned int i = 0; + DWORD dwWaitResult; + + int Id=(int)lpParam; + + struct statistics stats; + DWORD dwStartTime; + + stats.relationId = RELATION_ID; + stats.processId = USE_PROCESS_COUNT; + stats.operationsFailed = 0; + stats.operationsPassed = 0; + stats.operationsTotal = 0; + stats.operationTime = 0; + + dwWaitResult = WaitForSingleObject( + StartTestsEvHandle, // handle to start test handle + TIMEOUT); + + if(dwWaitResult != WAIT_OBJECT_0) + { + Fail("Error while waiting for StartTest Event@ thread %d, RC is %d, Error is %d\n", Id, dwWaitResult, GetLastError()); + } + + dwStartTime = GetTickCount(); + + for( i = 0; i < REPEAT_COUNT; i++ ) + { + dwWaitResult = WaitForSingleObject( + hSemaphoreHandle, // handle to Semaphore + TIMEOUT); + + if(dwWaitResult != WAIT_OBJECT_0) + { +// Trace("Error while waiting for onject @ thread %d, # iter %d, RC is %d, Error is %d\n", Id, i, dwWaitResult, GetLastError()); + stats.operationsFailed += 1; + stats.operationsTotal += 1; + testStatus = FAIL; + continue; + } + if (! ReleaseSemaphore(hSemaphoreHandle, 1, NULL)) + { + // Deal with error. + // Trace("Error while releasing Semaphore @ thread %d # iter %d\n", Id, i); + stats.operationsFailed += 1; + stats.operationsTotal += 1; + // Probably need to have while true loop to attempt to release semaphore.. + testStatus = FAIL; + continue; + } + + stats.operationsTotal += 1; + stats.operationsPassed += 1; +// Trace("Successs while releasing Semaphore @ iteration %d -> thread %d -> Process %d\n", i, Id, USE_PROCESS_COUNT); + + } + + stats.operationTime = GetTimeDiff(dwStartTime); + if(resultBuffer->LogResult(Id, (char *)&stats)) + { + Fail("Error:%d: while writing to shared memory, Thread Id is[%d] and Process id is [%d]\n", GetLastError(), Id, USE_PROCESS_COUNT); + } + // Trace("Thread %d over for process %d\n", Id, USE_PROCESS_COUNT); +} |