summaryrefslogtreecommitdiff
path: root/Build/source/libs/icu/icu-50.1/test/threadtest/threadtest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/icu/icu-50.1/test/threadtest/threadtest.cpp')
-rw-r--r--Build/source/libs/icu/icu-50.1/test/threadtest/threadtest.cpp537
1 files changed, 537 insertions, 0 deletions
diff --git a/Build/source/libs/icu/icu-50.1/test/threadtest/threadtest.cpp b/Build/source/libs/icu/icu-50.1/test/threadtest/threadtest.cpp
new file mode 100644
index 00000000000..85e53a552a4
--- /dev/null
+++ b/Build/source/libs/icu/icu-50.1/test/threadtest/threadtest.cpp
@@ -0,0 +1,537 @@
+//
+//********************************************************************
+// Copyright (C) 2002-2011, International Business Machines
+// Corporation and others. All Rights Reserved.
+//********************************************************************
+//
+// File threadtest.cpp
+//
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "unicode/utypes.h"
+#include "unicode/uclean.h"
+#include "umutex.h"
+#include "threadtest.h"
+
+AbstractThreadTest::~AbstractThreadTest() {}
+
+//------------------------------------------------------------------------------
+//
+// Factory functions for creating different test types.
+//
+//------------------------------------------------------------------------------
+extern AbstractThreadTest *createStringTest();
+extern AbstractThreadTest *createConvertTest();
+
+
+
+//------------------------------------------------------------------------------
+//
+// Windows specific code for starting threads
+//
+//------------------------------------------------------------------------------
+#if U_PLATFORM_USES_ONLY_WIN32_API
+
+#include "Windows.h"
+#include "process.h"
+
+
+
+typedef void (*ThreadFunc)(void *);
+
+class ThreadFuncs // This class isolates OS dependent threading
+{ // functions from the rest of ThreadTest program.
+public:
+ static void Sleep(int millis) {::Sleep(millis);};
+ static void startThread(ThreadFunc, void *param);
+ static unsigned long getCurrentMillis();
+ static void yield() {::Sleep(0);};
+};
+
+void ThreadFuncs::startThread(ThreadFunc func, void *param)
+{
+ unsigned long x;
+ x = _beginthread(func, 0x10000, param);
+ if (x == -1)
+ {
+ fprintf(stderr, "Error starting thread. Errno = %d\n", errno);
+ exit(-1);
+ }
+}
+
+unsigned long ThreadFuncs::getCurrentMillis()
+{
+ return (unsigned long)::GetTickCount();
+}
+
+
+
+
+// #elif defined (POSIX)
+#else
+
+//------------------------------------------------------------------------------
+//
+// UNIX specific code for starting threads
+//
+//------------------------------------------------------------------------------
+#include <pthread.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sched.h>
+#include <sys/timeb.h>
+
+
+extern "C" {
+
+
+typedef void (*ThreadFunc)(void *);
+typedef void *(*pthreadfunc)(void *);
+
+class ThreadFuncs // This class isolates OS dependent threading
+{ // functions from the rest of ThreadTest program.
+public:
+ static void Sleep(int millis);
+ static void startThread(ThreadFunc, void *param);
+ static unsigned long getCurrentMillis();
+ static void yield() {sched_yield();};
+};
+
+void ThreadFuncs::Sleep(int millis)
+{
+ int seconds = millis/1000;
+ if (seconds <= 0) seconds = 1;
+ ::sleep(seconds);
+}
+
+
+void ThreadFuncs::startThread(ThreadFunc func, void *param)
+{
+ unsigned long x;
+
+ pthread_t tId;
+ //thread_t tId;
+#if defined(_HP_UX) && defined(XML_USE_DCE)
+ x = pthread_create( &tId, pthread_attr_default, (pthreadfunc)func, param);
+#else
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ x = pthread_create( &tId, &attr, (pthreadfunc)func, param);
+#endif
+ if (x == -1)
+ {
+ fprintf(stderr, "Error starting thread. Errno = %d\n", errno);
+ exit(-1);
+ }
+}
+
+unsigned long ThreadFuncs::getCurrentMillis() {
+ timeb aTime;
+ ftime(&aTime);
+ return (unsigned long)(aTime.time*1000 + aTime.millitm);
+}
+}
+
+
+// #else
+// #error This platform is not supported
+#endif
+
+
+
+//------------------------------------------------------------------------------
+//
+// struct runInfo Holds the info extracted from the command line and data
+// that is shared by all threads.
+// There is only one of these, and it is static.
+// During the test, the threads will access this info without
+// any synchronization.
+//
+//------------------------------------------------------------------------------
+const int MAXINFILES = 25;
+struct RunInfo
+{
+ bool quiet;
+ bool verbose;
+ int numThreads;
+ int totalTime;
+ int checkTime;
+ AbstractThreadTest *fTest;
+ bool stopFlag;
+ bool exitFlag;
+ int32_t runningThreads;
+};
+
+
+//------------------------------------------------------------------------------
+//
+// struct threadInfo Holds information specific to an individual thread.
+// One of these is set up for each thread in the test.
+// The main program monitors the threads by looking
+// at the status stored in these structs.
+//
+//------------------------------------------------------------------------------
+struct ThreadInfo
+{
+ bool fHeartBeat; // Set true by the thread each time it finishes
+ // a test.
+ unsigned int fCycles; // Number of cycles completed.
+ int fThreadNum; // Identifying number for this thread.
+ ThreadInfo() {
+ fHeartBeat = false;
+ fCycles = 0;
+ fThreadNum = -1;
+ }
+};
+
+
+//
+//------------------------------------------------------------------------------
+//
+// Global Data
+//
+//------------------------------------------------------------------------------
+RunInfo gRunInfo;
+ThreadInfo *gThreadInfo;
+UMTX gStopMutex; // Lets main thread suspend test threads.
+UMTX gInfoMutex; // Synchronize access to data passed between
+ // worker threads and the main thread
+
+
+//----------------------------------------------------------------------
+//
+// parseCommandLine Read through the command line, and save all
+// of the options in the gRunInfo struct.
+//
+// Display the usage message if the command line
+// is no good.
+//
+// Probably ought to be a member function of RunInfo.
+//
+//----------------------------------------------------------------------
+
+void parseCommandLine(int argc, char **argv)
+{
+ gRunInfo.quiet = false; // Set up defaults for run.
+ gRunInfo.verbose = false;
+ gRunInfo.numThreads = 2;
+ gRunInfo.totalTime = 0;
+ gRunInfo.checkTime = 10;
+
+ try // Use exceptions for command line syntax errors.
+ {
+ int argnum = 1;
+ while (argnum < argc)
+ {
+ if (strcmp(argv[argnum], "-quiet") == 0)
+ gRunInfo.quiet = true;
+ else if (strcmp(argv[argnum], "-verbose") == 0)
+ gRunInfo.verbose = true;
+ else if (strcmp(argv[argnum], "--help") == 0 ||
+ (strcmp(argv[argnum], "?") == 0)) {throw 1; }
+
+ else if (strcmp(argv[argnum], "-threads") == 0)
+ {
+ ++argnum;
+ if (argnum >= argc)
+ throw 1;
+ gRunInfo.numThreads = atoi(argv[argnum]);
+ if (gRunInfo.numThreads < 0)
+ throw 1;
+ }
+ else if (strcmp(argv[argnum], "-time") == 0)
+ {
+ ++argnum;
+ if (argnum >= argc)
+ throw 1;
+ gRunInfo.totalTime = atoi(argv[argnum]);
+ if (gRunInfo.totalTime < 1)
+ throw 1;
+ }
+ else if (strcmp(argv[argnum], "-ctime") == 0)
+ {
+ ++argnum;
+ if (argnum >= argc)
+ throw 1;
+ gRunInfo.checkTime = atoi(argv[argnum]);
+ if (gRunInfo.checkTime < 1)
+ throw 1;
+ }
+ else if (strcmp(argv[argnum], "string") == 0)
+ {
+ gRunInfo.fTest = createStringTest();
+ }
+ else if (strcmp(argv[argnum], "convert") == 0)
+ {
+ gRunInfo.fTest = createConvertTest();
+ }
+ else
+ {
+ fprintf(stderr, "Unrecognized command line option. Scanning \"%s\"\n",
+ argv[argnum]);
+ throw 1;
+ }
+ argnum++;
+ }
+ // We've reached the end of the command line parameters.
+ // Fail if no test name was specified.
+ if (gRunInfo.fTest == NULL) {
+ fprintf(stderr, "No test specified.\n");
+ throw 1;
+ }
+
+ }
+ catch (int)
+ {
+ fprintf(stderr, "usage: threadtest [-threads nnn] [-time nnn] [-quiet] [-verbose] test-name\n"
+ " -quiet Suppress periodic status display. \n"
+ " -verbose Display extra messages. \n"
+ " -threads nnn Number of threads. Default is 2. \n"
+ " -time nnn Total time to run, in seconds. Default is forever.\n"
+ " -ctime nnn Time between extra consistency checks, in seconds. Default 10\n"
+ " testname string | convert\n"
+ );
+ exit(1);
+ }
+}
+
+
+
+
+
+//----------------------------------------------------------------------
+//
+// threadMain The main function for each of the swarm of test threads.
+// Run in a loop, executing the runOnce() test function each time.
+//
+//
+//----------------------------------------------------------------------
+
+extern "C" {
+
+void threadMain (void *param)
+{
+ ThreadInfo *thInfo = (ThreadInfo *)param;
+
+ if (gRunInfo.verbose)
+ printf("Thread #%d: starting\n", thInfo->fThreadNum);
+ umtx_atomic_inc(&gRunInfo.runningThreads);
+
+ //
+ //
+ while (true)
+ {
+ if (gRunInfo.verbose )
+ printf("Thread #%d: starting loop\n", thInfo->fThreadNum);
+
+ //
+ // If the main thread is asking us to wait, do so by locking gStopMutex
+ // which will block us, since the main thread will be holding it already.
+ //
+ umtx_lock(&gInfoMutex);
+ UBool stop = gRunInfo.stopFlag; // Need mutex for processors with flakey memory models.
+ umtx_unlock(&gInfoMutex);
+
+ if (stop) {
+ if (gRunInfo.verbose) {
+ fprintf(stderr, "Thread #%d: suspending\n", thInfo->fThreadNum);
+ }
+ umtx_atomic_dec(&gRunInfo.runningThreads);
+ while (gRunInfo.stopFlag) {
+ umtx_lock(&gStopMutex);
+ umtx_unlock(&gStopMutex);
+ }
+ umtx_atomic_inc(&gRunInfo.runningThreads);
+ if (gRunInfo.verbose) {
+ fprintf(stderr, "Thread #%d: restarting\n", thInfo->fThreadNum);
+ }
+ }
+
+ //
+ // The real work of the test happens here.
+ //
+ gRunInfo.fTest->runOnce();
+
+ umtx_lock(&gInfoMutex);
+ thInfo->fHeartBeat = true;
+ thInfo->fCycles++;
+ UBool exitNow = gRunInfo.exitFlag;
+ umtx_unlock(&gInfoMutex);
+
+ //
+ // If main thread says it's time to exit, break out of the loop.
+ //
+ if (exitNow) {
+ break;
+ }
+ }
+
+ umtx_atomic_dec(&gRunInfo.runningThreads);
+
+ // Returning will kill the thread.
+ return;
+}
+
+}
+
+
+
+
+//----------------------------------------------------------------------
+//
+// main
+//
+//----------------------------------------------------------------------
+
+int main (int argc, char **argv)
+{
+ //
+ // Parse the command line options, and create the specified kind of test.
+ //
+ parseCommandLine(argc, argv);
+
+
+ //
+ // Fire off the requested number of parallel threads
+ //
+
+ if (gRunInfo.numThreads == 0)
+ exit(0);
+
+ gRunInfo.exitFlag = FALSE;
+ gRunInfo.stopFlag = TRUE; // Will cause the new threads to block
+ umtx_lock(&gStopMutex);
+
+ gThreadInfo = new ThreadInfo[gRunInfo.numThreads];
+ int threadNum;
+ for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++)
+ {
+ gThreadInfo[threadNum].fThreadNum = threadNum;
+ ThreadFuncs::startThread(threadMain, &gThreadInfo[threadNum]);
+ }
+
+
+ unsigned long startTime = ThreadFuncs::getCurrentMillis();
+ int elapsedSeconds = 0;
+ int timeSinceCheck = 0;
+
+ //
+ // Unblock the threads.
+ //
+ gRunInfo.stopFlag = FALSE; // Unblocks the worker threads.
+ umtx_unlock(&gStopMutex);
+
+ //
+ // Loop, watching the heartbeat of the worker threads.
+ // Each second,
+ // display "+" if all threads have completed at least one loop
+ // display "." if some thread hasn't since previous "+"
+ // Each "ctime" seconds,
+ // Stop all the worker threads at the top of their loop, then
+ // call the test's check function.
+ //
+ while (gRunInfo.totalTime == 0 || gRunInfo.totalTime > elapsedSeconds)
+ {
+ ThreadFuncs::Sleep(1000); // We sleep while threads do their work ...
+
+ if (gRunInfo.quiet == false && gRunInfo.verbose == false)
+ {
+ char c = '+';
+ int threadNum;
+ umtx_lock(&gInfoMutex);
+ for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++)
+ {
+ if (gThreadInfo[threadNum].fHeartBeat == false)
+ {
+ c = '.';
+ break;
+ };
+ }
+ umtx_unlock(&gInfoMutex);
+ fputc(c, stdout);
+ fflush(stdout);
+ if (c == '+')
+ for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++)
+ gThreadInfo[threadNum].fHeartBeat = false;
+ }
+
+ //
+ // Update running times.
+ //
+ timeSinceCheck -= elapsedSeconds;
+ elapsedSeconds = (ThreadFuncs::getCurrentMillis() - startTime) / 1000;
+ timeSinceCheck += elapsedSeconds;
+
+ //
+ // Call back to the test to let it check its internal validity
+ //
+ if (timeSinceCheck >= gRunInfo.checkTime) {
+ if (gRunInfo.verbose) {
+ fprintf(stderr, "Main: suspending all threads\n");
+ }
+ umtx_lock(&gStopMutex); // Block the worker threads at the top of their loop
+ gRunInfo.stopFlag = TRUE;
+ for (;;) {
+ umtx_lock(&gInfoMutex);
+ UBool done = gRunInfo.runningThreads == 0;
+ umtx_unlock(&gInfoMutex);
+ if (done) { break;}
+ ThreadFuncs::yield();
+ }
+
+
+
+ gRunInfo.fTest->check();
+ if (gRunInfo.quiet == false && gRunInfo.verbose == false) {
+ fputc('C', stdout);
+ }
+
+ if (gRunInfo.verbose) {
+ fprintf(stderr, "Main: starting all threads.\n");
+ }
+ gRunInfo.stopFlag = FALSE; // Unblock the worker threads.
+ umtx_unlock(&gStopMutex);
+ timeSinceCheck = 0;
+ }
+ };
+
+ //
+ // Time's up, we are done. (We only get here if this was a timed run)
+ // Tell the threads to exit.
+ //
+ gRunInfo.exitFlag = true;
+ for (;;) {
+ umtx_lock(&gInfoMutex);
+ UBool done = gRunInfo.runningThreads == 0;
+ umtx_unlock(&gInfoMutex);
+ if (done) { break;}
+ ThreadFuncs::yield();
+ }
+
+ //
+ // Tally up the total number of cycles completed by each of the threads.
+ //
+ double totalCyclesCompleted = 0;
+ for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++) {
+ totalCyclesCompleted += gThreadInfo[threadNum].fCycles;
+ }
+
+ double cyclesPerMinute = totalCyclesCompleted / (double(gRunInfo.totalTime) / double(60));
+ printf("\n%8.1f cycles per minute.", cyclesPerMinute);
+
+ //
+ // Memory should be clean coming out
+ //
+ delete gRunInfo.fTest;
+ delete [] gThreadInfo;
+ umtx_destroy(&gInfoMutex);
+ umtx_destroy(&gStopMutex);
+ u_cleanup();
+
+ return 0;
+}
+
+