summaryrefslogtreecommitdiff
path: root/src/pal/tests/palsuite/composite/threading/threadsuspension_switchthread/threadsuspension.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/pal/tests/palsuite/composite/threading/threadsuspension_switchthread/threadsuspension.cpp')
-rw-r--r--src/pal/tests/palsuite/composite/threading/threadsuspension_switchthread/threadsuspension.cpp914
1 files changed, 914 insertions, 0 deletions
diff --git a/src/pal/tests/palsuite/composite/threading/threadsuspension_switchthread/threadsuspension.cpp b/src/pal/tests/palsuite/composite/threading/threadsuspension_switchthread/threadsuspension.cpp
new file mode 100644
index 0000000000..a117b86174
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/threading/threadsuspension_switchthread/threadsuspension.cpp
@@ -0,0 +1,914 @@
+// 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: \composite\threading\threadsuspension\threadsuspension.c
+**
+** Purpose: To verify Thread Suspension Reegneering effort for this milestone
+
+ PsedoCode:
+
+ Preparation:
+ Create PROCESS_COUNT processes.
+ Test:
+ Create Worker Thread
+ Start Reading and writing to a File
+
+ Create Worker Thread
+ In an infinite loop do the following
+ Enter Critical Section
+ Increment Counter
+ Leave Critical Section
+
+ Create Worker Thread
+ Allocate Memory and Free Memory
+
+ Create Worker Thread
+ In a tight loop add numbers
+
+ In a loop repeated REPEAT_COUNT times
+
+ Create Thread
+
+ Suspend all worker threads
+ Resume all worker threads
+
+ At the end of the loop call PAL_Shutdown
+
+ Parameters:
+ PROCESS_COUNT: Number of processes
+ WORKER_THREAD_MULTIPLIER_COUNT: Number of instances of worker threads in each process
+ REPEAT_COUNT: The number of times to execute the loop.
+
+ Statistics Captured:
+ Total elapsed time
+ MTBF
+
+
+ Scenario:
+**
+ One thread suspends all remaining threads which are in the middle of doing some work and resume all threads
+ Thread 1: Reading and Writing File
+ Thread 2: Enter and Leave Critical Section
+ Thread 3: Allocating chunks of memory
+ Thread 4: Perform Unsafe Operation (printf, malloc)
+ Thread 5: Suspends Thread 1 to Thread 4 and resumes them
+
+**
+**
+**
+** Dependencies:
+**
+**
+
+**
+**=========================================================*/
+
+#include <palsuite.h>
+#include "resultbuffer.h"
+
+#define BUFSIZE 4096
+#define NUMBER_OF_WORKER_THREAD_TYPES 4
+#define THREAD_MAX 64
+
+#define TEST_FAIL 1
+#define TEST_PASS 0
+
+
+DWORD GLOBAL_COUNTER ;
+DWORD UNIQUE_FILE_NUMBER=0;
+HANDLE g_hEvent;
+
+bool failFlag = false; //To Track failure at the Operation Level
+
+// 2 dimensional array to hold thread handles for each worker thread
+HANDLE hThread[NUMBER_OF_WORKER_THREAD_TYPES][THREAD_MAX];
+
+/*unsigned int g_readfileoperation;
+unsigned int g_enterleavecsoperation;
+unsigned int g_allocatefreeoperation;
+unsigned int g_doworintightloop;
+*/
+
+int TYPES_OF_WORKER_THREAD = NUMBER_OF_WORKER_THREAD_TYPES;
+
+int testStatus=TEST_PASS; //Indicates test failure
+
+
+struct statistics{
+ unsigned int processId;
+ unsigned int operationsFailed;
+ unsigned int operationsPassed;
+ unsigned int operationsTotal;
+ DWORD operationTime;
+ unsigned int relationId;
+};
+
+struct processStatistics{
+ unsigned int processId;
+ DWORD operationTime;
+ unsigned int relationId;
+};
+
+/* Results Buffer */
+ResultBuffer *resultBuffer;
+
+
+/* Test Input Variables */
+unsigned int USE_PROCESS_COUNT = 0; //Identifies the Process number. There could potentially
+unsigned int WORKER_THREAD_MULTIPLIER_COUNT = 0; //In this test case this represents the number of worker thread instances
+unsigned int REPEAT_COUNT = 0; //Number of Suspend Resume operation of worker threads
+unsigned int RELATION_ID = 0;
+
+
+
+CRITICAL_SECTION CriticalSectionM; /* Critical Section Object (used as mutex) */
+CRITICAL_SECTION g_csUniqueFileName;
+
+void PALAPI setup(void);
+void PALAPI cleanup(void);
+void PALAPI incrementCounter(void);
+DWORD PALAPI readfile( LPVOID);
+DWORD PALAPI enterandleave_cs( LPVOID);
+DWORD PALAPI allocateandfree_memory( LPVOID);
+DWORD PALAPI doworkintightloop_cs( LPVOID);
+DWORD PALAPI suspendandresumethreads( LPVOID);
+int GetParameters(int, char * *);
+
+
+//Main Entry for the Thread Suspension Test Case
+int __cdecl main (int argc, char **argv)
+{
+
+/*
+* Parameter to the threads that will be created
+*/
+
+
+DWORD dwThrdParam = 0;
+DWORD dwStart;
+
+/* Variables to capture the file name and the file pointer*/
+char fileName[MAX_PATH];
+char processFileName[MAX_PATH];
+
+FILE *hFile, *hProcessFile;
+struct statistics* buffer;
+struct processStatistics *processBuffer;
+
+struct processStatistics processStats;
+
+struct statistics* tmpBuf = NULL;
+int statisticsSize = 0;
+
+DWORD dwThreadId=0;
+HANDLE hMainThread;
+unsigned int i = 0;
+int j = 0;
+
+
+/*
+* PAL Initialize
+*/
+
+if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+
+//Get Parameters
+if(GetParameters(argc, argv))
+ {
+ Fail("Error in obtaining the parameters\n");
+ }
+
+
+//Setup for Process Result Collection
+statisticsSize = sizeof(struct statistics);
+_snprintf(processFileName, MAX_PATH, "%d_process_threadsuspension_%d_.txt", USE_PROCESS_COUNT, RELATION_ID);
+hProcessFile = fopen(processFileName, "w+");
+
+if(hProcessFile == NULL)
+ {
+ Fail("Error in opening file to write process results for process [%d]\n", USE_PROCESS_COUNT);
+ }
+
+//Initialize Process Stats Variables
+processStats.operationTime = 0;
+processStats.processId = USE_PROCESS_COUNT;
+processStats.relationId = RELATION_ID;
+
+//Start Process Time Capture
+dwStart = GetTickCount();
+
+//Setup for Thread Result Collection
+statisticsSize = sizeof(struct statistics);
+_snprintf(fileName, MAX_PATH, "%d_thread_threadsuspension_%d_.txt", USE_PROCESS_COUNT,RELATION_ID);
+hFile = fopen(fileName, "w+");
+
+if(hFile == NULL)
+ {
+ Fail("Error in opening file to write thread results for process [%d]\n", USE_PROCESS_COUNT);
+ }
+
+// For each thread we will log relationid (int), processid (int), operations failed (int), passed (int), total (int)
+// and number of ticks (DWORD) for the operations
+resultBuffer = new ResultBuffer( 1, statisticsSize);
+
+/*
+* Call the Setup Routine
+*/
+setup();
+
+Trace("WORKER_THREAD_MULTIPLIER_COUNT: %d \n", WORKER_THREAD_MULTIPLIER_COUNT);
+
+//Create WORKER_THREAD_MULTIPLIER_COUNT Instances of each type of worker thread
+for (i=0;i<WORKER_THREAD_MULTIPLIER_COUNT;i++)
+{
+
+ /*
+ * Create readfile thread
+ */
+ hThread[0][i] = CreateThread(
+ NULL,
+ 0,
+ readfile,
+ NULL,
+ 0,
+ &dwThreadId);
+
+ if ( NULL == hThread[0][i] )
+ {
+ Fail ( "CreateThread() returned NULL. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+
+
+ /*
+ * Create Enter and Leave Critical Section Thread
+ */
+ hThread[1][i] = CreateThread(
+ NULL,
+ 0,
+ enterandleave_cs,
+ NULL,
+ 0,
+ &dwThreadId);
+
+ if ( NULL == hThread[1][i] )
+ {
+ Fail ( "CreateThread() returned NULL. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+
+
+ /*
+ * Create Allocate and Free Memory Thread
+ */
+ hThread[2][i] = CreateThread(
+ NULL,
+ 0,
+ allocateandfree_memory,
+ NULL,
+ 0,
+ &dwThreadId);
+
+ if ( NULL == hThread[2][i])
+ {
+ Fail ( "CreateThread() returned NULL. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+
+
+ /*
+ * Create Work in tight Loop thread
+ */
+ hThread[3][i] = CreateThread(
+ NULL,
+ 0,
+ doworkintightloop_cs,
+ NULL,
+ 0,
+ &dwThreadId);
+
+ if ( NULL == hThread[3][i])
+ {
+ Fail ( "CreateThread() returned NULL. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+
+
+}
+
+
+
+
+
+/*
+ * Create Main test case thread that Suspends and Resumes Threads
+ */
+ hMainThread = CreateThread(
+ NULL,
+ 0,
+ suspendandresumethreads,
+ (LPVOID)dwThrdParam,
+ 0,
+ &dwThreadId);
+
+ if ( NULL == hMainThread )
+ {
+ Fail ( "CreateThread() returned NULL. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+
+
+
+/*
+* Set Event to allow all threads to start
+*/
+
+if (0==SetEvent(g_hEvent))
+{
+ Fail ( "SetEvent returned Zero. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+}
+
+/*
+ * Wait for main thread to complete
+ *
+ */
+ if (WAIT_OBJECT_0 != WaitForSingleObject (hMainThread, INFINITE))
+ {
+ Fail ("Main: Wait for Single Object (mainThread) failed. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+//Get the end time of the process
+processStats.operationTime = GetTickCount() - dwStart;
+
+//Write Process Result Contents to File
+if(hProcessFile!= NULL)
+ {
+ fprintf(hProcessFile, "%d,%lu,%d\n", processStats.processId, processStats.operationTime, processStats.relationId );
+ }
+
+if (0!=fclose(hProcessFile))
+{
+ Fail("Unable to write process results to file"
+ "GetLastError returned %d\n", GetLastError());
+}
+
+
+//Write to log file
+//Trace("# of Read File Operations %d\n", g_readfileoperation);
+//Trace("# of Enter and Leace CS Operations %d\n", g_enterleavecsoperation);
+//Trace("# of Do Work In Tight Loop Operations %d\n", g_doworintightloop);
+//Trace("# of Allocate and Free Operations %d\n", g_allocatefreeoperation);
+
+
+//Write Thread Result Contents to File
+if(hFile!= NULL)
+ {
+ for( i = 0; i < 1; i++ )
+ {
+ buffer = (struct statistics *)resultBuffer->getResultBuffer(i);
+ fprintf(hFile, "%d,%d,%d,%d,%lu,%d\n", buffer->processId, buffer->operationsFailed, buffer->operationsPassed, buffer->operationsTotal, buffer->operationTime, buffer->relationId );
+ }
+ }
+
+if (0!=fclose(hFile))
+{
+ Fail("Unable to write thread results to file"
+ "GetLastError returned %d\n", GetLastError());
+}
+
+cleanup();
+
+if (failFlag == TRUE)
+{
+ return FAIL;
+}
+else
+{
+ return PASS;
+}
+}
+
+
+/*
+* Setup for the test case
+*/
+
+VOID
+setup(VOID)
+{
+ /*Delete All Temporary Files Created by the previous execution of the test case*/
+ HANDLE hSearch;
+ BOOL fFinished = FALSE;
+ WIN32_FIND_DATA FileData;
+
+ //Start searching for .tmp files in the current directory.
+ hSearch = FindFirstFile("*.tmp*", &FileData);
+ if (hSearch == INVALID_HANDLE_VALUE)
+ {
+ //No Files That Matched Criteria
+ fFinished = TRUE;
+ }
+
+ //Delete all files that match the pattern
+ while (!fFinished)
+ {
+ if (!DeleteFile(FileData.cFileName))
+ {
+ Trace("Setup: Could not delete temporary file %s\n",FileData.cFileName );
+ Fail ("GetLastError returned %d\n", GetLastError());
+ }
+ if (!FindNextFile(hSearch, &FileData))
+ {
+ if (GetLastError() == ERROR_NO_MORE_FILES)
+ {
+ fFinished = TRUE;
+ }
+ else
+ {
+ Fail("Unable to Delete Temporary Files, GetLastError is %d \n", GetLastError());
+ }
+ }
+ }
+
+ // Close the search handle, only if HANDLE is Valid
+ if (hSearch != INVALID_HANDLE_VALUE)
+ {
+ if (!FindClose(hSearch))
+ {
+ Trace("Setup: Could not close search handle \n");
+ Fail ("GetLastError returned %d\n", GetLastError());
+ }
+ }
+
+ g_hEvent = CreateEvent(NULL,TRUE,FALSE, NULL);
+ if(g_hEvent == NULL)
+ {
+ Fail("Create Event Failed\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ InitializeCriticalSection ( &g_csUniqueFileName);
+}
+
+/*
+* Cleanup for the test case
+*/
+
+VOID
+cleanup(VOID)
+{
+ //DeleteCriticalSection(&g_csUniqueFileName);
+ PAL_Terminate();
+}
+
+
+VOID
+incrementCounter(VOID)
+{
+
+ if (INT_MAX == GLOBAL_COUNTER)
+ {
+ GLOBAL_COUNTER = 0;
+ }
+
+ GLOBAL_COUNTER++;
+}
+
+/*
+ * Worker Thread
+ * Read File: Read from a file and write to a temporary file and then delete the temp file
+ */
+DWORD
+PALAPI
+readfile( LPVOID lpParam )
+{
+
+ // Declaring Local Variables
+ HANDLE hFile,hTempfile;
+ char buffer[BUFSIZE];
+ DWORD dwBytesRead, dwBytesWritten, dwBufSize=BUFSIZE;
+ DWORD dwWaitResult=0;
+ char filename[MAX_PATH];
+
+ //Wait for event to signal to start test
+ dwWaitResult = WaitForSingleObject(g_hEvent,INFINITE);
+ if (WAIT_OBJECT_0 != dwWaitResult)
+ {
+ Fail ("readfile: Wait for Single Object (g_hEvent) failed. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+
+ /*Start Operation*/
+
+ // Open the existing file.
+ while(TRUE)
+ {
+
+ hFile = CreateFile("samplefile.dat", // file name
+ GENERIC_READ, // open for reading
+ FILE_SHARE_READ, // Share the file for read
+ NULL, // default security
+ OPEN_EXISTING, // existing file only
+ FILE_ATTRIBUTE_NORMAL, // normal file
+ NULL); // no template
+
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Trace("Could not open file \n");
+ Fail ( "GetLastError returned %d\n", GetLastError());
+ }
+
+ //Generate Unique File Name to Write
+ //Enter CS
+ EnterCriticalSection(&g_csUniqueFileName);
+
+ //Increment Number and assign to local variable
+ UNIQUE_FILE_NUMBER++;
+ _snprintf(filename, MAX_PATH, "%d_%d_tempfile.tmp", USE_PROCESS_COUNT,UNIQUE_FILE_NUMBER);
+ //filename = itoa(UNIQUE_FILE_NUMBER);
+ //Leave CS
+ LeaveCriticalSection(&g_csUniqueFileName);
+
+
+ // Create a temporary file with name generate above
+ hTempfile = CreateFile(filename, // file name
+ GENERIC_WRITE, // open for read/write
+ 0, // do not share
+ NULL, // default security
+ CREATE_ALWAYS, // overwrite existing file
+ FILE_ATTRIBUTE_NORMAL, // normal file
+ NULL); // no template
+
+
+ if (hTempfile == INVALID_HANDLE_VALUE)
+ {
+ Trace("Could not create temporary file\n");
+ Fail ( "GetLastError returned %d\n", GetLastError());
+ }
+
+ // Read 4K blocks to the buffer.
+ // Change all characters in the buffer to upper case.
+ // Write the buffer to the temporary file.
+
+ do
+ {
+ if (ReadFile(hFile, buffer, 4096,
+ &dwBytesRead, NULL))
+ {
+
+ WriteFile(hTempfile, buffer, dwBytesRead,
+ &dwBytesWritten, NULL);
+ }
+ } while (dwBytesRead == BUFSIZE);
+
+
+
+ // Close both files.
+ if (0==CloseHandle(hFile))
+ {
+ Trace("Could not handle hFile\n");
+ Fail ( "GetLastError returned %d\n", GetLastError());
+ }
+
+ if (0==CloseHandle(hTempfile))
+ {
+ Trace("Could not handle hTempFile\n");
+ Fail ( "GetLastError returned %d\n", GetLastError());
+ }
+
+ //Delete the file that was created
+ if (!DeleteFile(filename))
+ {
+ Trace("Could not delete temporary file %s\n", filename);
+ Fail ( "GetLastError returned %d\n", GetLastError());
+
+ }
+
+ SwitchToThread();
+ //g_readfileoperation++;
+ }
+
+/*End Operation*/
+
+ return 0;
+}
+
+
+/* Worker Thread
+ * Enter and Leave Nested Critical Sections
+ */
+DWORD
+PALAPI
+enterandleave_cs( LPVOID lpParam )
+{
+
+ //Declare Local Variables
+
+ CRITICAL_SECTION lcs;
+ CRITICAL_SECTION lcsNested;
+
+ DWORD dwWaitResult;
+
+ //Intialize Critical Section Structures
+ InitializeCriticalSection ( &lcs);
+ InitializeCriticalSection ( &lcsNested);
+
+
+ //Wait for event to signal to start test
+ dwWaitResult = WaitForSingleObject(g_hEvent,INFINITE);
+ if (WAIT_OBJECT_0 != dwWaitResult)
+ {
+ Fail ("enterandleave_cs: Wait for Single Object (g_hEvent) failed. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ //Trace("Critical Section Started\n");
+
+ while(TRUE)
+ {
+ EnterCriticalSection(&lcs);
+
+ EnterCriticalSection(&lcsNested);
+
+ incrementCounter();
+
+ LeaveCriticalSection(&lcsNested);
+
+ LeaveCriticalSection(&lcs);
+
+ SwitchToThread();
+ //g_enterleavecsoperation++;
+ }
+
+ //Delete Critical Section Structures
+
+ DeleteCriticalSection(&lcs);
+ DeleteCriticalSection(&lcsNested);
+
+
+ return 0;
+}
+
+
+/*
+ * Allocate and Free Memory
+ */
+DWORD
+PALAPI
+allocateandfree_memory( LPVOID lpParam )
+{
+
+
+ int i;
+ char *textArrPtr[64];
+ DWORD dwWaitResult;
+
+ //Wait for event to signal to start test
+ dwWaitResult = WaitForSingleObject(g_hEvent,INFINITE);
+ if (WAIT_OBJECT_0 != dwWaitResult)
+ {
+ Fail ("allocateandfree_memory: Wait for Single Object (g_hEvent) failed. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+
+ while(TRUE)
+ {
+
+ //do allocate and free operation
+
+ for (i=0;i<64;i++)
+ {
+ textArrPtr[i] = (char*) malloc(BUFSIZE);
+ if (textArrPtr[i] == NULL)
+ {
+ Fail("Insufficient Memory Available, GetLastError is %d \n", GetLastError());
+ testStatus = TEST_FAIL;
+ }
+ }
+
+ for (i=0;i<64;i++)
+ {
+ free(textArrPtr[i]);
+ }
+
+ SwitchToThread();
+ //g_allocatefreeoperation++;
+ }
+
+
+
+
+ return 0;
+}
+
+/*
+ * Do work in a tight loop
+ */
+DWORD
+PALAPI
+doworkintightloop_cs( LPVOID lpParam )
+{
+
+ unsigned int i;
+ DWORD dwWaitResult;
+
+ //Wait for event to signal to start test
+ dwWaitResult = WaitForSingleObject(g_hEvent,INFINITE);
+ if (WAIT_OBJECT_0 != dwWaitResult)
+ {
+ Fail ("doworkintightloop_cs: Wait for Single Object (g_hEvent) failed. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ i= 0;
+ while (TRUE)
+ {
+
+ if (INT_MAX == i)
+ i =0;
+ i++;
+ //g_doworintightloop++;
+
+ SwitchToThread();
+ }
+
+ return 0;
+}
+
+
+/*
+ * Main Test Case worker thread which will suspend and resume all other worker threads
+ */
+DWORD
+PALAPI
+suspendandresumethreads( LPVOID lpParam )
+{
+
+ unsigned int loopcount = REPEAT_COUNT;
+ int Id=(int)lpParam;
+ unsigned int i,j,k;
+ DWORD dwStart;
+ DWORD dwWaitResult=0;
+ DWORD dwLastError = 0;
+ struct statistics stats;
+ struct statistics* buffer;
+
+
+
+ //Initialize the Statistics Structure
+ stats.relationId = RELATION_ID;
+ stats.processId = USE_PROCESS_COUNT;
+ stats.operationsFailed = 0;
+ stats.operationsPassed = 0;
+ stats.operationsTotal = 0;
+ stats.operationTime = 0;
+
+
+
+ //Wait for event to signal to start test
+ WaitForSingleObject(g_hEvent,INFINITE);
+ if (WAIT_OBJECT_0 != dwWaitResult)
+ {
+ Fail ("suspendandresumethreads: Wait for Single Object (g_hEvent) failed. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+
+ //Capture Start Import
+ dwStart = GetTickCount();
+
+ for(i = 0; i < loopcount; i++)
+ {
+
+ failFlag = false;
+
+ //Suspend Worker Threads
+ for (k=0;k<WORKER_THREAD_MULTIPLIER_COUNT;k++)
+ {
+ for (j=0;j<4;j++)
+ {
+ if (-1 == SuspendThread(hThread[j][k]))
+ {
+ //If the operation indicate failure
+ failFlag = true;
+ }
+ }
+ }
+
+
+ //Resume Worker Threads
+ for (k=0;k<WORKER_THREAD_MULTIPLIER_COUNT;k++)
+ {
+ for (j=0;j<4;j++)
+ {
+
+ //Only suspend if not already in suspended state
+
+ if (-1 == ResumeThread(hThread[j][k]))
+ {
+ //If the operation indicate failure
+ failFlag = true;
+ }
+
+ }
+ }
+
+
+ //Check for Fail Flag. If set increment number of failures
+ // If Fail flag not set then increment number of operations and number of passe
+ if (failFlag == true)
+ {
+ stats.operationsFailed++;
+ }
+ else
+ {
+ stats.operationsPassed +=1;
+
+ }
+ stats.operationsTotal +=1;
+
+ }
+
+ stats.operationTime = GetTickCount() - dwStart;
+
+ /*Trace("\n\n\n\nOperation Time: %d milliseconds\n", stats.operationTime);
+ Trace("Operation Passed: %d\n", stats.operationsPassed);
+ Trace("Operation Total: %d\n", stats.operationsTotal);
+ Trace("Operation Failed: %d\n", stats.operationsFailed);
+ */
+ if(resultBuffer->LogResult(Id, (char *)&stats))
+ {
+ Fail("Error while writing to shared memory, Thread Id is[%d] and Process id is [%d]\n", Id, USE_PROCESS_COUNT);
+ }
+
+ buffer = (struct statistics *)resultBuffer->getResultBuffer(Id);
+ //Trace("\n%d,%d,%d,%lu\n", buffer->operationsFailed, buffer->operationsPassed, buffer->operationsTotal, buffer->operationTime );
+
+
+ return 0;
+}
+
+
+
+int GetParameters( int argc, char **argv)
+{
+
+ if( (argc != 5) || ((argc == 1) && !strcmp(argv[1],"/?"))
+ || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H"))
+ {
+ Trace("PAL -Composite Thread Suspension Test\n");
+ Trace("Usage:\n");
+ Trace("\t[PROCESS_COUNT] Greater than or Equal to 1 \n");
+ Trace("\t[WORKER_THREAD_MULTIPLIER_COUNT] Greater than or Equal to 1 and Less than or Equal to 64 \n");
+ Trace("\t[REPEAT_COUNT] Greater than or Equal to 1\n");
+ Trace("\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)
+ {
+ Trace("\nPROCESS_COUNT to greater than or equal to 1\n");
+ return -1;
+ }
+
+ WORKER_THREAD_MULTIPLIER_COUNT = atoi(argv[2]);
+ if( WORKER_THREAD_MULTIPLIER_COUNT < 1 || WORKER_THREAD_MULTIPLIER_COUNT > 64)
+ {
+ Trace("\nWORKER_THREAD_MULTIPLIER_COUNT to be greater than or equal to 1 or less than or equal to 64\n");
+ return -1;
+ }
+
+ REPEAT_COUNT = atoi(argv[3]);
+ if( REPEAT_COUNT < 1)
+ {
+ Trace("\nREPEAT_COUNT to greater than or equal to 1\n");
+ return -1;
+ }
+
+ RELATION_ID = atoi(argv[4]);
+ if( RELATION_ID < 1)
+ {
+ Trace("\nRELATION_ID to be greater than or equal to 1\n");
+ return -1;
+ }
+ return 0;
+}