diff options
Diffstat (limited to 'src/pal/tests/palsuite/composite/wfmo/mutex.c')
-rw-r--r-- | src/pal/tests/palsuite/composite/wfmo/mutex.c | 365 |
1 files changed, 365 insertions, 0 deletions
diff --git a/src/pal/tests/palsuite/composite/wfmo/mutex.c b/src/pal/tests/palsuite/composite/wfmo/mutex.c new file mode 100644 index 0000000000..c8ed01426c --- /dev/null +++ b/src/pal/tests/palsuite/composite/wfmo/mutex.c @@ -0,0 +1,365 @@ +// 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 WFMO Test case for Mutex +** 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" + +/* Test Input Variables */ +unsigned int USE_PROCESS_COUNT = 0; +unsigned int THREAD_COUNT = 0; +unsigned int REPEAT_COUNT = 0; +unsigned int SLEEP_LENGTH = 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 to signal threads to start the tests */ +HANDLE StartTestsEvHandle = NULL; +/* Handle to mutex which will be contended by threads */ +HANDLE hMutexHandle = NULL; +/* Results Buffer */ +ResultBuffer *resultBuffer = NULL; + +int testStatus; + +void PALAPI Run_Thread(LPVOID lpParam); + +int GetParameters( int argc, char **argv) +{ + if( (argc != 6) || ((argc == 1) && !strcmp(argv[1],"/?")) + || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H")) + { + printf("PAL -Composite WFMO Test\n"); + printf("Usage:\n"); + printf("mutex\n\t[USE_PROCESS_COUNT [greater than 0] \n"); + printf("\t[THREAD_COUNT [greater than 0] \n"); + printf("\t[REPEAT_COUNT [greater than 0]\n"); + printf("\t[SLEEP_LENGTH [greater than 0]\n"); + printf("\t[RELATION_ID [greater than 0]\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; + } + + SLEEP_LENGTH = atoi(argv[4]); + if( SLEEP_LENGTH < 1) + { + printf("\nMain Process:Invalid SLEEP_LENGTH number, Pass greater than 1\n"); + return -1; + } + + RELATION_ID = atoi(argv[5]); + 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_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] and no. of threads is [%d]\n", USE_PROCESS_COUNT, THREAD_COUNT); + + /* Register the start time */ + dwStartTime = GetTickCount(); + processStats.relationId = RELATION_ID; + processStats.processId = USE_PROCESS_COUNT; + + _snprintf(processFileName, MAX_PATH, "%d_process_wfmo_%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_wfmo_%d_.txt", USE_PROCESS_COUNT, RELATION_ID); + pFile = fopen(fileName, "w+"); + if(pFile == NULL) + { + Fail("Error in opening file for write for process [%d], error [%d]\n", USE_PROCESS_COUNT, GetLastError()); + } + // 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 start tests Event for process count %d\n", GetLastError(), 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 */ + + if( THREAD_COUNT != 1 ) + { + returnCode = WaitForMultipleObjects(THREAD_COUNT, hThread, TRUE, INFINITE); + } + else + { + returnCode = WaitForSingleObject(hThread[0], 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 Process %d done\n", USE_PROCESS_COUNT); + //Trace("Contents of the buffer are [%s]\n", resultBuffer->getResultBuffer()); + 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; + } + + PAL_Terminate(); + return testStatus; +} + +void PALAPI Run_Thread (LPVOID lpParam) +{ + unsigned int i = 0; + struct statistics stats; + + DWORD dwWaitResult; + 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 + INFINITE); + + if(dwWaitResult != WAIT_OBJECT_0) + { + Trace("Error:%d: while waiting for StartTest Event@ thread %d\n", GetLastError(), Id); + testStatus = FAIL; + } + + /* Register the start time */ + dwStartTime = GetTickCount(); + + /* Run the tests repeat count times */ + for( i = 0; i < REPEAT_COUNT; i++ ) + { + dwWaitResult = WaitForSingleObject( + hMutexHandle, // handle to mutex + INFINITE); + + 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; + } + + Sleep(SLEEP_LENGTH); + + if (!ReleaseMutex(hMutexHandle)) + { + // Deal with error. + Trace("Error:%d: while releasing mutex @ thread %d # iter %d\n", GetLastError(), Id, i); + stats.operationsFailed += 1; + stats.operationsTotal += 1; + // do we 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 %lu, Process Count [%d], ThreadCount[%d]\n", stats.operationTime, USE_PROCESS_COUNT, Id); + + 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("Contents of the buffer are after thread [%d]\n", Id); +} |