Home | History | Annotate | Download | only in intltest
      1 /********************************************************************
      2  * COPYRIGHT:
      3  * Copyright (c) 1999-2012, International Business Machines Corporation and
      4  * others. All Rights Reserved.
      5  ********************************************************************/
      6 
      7 #if defined(hpux)
      8 # ifndef _INCLUDE_POSIX_SOURCE
      9 #  define _INCLUDE_POSIX_SOURCE
     10 # endif
     11 #endif
     12 
     13 #include "simplethread.h"
     14 
     15 #include "unicode/utypes.h"
     16 #include "unicode/ustring.h"
     17 #include "umutex.h"
     18 #include "cmemory.h"
     19 #include "cstring.h"
     20 #include "uparse.h"
     21 #include "unicode/localpointer.h"
     22 #include "unicode/resbund.h"
     23 #include "unicode/udata.h"
     24 #include "unicode/uloc.h"
     25 #include "unicode/locid.h"
     26 #include "putilimp.h"
     27 #include "intltest.h"
     28 #include "tsmthred.h"
     29 #include "unicode/ushape.h"
     30 
     31 
     32 #if U_PLATFORM_USES_ONLY_WIN32_API
     33     /* Prefer native Windows APIs even if POSIX is implemented (i.e., on Cygwin). */
     34 #   undef POSIX
     35 #elif U_PLATFORM_IMPLEMENTS_POSIX
     36 #   define POSIX
     37 #else
     38 #   undef POSIX
     39 #endif
     40 
     41 
     42 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
     43 /* Needed by z/OS to get usleep */
     44 #if U_PLATFORM == U_PF_OS390
     45 #define __DOT1 1
     46 #define __UU
     47 #ifndef _XPG4_2
     48 #define _XPG4_2
     49 #endif
     50 #include <unistd.h>
     51 #endif
     52 #if defined(POSIX)
     53 
     54 #define HAVE_IMP
     55 
     56 #if (ICU_USE_THREADS == 1)
     57 #include <pthread.h>
     58 #endif
     59 
     60 #if defined(__hpux) && defined(HPUX_CMA)
     61 # if defined(read)  // read being defined as cma_read causes trouble with iostream::read
     62 #  undef read
     63 # endif
     64 #endif
     65 
     66 /* Define __EXTENSIONS__ for Solaris and old friends in strict mode. */
     67 #ifndef __EXTENSIONS__
     68 #define __EXTENSIONS__
     69 #endif
     70 
     71 #if U_PLATFORM == U_PF_OS390
     72 #include <sys/types.h>
     73 #endif
     74 
     75 #if U_PLATFORM != U_PF_OS390
     76 #include <signal.h>
     77 #endif
     78 
     79 /* Define _XPG4_2 for Solaris and friends. */
     80 #ifndef _XPG4_2
     81 #define _XPG4_2
     82 #endif
     83 
     84 /* Define __USE_XOPEN_EXTENDED for Linux and glibc. */
     85 #ifndef __USE_XOPEN_EXTENDED
     86 #define __USE_XOPEN_EXTENDED
     87 #endif
     88 
     89 /* Define _INCLUDE_XOPEN_SOURCE_EXTENDED for HP/UX (11?). */
     90 #ifndef _INCLUDE_XOPEN_SOURCE_EXTENDED
     91 #define _INCLUDE_XOPEN_SOURCE_EXTENDED
     92 #endif
     93 
     94 #include <unistd.h>
     95 
     96 #endif
     97 /* HPUX */
     98 #ifdef sleep
     99 #undef sleep
    100 #endif
    101 
    102 #define TSMTHREAD_FAIL(msg) errln("%s at file %s, line %d", msg, __FILE__, __LINE__)
    103 #define TSMTHREAD_ASSERT(expr) {if (!(expr)) {TSMTHREAD_FAIL("Fail");}}
    104 
    105 MultithreadTest::MultithreadTest()
    106 {
    107 }
    108 
    109 MultithreadTest::~MultithreadTest()
    110 {
    111 }
    112 
    113 
    114 
    115 #if (ICU_USE_THREADS==0)
    116 void MultithreadTest::runIndexedTest( int32_t index, UBool exec,
    117                 const char* &name, char* /*par*/ ) {
    118   if (exec) logln("TestSuite MultithreadTest: ");
    119 
    120   if(index == 0)
    121       name = "NO_THREADED_TESTS";
    122   else
    123       name = "";
    124 
    125   if(exec) { logln("MultithreadTest - test DISABLED.  ICU_USE_THREADS set to 0, check your configuration if this is a problem..");
    126   }
    127 }
    128 #else
    129 
    130 #include <stdio.h>
    131 #include <string.h>
    132 #include <ctype.h>    // tolower, toupper
    133 
    134 #include "unicode/putil.h"
    135 
    136 // for mthreadtest
    137 #include "unicode/numfmt.h"
    138 #include "unicode/choicfmt.h"
    139 #include "unicode/msgfmt.h"
    140 #include "unicode/locid.h"
    141 #include "unicode/coll.h"
    142 #include "unicode/calendar.h"
    143 #include "ucaconf.h"
    144 
    145 void SimpleThread::errorFunc() {
    146     // *(char *)0 = 3;            // Force entry into a debugger via a crash;
    147 }
    148 
    149 void MultithreadTest::runIndexedTest( int32_t index, UBool exec,
    150                 const char* &name, char* /*par*/ ) {
    151     if (exec)
    152         logln("TestSuite MultithreadTest: ");
    153     switch (index) {
    154     case 0:
    155         name = "TestThreads";
    156         if (exec)
    157             TestThreads();
    158         break;
    159 
    160     case 1:
    161         name = "TestMutex";
    162         if (exec)
    163             TestMutex();
    164         break;
    165 
    166     case 2:
    167         name = "TestThreadedIntl";
    168 #if !UCONFIG_NO_FORMATTING
    169         if (exec) {
    170             TestThreadedIntl();
    171         }
    172 #endif
    173         break;
    174 
    175     case 3:
    176       name = "TestCollators";
    177 #if !UCONFIG_NO_COLLATION
    178       if (exec) {
    179             TestCollators();
    180       }
    181 #endif /* #if !UCONFIG_NO_COLLATION */
    182       break;
    183 
    184     case 4:
    185         name = "TestString";
    186         if (exec) {
    187             TestString();
    188         }
    189         break;
    190 
    191 	case 5:
    192         name = "TestArabicShapingThreads";
    193         if (exec) {
    194             TestArabicShapingThreads();
    195         }
    196         break;
    197 
    198 
    199     default:
    200         name = "";
    201         break; //needed to end loop
    202     }
    203 }
    204 
    205 
    206 //-----------------------------------------------------------------------------------
    207 //
    208 //   TestThreads -- see if threads really work at all.
    209 //
    210 //   Set up N threads pointing at N chars. When they are started, they will
    211 //   each sleep 1 second and then set their chars. At the end we make sure they
    212 //   are all set.
    213 //
    214 //-----------------------------------------------------------------------------------
    215 #define THREADTEST_NRTHREADS 8
    216 #define ARABICSHAPE_THREADTEST 30
    217 
    218 class TestThreadsThread : public SimpleThread
    219 {
    220 public:
    221     TestThreadsThread(char* whatToChange) { fWhatToChange = whatToChange; }
    222     virtual void run() { SimpleThread::sleep(1000);
    223                          Mutex m;
    224                          *fWhatToChange = '*';
    225     }
    226 private:
    227     char *fWhatToChange;
    228 };
    229 //-----------------------------------------------------------------------------------
    230 //
    231 //   TestArabicShapeThreads -- see if calls to u_shapeArabic in many threads works successfully
    232 //
    233 //   Set up N threads pointing at N chars. When they are started, they will make calls to doTailTest which tests
    234 //   u_shapeArabic, if the calls are successful it will the set * chars.
    235 //   At the end we make sure all threads managed to run u_shapeArabic successfully.
    236 //   This is a unit test for ticket 9473
    237 //
    238 //-----------------------------------------------------------------------------------
    239 class TestArabicShapeThreads : public SimpleThread
    240 {
    241 public:
    242     TestArabicShapeThreads(char* whatToChange) { fWhatToChange = whatToChange;}
    243     virtual void run() {
    244 	    if(doTailTest()==TRUE)
    245 			*fWhatToChange = '*';
    246     }
    247 private:
    248     char *fWhatToChange;
    249 
    250 	UBool doTailTest(void) {
    251   static const UChar src[] = { 0x0020, 0x0633, 0 };
    252   static const UChar dst_old[] = { 0xFEB1, 0x200B,0 };
    253   static const UChar dst_new[] = { 0xFEB1, 0xFE73,0 };
    254   UChar dst[3] = { 0x0000, 0x0000,0 };
    255   int32_t length;
    256   UErrorCode status;
    257   IntlTest inteltst =  IntlTest();
    258 
    259   status = U_ZERO_ERROR;
    260   length = u_shapeArabic(src, -1, dst, LENGTHOF(dst),
    261                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_SEEN_TWOCELL_NEAR, &status);
    262   if(U_FAILURE(status)) {
    263 	   inteltst.errln("Fail: status %s\n", u_errorName(status));
    264 	return FALSE;
    265   } else if(length!=2) {
    266     inteltst.errln("Fail: len %d expected 3\n", length);
    267 	return FALSE;
    268   } else if(u_strncmp(dst,dst_old,LENGTHOF(dst))) {
    269     inteltst.errln("Fail: got U+%04X U+%04X expected U+%04X U+%04X\n",
    270             dst[0],dst[1],dst_old[0],dst_old[1]);
    271 	return FALSE;
    272   }
    273 
    274 
    275   //"Trying new tail
    276   status = U_ZERO_ERROR;
    277   length = u_shapeArabic(src, -1, dst, LENGTHOF(dst),
    278                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_SEEN_TWOCELL_NEAR|U_SHAPE_TAIL_NEW_UNICODE, &status);
    279   if(U_FAILURE(status)) {
    280     inteltst.errln("Fail: status %s\n", u_errorName(status));
    281 	return FALSE;
    282   } else if(length!=2) {
    283     inteltst.errln("Fail: len %d expected 3\n", length);
    284 	return FALSE;
    285   } else if(u_strncmp(dst,dst_new,LENGTHOF(dst))) {
    286     inteltst.errln("Fail: got U+%04X U+%04X expected U+%04X U+%04X\n",
    287             dst[0],dst[1],dst_new[0],dst_new[1]);
    288 	return FALSE;
    289   }
    290 
    291 
    292   return TRUE;
    293 
    294 }
    295 
    296 
    297 };
    298 
    299 void MultithreadTest::TestThreads()
    300 {
    301     char threadTestChars[THREADTEST_NRTHREADS + 1];
    302     SimpleThread *threads[THREADTEST_NRTHREADS];
    303     int32_t numThreadsStarted = 0;
    304 
    305     int32_t i;
    306     for(i=0;i<THREADTEST_NRTHREADS;i++)
    307     {
    308         threadTestChars[i] = ' ';
    309         threads[i] = new TestThreadsThread(&threadTestChars[i]);
    310     }
    311     threadTestChars[THREADTEST_NRTHREADS] = '\0';
    312 
    313     logln("->" + UnicodeString(threadTestChars) + "<- Firing off threads.. ");
    314     for(i=0;i<THREADTEST_NRTHREADS;i++)
    315     {
    316         if (threads[i]->start() != 0) {
    317             errln("Error starting thread %d", i);
    318         }
    319         else {
    320             numThreadsStarted++;
    321         }
    322         SimpleThread::sleep(100);
    323         logln(" Subthread started.");
    324     }
    325 
    326     logln("Waiting for threads to be set..");
    327     if (numThreadsStarted == 0) {
    328         errln("No threads could be started for testing!");
    329         return;
    330     }
    331 
    332     int32_t patience = 40; // seconds to wait
    333 
    334     while(patience--)
    335     {
    336         int32_t count = 0;
    337         umtx_lock(NULL);
    338         for(i=0;i<THREADTEST_NRTHREADS;i++)
    339         {
    340             if(threadTestChars[i] == '*')
    341             {
    342                 count++;
    343             }
    344         }
    345         umtx_unlock(NULL);
    346 
    347         if(count == THREADTEST_NRTHREADS)
    348         {
    349             logln("->" + UnicodeString(threadTestChars) + "<- Got all threads! cya");
    350             for(i=0;i<THREADTEST_NRTHREADS;i++)
    351             {
    352                 delete threads[i];
    353             }
    354             return;
    355         }
    356 
    357         logln("->" + UnicodeString(threadTestChars) + "<- Waiting..");
    358         SimpleThread::sleep(500);
    359     }
    360 
    361     errln("->" + UnicodeString(threadTestChars) + "<- PATIENCE EXCEEDED!! Still missing some.");
    362     for(i=0;i<THREADTEST_NRTHREADS;i++)
    363     {
    364         delete threads[i];
    365     }
    366 }
    367 
    368 
    369 void MultithreadTest::TestArabicShapingThreads()
    370 {
    371     char threadTestChars[ARABICSHAPE_THREADTEST + 1];
    372     SimpleThread *threads[ARABICSHAPE_THREADTEST];
    373     int32_t numThreadsStarted = 0;
    374 
    375     int32_t i;
    376 
    377     for(i=0;i<ARABICSHAPE_THREADTEST;i++)
    378     {
    379         threadTestChars[i] = ' ';
    380         threads[i] = new TestArabicShapeThreads(&threadTestChars[i]);
    381     }
    382     threadTestChars[ARABICSHAPE_THREADTEST] = '\0';
    383 
    384     logln("-> do TestArabicShapingThreads <- Firing off threads.. ");
    385     for(i=0;i<ARABICSHAPE_THREADTEST;i++)
    386     {
    387         if (threads[i]->start() != 0) {
    388             errln("Error starting thread %d", i);
    389         }
    390         else {
    391             numThreadsStarted++;
    392         }
    393         //SimpleThread::sleep(100);
    394         logln(" Subthread started.");
    395     }
    396 
    397     logln("Waiting for threads to be set..");
    398     if (numThreadsStarted == 0) {
    399         errln("No threads could be started for testing!");
    400         return;
    401     }
    402 
    403     int32_t patience = 100; // seconds to wait
    404 
    405     while(patience--)
    406     {
    407         int32_t count = 0;
    408         umtx_lock(NULL);
    409         for(i=0;i<ARABICSHAPE_THREADTEST;i++)
    410         {
    411             if(threadTestChars[i] == '*')
    412             {
    413                 count++;
    414             }
    415         }
    416         umtx_unlock(NULL);
    417 
    418         if(count == ARABICSHAPE_THREADTEST)
    419         {
    420             logln("->TestArabicShapingThreads <- Got all threads! cya");
    421             for(i=0;i<ARABICSHAPE_THREADTEST;i++)
    422             {
    423                 delete threads[i];
    424             }
    425             return;
    426         }
    427 
    428         logln("-> TestArabicShapingThreads <- Waiting..");
    429         SimpleThread::sleep(500);
    430     }
    431 
    432     errln("-> TestArabicShapingThreads <- PATIENCE EXCEEDED!! Still missing some.");
    433     for(i=0;i<ARABICSHAPE_THREADTEST;i++)
    434     {
    435         delete threads[i];
    436     }
    437 
    438 }
    439 
    440 
    441 //-----------------------------------------------------------------------
    442 //
    443 //  TestMutex  - a simple (non-stress) test to verify that ICU mutexes
    444 //               are actually mutexing.  Does not test the use of
    445 //               mutexes within ICU services, but rather that the
    446 //               platform's mutex support is at least superficially there.
    447 //
    448 //----------------------------------------------------------------------
    449 static UMutex    gTestMutexA = U_MUTEX_INITIALIZER;
    450 static UMutex    gTestMutexB = U_MUTEX_INITIALIZER;
    451 
    452 static int     gThreadsStarted = 0;
    453 static int     gThreadsInMiddle = 0;
    454 static int     gThreadsDone = 0;
    455 
    456 static const int TESTMUTEX_THREAD_COUNT = 4;
    457 
    458 static int safeIncr(int &var, int amt) {
    459     // Thread safe (using global mutex) increment of a variable.
    460     // Return the updated value.
    461     // Can also be used as a safe load of a variable by incrementing it by 0.
    462     Mutex m;
    463     var += amt;
    464     return var;
    465 }
    466 
    467 class TestMutexThread : public SimpleThread
    468 {
    469 public:
    470     virtual void run()
    471     {
    472         // This is the code that each of the spawned threads runs.
    473         // All of the spawned threads bunch up together at each of the two mutexes
    474         // because the main holds the mutexes until they do.
    475         //
    476         safeIncr(gThreadsStarted, 1);
    477         umtx_lock(&gTestMutexA);
    478         umtx_unlock(&gTestMutexA);
    479         safeIncr(gThreadsInMiddle, 1);
    480         umtx_lock(&gTestMutexB);
    481         umtx_unlock(&gTestMutexB);
    482         safeIncr(gThreadsDone, 1);
    483     }
    484 };
    485 
    486 void MultithreadTest::TestMutex()
    487 {
    488     // Start up the test threads.  They should all pile up waiting on
    489     // gTestMutexA, which we (the main thread) hold until the test threads
    490     //   all get there.
    491     gThreadsStarted = 0;
    492     gThreadsInMiddle = 0;
    493     gThreadsDone = 0;
    494     umtx_lock(&gTestMutexA);
    495     TestMutexThread  *threads[TESTMUTEX_THREAD_COUNT];
    496     int i;
    497     int32_t numThreadsStarted = 0;
    498     for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) {
    499         threads[i] = new TestMutexThread;
    500         if (threads[i]->start() != 0) {
    501             errln("Error starting thread %d", i);
    502         }
    503         else {
    504             numThreadsStarted++;
    505         }
    506     }
    507     if (numThreadsStarted == 0) {
    508         errln("No threads could be started for testing!");
    509         return;
    510     }
    511 
    512     int patience = 0;
    513     while (safeIncr(gThreadsStarted, 0) != TESTMUTEX_THREAD_COUNT) {
    514         if (patience++ > 24) {
    515             TSMTHREAD_FAIL("Patience Exceeded");
    516             return;
    517         }
    518         SimpleThread::sleep(500);
    519     }
    520     // None of the test threads should have advanced past the first mutex.
    521     TSMTHREAD_ASSERT(gThreadsInMiddle==0);
    522     TSMTHREAD_ASSERT(gThreadsDone==0);
    523 
    524     //  All of the test threads have made it to the first mutex.
    525     //  We (the main thread) now let them advance to the second mutex,
    526     //   where they should all pile up again.
    527     umtx_lock(&gTestMutexB);
    528     umtx_unlock(&gTestMutexA);
    529 
    530     patience = 0;
    531     while (safeIncr(gThreadsInMiddle, 0) != TESTMUTEX_THREAD_COUNT) {
    532         if (patience++ > 24) {
    533             TSMTHREAD_FAIL("Patience Exceeded");
    534             return;
    535         }
    536         SimpleThread::sleep(500);
    537     }
    538     TSMTHREAD_ASSERT(gThreadsDone==0);
    539 
    540     //  All test threads made it to the second mutex.
    541     //   Now let them proceed from there.  They will all terminate.
    542     umtx_unlock(&gTestMutexB);
    543     patience = 0;
    544     while (safeIncr(gThreadsDone, 0) != TESTMUTEX_THREAD_COUNT) {
    545         if (patience++ > 24) {
    546             TSMTHREAD_FAIL("Patience Exceeded");
    547             return;
    548         }
    549         SimpleThread::sleep(500);
    550     }
    551 
    552     // All threads made it by both mutexes.
    553 
    554     for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) {
    555         delete threads[i];
    556     }
    557 
    558 }
    559 
    560 
    561 //-------------------------------------------------------------------------------------------
    562 //
    563 // class ThreadWithStatus - a thread that we can check the status and error condition of
    564 //
    565 //-------------------------------------------------------------------------------------------
    566 class ThreadWithStatus : public SimpleThread
    567 {
    568 public:
    569     UBool  getError() { return (fErrors > 0); }
    570     UBool  getError(UnicodeString& fillinError) { fillinError = fErrorString; return (fErrors > 0); }
    571     virtual ~ThreadWithStatus(){}
    572 protected:
    573     ThreadWithStatus() :  fErrors(0) {}
    574     void error(const UnicodeString &error) {
    575         fErrors++; fErrorString = error;
    576         SimpleThread::errorFunc();
    577     }
    578     void error() { error("An error occured."); }
    579 private:
    580     int32_t fErrors;
    581     UnicodeString fErrorString;
    582 };
    583 
    584 
    585 
    586 //-------------------------------------------------------------------------------------------
    587 //
    588 //   TestMultithreadedIntl.  Test ICU Formatting n a multi-threaded environment
    589 //
    590 //-------------------------------------------------------------------------------------------
    591 
    592 
    593 // * Show exactly where the string's differences lie.
    594 UnicodeString showDifference(const UnicodeString& expected, const UnicodeString& result)
    595 {
    596     UnicodeString res;
    597     res = expected + "<Expected\n";
    598     if(expected.length() != result.length())
    599         res += " [ Different lengths ] \n";
    600     else
    601     {
    602         for(int32_t i=0;i<expected.length();i++)
    603         {
    604             if(expected[i] == result[i])
    605             {
    606                 res += " ";
    607             }
    608             else
    609             {
    610                 res += "|";
    611             }
    612         }
    613         res += "<Differences";
    614         res += "\n";
    615     }
    616     res += result + "<Result\n";
    617 
    618     return res;
    619 }
    620 
    621 
    622 
    623 
    624 //-------------------------------------------------------------------------------------------
    625 //
    626 //   FormatThreadTest - a thread that tests performing a number of numberformats.
    627 //
    628 //-------------------------------------------------------------------------------------------
    629 
    630 const int kFormatThreadIterations = 20;  // # of iterations per thread
    631 const int kFormatThreadThreads    = 10;  // # of threads to spawn
    632 const int kFormatThreadPatience   = 60;  // time in seconds to wait for all threads
    633 
    634 #if !UCONFIG_NO_FORMATTING
    635 
    636 
    637 
    638 struct FormatThreadTestData
    639 {
    640     double number;
    641     UnicodeString string;
    642     FormatThreadTestData(double a, const UnicodeString& b) : number(a),string(b) {}
    643 } ;
    644 
    645 
    646 // "Someone from {2} is receiving a #{0} error - {1}. Their telephone call is costing {3 number,currency}."
    647 
    648 void formatErrorMessage(UErrorCode &realStatus, const UnicodeString& pattern, const Locale& theLocale,
    649                      UErrorCode inStatus0, /* statusString 1 */ const Locale &inCountry2, double currency3, // these numbers are the message arguments.
    650                      UnicodeString &result)
    651 {
    652     if(U_FAILURE(realStatus))
    653         return; // you messed up
    654 
    655     UnicodeString errString1(u_errorName(inStatus0));
    656 
    657     UnicodeString countryName2;
    658     inCountry2.getDisplayCountry(theLocale,countryName2);
    659 
    660     Formattable myArgs[] = {
    661         Formattable((int32_t)inStatus0),   // inStatus0      {0}
    662         Formattable(errString1), // statusString1 {1}
    663         Formattable(countryName2),  // inCountry2 {2}
    664         Formattable(currency3)// currency3  {3,number,currency}
    665     };
    666 
    667     MessageFormat *fmt = new MessageFormat("MessageFormat's API is broken!!!!!!!!!!!",realStatus);
    668     fmt->setLocale(theLocale);
    669     fmt->applyPattern(pattern, realStatus);
    670 
    671     if (U_FAILURE(realStatus)) {
    672         delete fmt;
    673         return;
    674     }
    675 
    676     FieldPosition ignore = 0;
    677     fmt->format(myArgs,4,result,ignore,realStatus);
    678 
    679     delete fmt;
    680 }
    681 
    682 
    683 UBool U_CALLCONV isAcceptable(void *, const char *, const char *, const UDataInfo *) {
    684     return TRUE;
    685 }
    686 
    687 //static UMTX debugMutex = NULL;
    688 //static UMTX gDebugMutex;
    689 
    690 
    691 class FormatThreadTest : public ThreadWithStatus
    692 {
    693 public:
    694     int     fNum;
    695     int     fTraceInfo;
    696 
    697     FormatThreadTest() // constructor is NOT multithread safe.
    698         : ThreadWithStatus(),
    699         fNum(0),
    700         fTraceInfo(0),
    701         fOffset(0)
    702         // the locale to use
    703     {
    704         static int32_t fgOffset = 0;
    705         fgOffset += 3;
    706         fOffset = fgOffset;
    707     }
    708 
    709 
    710     virtual void run()
    711     {
    712         fTraceInfo                     = 1;
    713         LocalPointer<NumberFormat> percentFormatter;
    714         UErrorCode status = U_ZERO_ERROR;
    715 
    716 #if 0
    717         // debugging code,
    718         for (int i=0; i<4000; i++) {
    719             status = U_ZERO_ERROR;
    720             UDataMemory *data1 = udata_openChoice(0, "res", "en_US", isAcceptable, 0, &status);
    721             UDataMemory *data2 = udata_openChoice(0, "res", "fr", isAcceptable, 0, &status);
    722             udata_close(data1);
    723             udata_close(data2);
    724             if (U_FAILURE(status)) {
    725                 error("udata_openChoice failed.\n");
    726                 break;
    727             }
    728         }
    729         return;
    730 #endif
    731 
    732 #if 0
    733         // debugging code,
    734         int m;
    735         for (m=0; m<4000; m++) {
    736             status         = U_ZERO_ERROR;
    737             UResourceBundle *res   = NULL;
    738             const char *localeName = NULL;
    739 
    740             Locale  loc = Locale::getEnglish();
    741 
    742             localeName = loc.getName();
    743             // localeName = "en";
    744 
    745             // ResourceBundle bund = ResourceBundle(0, loc, status);
    746             //umtx_lock(&gDebugMutex);
    747             res = ures_open(NULL, localeName, &status);
    748             //umtx_unlock(&gDebugMutex);
    749 
    750             //umtx_lock(&gDebugMutex);
    751             ures_close(res);
    752             //umtx_unlock(&gDebugMutex);
    753 
    754             if (U_FAILURE(status)) {
    755                 error("Resource bundle construction failed.\n");
    756                 break;
    757             }
    758         }
    759         return;
    760 #endif
    761 
    762         // Keep this data here to avoid static initialization.
    763         FormatThreadTestData kNumberFormatTestData[] =
    764         {
    765             FormatThreadTestData((double)5.0, UnicodeString("5", "")),
    766                 FormatThreadTestData( 6.0, UnicodeString("6", "")),
    767                 FormatThreadTestData( 20.0, UnicodeString("20", "")),
    768                 FormatThreadTestData( 8.0, UnicodeString("8", "")),
    769                 FormatThreadTestData( 8.3, UnicodeString("8.3", "")),
    770                 FormatThreadTestData( 12345, UnicodeString("12,345", "")),
    771                 FormatThreadTestData( 81890.23, UnicodeString("81,890.23", "")),
    772         };
    773         int32_t kNumberFormatTestDataLength = (int32_t)(sizeof(kNumberFormatTestData) /
    774                                                         sizeof(kNumberFormatTestData[0]));
    775 
    776         // Keep this data here to avoid static initialization.
    777         FormatThreadTestData kPercentFormatTestData[] =
    778         {
    779             FormatThreadTestData((double)5.0, CharsToUnicodeString("500\\u00a0%")),
    780                 FormatThreadTestData( 1.0, CharsToUnicodeString("100\\u00a0%")),
    781                 FormatThreadTestData( 0.26, CharsToUnicodeString("26\\u00a0%")),
    782                 FormatThreadTestData(
    783                    16384.99, CharsToUnicodeString("1\\u00a0638\\u00a0499\\u00a0%")), // U+00a0 = NBSP
    784                 FormatThreadTestData(
    785                     81890.23, CharsToUnicodeString("8\\u00a0189\\u00a0023\\u00a0%")),
    786         };
    787         int32_t kPercentFormatTestDataLength =
    788                 (int32_t)(sizeof(kPercentFormatTestData) / sizeof(kPercentFormatTestData[0]));
    789         int32_t iteration;
    790 
    791         status = U_ZERO_ERROR;
    792         LocalPointer<NumberFormat> formatter(NumberFormat::createInstance(Locale::getEnglish(),status));
    793         if(U_FAILURE(status)) {
    794             error("Error on NumberFormat::createInstance().");
    795             goto cleanupAndReturn;
    796         }
    797 
    798         percentFormatter.adoptInstead(NumberFormat::createPercentInstance(Locale::getFrench(),status));
    799         if(U_FAILURE(status))             {
    800             error("Error on NumberFormat::createPercentInstance().");
    801             goto cleanupAndReturn;
    802         }
    803 
    804         for(iteration = 0;!getError() && iteration<kFormatThreadIterations;iteration++)
    805         {
    806 
    807             int32_t whichLine = (iteration + fOffset)%kNumberFormatTestDataLength;
    808 
    809             UnicodeString  output;
    810 
    811             formatter->format(kNumberFormatTestData[whichLine].number, output);
    812 
    813             if(0 != output.compare(kNumberFormatTestData[whichLine].string)) {
    814                 error("format().. expected " + kNumberFormatTestData[whichLine].string
    815                         + " got " + output);
    816                 goto cleanupAndReturn;
    817             }
    818 
    819             // Now check percent.
    820             output.remove();
    821             whichLine = (iteration + fOffset)%kPercentFormatTestDataLength;
    822 
    823             percentFormatter->format(kPercentFormatTestData[whichLine].number, output);
    824             if(0 != output.compare(kPercentFormatTestData[whichLine].string))
    825             {
    826                 error("percent format().. \n" +
    827                         showDifference(kPercentFormatTestData[whichLine].string,output));
    828                 goto cleanupAndReturn;
    829             }
    830 
    831             // Test message error
    832             const int       kNumberOfMessageTests = 3;
    833             UErrorCode      statusToCheck;
    834             UnicodeString   patternToCheck;
    835             Locale          messageLocale;
    836             Locale          countryToCheck;
    837             double          currencyToCheck;
    838 
    839             UnicodeString   expected;
    840 
    841             // load the cases.
    842             switch((iteration+fOffset) % kNumberOfMessageTests)
    843             {
    844             default:
    845             case 0:
    846                 statusToCheck=                      U_FILE_ACCESS_ERROR;
    847                 patternToCheck=        "0:Someone from {2} is receiving a #{0}"
    848                                        " error - {1}. Their telephone call is costing "
    849                                        "{3,number,currency}."; // number,currency
    850                 messageLocale=                      Locale("en","US");
    851                 countryToCheck=                     Locale("","HR");
    852                 currencyToCheck=                    8192.77;
    853                 expected=  "0:Someone from Croatia is receiving a #4 error - "
    854                             "U_FILE_ACCESS_ERROR. Their telephone call is costing $8,192.77.";
    855                 break;
    856             case 1:
    857                 statusToCheck=                      U_INDEX_OUTOFBOUNDS_ERROR;
    858                 patternToCheck=                     "1:A customer in {2} is receiving a #{0} error - {1}. Their telephone call is costing {3,number,currency}."; // number,currency
    859                 messageLocale=                      Locale("de","DE@currency=DEM");
    860                 countryToCheck=                     Locale("","BF");
    861                 currencyToCheck=                    2.32;
    862                 expected=                           CharsToUnicodeString(
    863                                                     "1:A customer in Burkina Faso is receiving a #8 error - U_INDEX_OUTOFBOUNDS_ERROR. Their telephone call is costing 2,32\\u00A0DEM.");
    864                 break;
    865             case 2:
    866                 statusToCheck=                      U_MEMORY_ALLOCATION_ERROR;
    867                 patternToCheck=   "2:user in {2} is receiving a #{0} error - {1}. "
    868                                   "They insist they just spent {3,number,currency} "
    869                                   "on memory."; // number,currency
    870                 messageLocale=                      Locale("de","AT@currency=ATS"); // Austrian German
    871                 countryToCheck=                     Locale("","US"); // hmm
    872                 currencyToCheck=                    40193.12;
    873                 expected=       CharsToUnicodeString(
    874                             "2:user in Vereinigte Staaten is receiving a #7 error"
    875                             " - U_MEMORY_ALLOCATION_ERROR. They insist they just spent"
    876                             " \\u00f6S\\u00A040.193,12 on memory.");
    877                 break;
    878             }
    879 
    880             UnicodeString result;
    881             UErrorCode status = U_ZERO_ERROR;
    882             formatErrorMessage(status,patternToCheck,messageLocale,statusToCheck,
    883                                 countryToCheck,currencyToCheck,result);
    884             if(U_FAILURE(status))
    885             {
    886                 UnicodeString tmp(u_errorName(status));
    887                 error("Failure on message format, pattern=" + patternToCheck +
    888                         ", error = " + tmp);
    889                 goto cleanupAndReturn;
    890             }
    891 
    892             if(result != expected)
    893             {
    894                 error("PatternFormat: \n" + showDifference(expected,result));
    895                 goto cleanupAndReturn;
    896             }
    897         }   /*  end of for loop */
    898 
    899 cleanupAndReturn:
    900         //  while (fNum == 4) {SimpleThread::sleep(10000);}   // Force a failure by preventing thread from finishing
    901         fTraceInfo = 2;
    902     }
    903 
    904 private:
    905     int32_t fOffset; // where we are testing from.
    906 };
    907 
    908 // ** The actual test function.
    909 
    910 void MultithreadTest::TestThreadedIntl()
    911 {
    912     int i;
    913     UnicodeString theErr;
    914     UBool   haveDisplayedInfo[kFormatThreadThreads];
    915     static const int32_t PATIENCE_SECONDS = 45;
    916 
    917     //
    918     //  Create and start the test threads
    919     //
    920     logln("Spawning: %d threads * %d iterations each.",
    921                 kFormatThreadThreads, kFormatThreadIterations);
    922     LocalArray<FormatThreadTest> tests(new FormatThreadTest[kFormatThreadThreads]);
    923     for(int32_t j = 0; j < kFormatThreadThreads; j++) {
    924         tests[j].fNum = j;
    925         int32_t threadStatus = tests[j].start();
    926         if (threadStatus != 0) {
    927             errln("System Error %d starting thread number %d.", threadStatus, j);
    928             SimpleThread::errorFunc();
    929             return;
    930         }
    931         haveDisplayedInfo[j] = FALSE;
    932     }
    933 
    934 
    935     // Spin, waiting for the test threads to finish.
    936     UBool   stillRunning;
    937     UDate startTime, endTime;
    938     startTime = Calendar::getNow();
    939     do {
    940         /*  Spin until the test threads  complete. */
    941         stillRunning = FALSE;
    942         endTime = Calendar::getNow();
    943         if (((int32_t)(endTime - startTime)/U_MILLIS_PER_SECOND) > PATIENCE_SECONDS) {
    944             errln("Patience exceeded. Test is taking too long.");
    945             return;
    946         }
    947         /*
    948          The following sleep must be here because the *BSD operating systems
    949          have a brain dead thread scheduler. They starve the child threads from
    950          CPU time.
    951         */
    952         SimpleThread::sleep(1); // yield
    953         for(i=0;i<kFormatThreadThreads;i++) {
    954             if (tests[i].isRunning()) {
    955                 stillRunning = TRUE;
    956             } else if (haveDisplayedInfo[i] == FALSE) {
    957                 logln("Thread # %d is complete..", i);
    958                 if(tests[i].getError(theErr)) {
    959                     dataerrln(UnicodeString("#") + i + ": " + theErr);
    960                     SimpleThread::errorFunc();
    961                 }
    962                 haveDisplayedInfo[i] = TRUE;
    963             }
    964         }
    965     } while (stillRunning);
    966 
    967     //
    968     //  All threads have finished.
    969     //
    970 }
    971 #endif /* #if !UCONFIG_NO_FORMATTING */
    972 
    973 
    974 
    975 
    976 
    977 //-------------------------------------------------------------------------------------------
    978 //
    979 // Collation threading test
    980 //
    981 //-------------------------------------------------------------------------------------------
    982 #if !UCONFIG_NO_COLLATION
    983 
    984 #define kCollatorThreadThreads   10  // # of threads to spawn
    985 #define kCollatorThreadPatience kCollatorThreadThreads*30
    986 
    987 struct Line {
    988     UChar buff[25];
    989     int32_t buflen;
    990 } ;
    991 
    992 static UBool
    993 skipLineBecauseOfBug(const UChar *s, int32_t length) {
    994     // TODO: Fix ICU ticket #8052
    995     if(length >= 3 &&
    996             (s[0] == 0xfb2 || s[0] == 0xfb3) &&
    997             s[1] == 0x334 &&
    998             (s[2] == 0xf73 || s[2] == 0xf75 || s[2] == 0xf81)) {
    999         return TRUE;
   1000     }
   1001     return FALSE;
   1002 }
   1003 
   1004 static UCollationResult
   1005 normalizeResult(int32_t result) {
   1006     return result<0 ? UCOL_LESS : result==0 ? UCOL_EQUAL : UCOL_GREATER;
   1007 }
   1008 
   1009 class CollatorThreadTest : public ThreadWithStatus
   1010 {
   1011 private:
   1012     const Collator *coll;
   1013     const Line *lines;
   1014     int32_t noLines;
   1015     UBool isAtLeastUCA62;
   1016 public:
   1017     CollatorThreadTest()  : ThreadWithStatus(),
   1018         coll(NULL),
   1019         lines(NULL),
   1020         noLines(0),
   1021         isAtLeastUCA62(TRUE)
   1022     {
   1023     };
   1024     void setCollator(Collator *c, Line *l, int32_t nl, UBool atLeastUCA62)
   1025     {
   1026         coll = c;
   1027         lines = l;
   1028         noLines = nl;
   1029         isAtLeastUCA62 = atLeastUCA62;
   1030     }
   1031     virtual void run() {
   1032         uint8_t sk1[1024], sk2[1024];
   1033         uint8_t *oldSk = NULL, *newSk = sk1;
   1034         int32_t oldLen = 0;
   1035         int32_t prev = 0;
   1036         int32_t i = 0;
   1037 
   1038         for(i = 0; i < noLines; i++) {
   1039             if(lines[i].buflen == 0) { continue; }
   1040 
   1041             if(skipLineBecauseOfBug(lines[i].buff, lines[i].buflen)) { continue; }
   1042 
   1043             int32_t resLen = coll->getSortKey(lines[i].buff, lines[i].buflen, newSk, 1024);
   1044 
   1045             if(oldSk != NULL) {
   1046                 int32_t skres = strcmp((char *)oldSk, (char *)newSk);
   1047                 int32_t cmpres = coll->compare(lines[prev].buff, lines[prev].buflen, lines[i].buff, lines[i].buflen);
   1048                 int32_t cmpres2 = coll->compare(lines[i].buff, lines[i].buflen, lines[prev].buff, lines[prev].buflen);
   1049 
   1050                 if(cmpres != -cmpres2) {
   1051                     error(UnicodeString("Compare result not symmetrical on line ") + (i + 1));
   1052                     break;
   1053                 }
   1054 
   1055                 if(cmpres != normalizeResult(skres)) {
   1056                     error(UnicodeString("Difference between coll->compare and sortkey compare on line ") + (i + 1));
   1057                     break;
   1058                 }
   1059 
   1060                 int32_t res = cmpres;
   1061                 if(res == 0 && !isAtLeastUCA62) {
   1062                     // Up to UCA 6.1, the collation test files use a custom tie-breaker,
   1063                     // comparing the raw input strings.
   1064                     res = u_strcmpCodePointOrder(lines[prev].buff, lines[i].buff);
   1065                     // Starting with UCA 6.2, the collation test files use the standard UCA tie-breaker,
   1066                     // comparing the NFD versions of the input strings,
   1067                     // which we do via setting strength=identical.
   1068                 }
   1069                 if(res > 0) {
   1070                     error(UnicodeString("Line is not greater or equal than previous line, for line ") + (i + 1));
   1071                     break;
   1072                 }
   1073             }
   1074 
   1075             oldSk = newSk;
   1076             oldLen = resLen;
   1077             prev = i;
   1078 
   1079             newSk = (newSk == sk1)?sk2:sk1;
   1080         }
   1081     }
   1082 };
   1083 
   1084 void MultithreadTest::TestCollators()
   1085 {
   1086 
   1087     UErrorCode status = U_ZERO_ERROR;
   1088     FILE *testFile = NULL;
   1089     char testDataPath[1024];
   1090     strcpy(testDataPath, IntlTest::getSourceTestData(status));
   1091     if (U_FAILURE(status)) {
   1092         errln("ERROR: could not open test data %s", u_errorName(status));
   1093         return;
   1094     }
   1095     strcat(testDataPath, "CollationTest_");
   1096 
   1097     const char* type = "NON_IGNORABLE";
   1098 
   1099     const char *ext = ".txt";
   1100     if(testFile) {
   1101         fclose(testFile);
   1102     }
   1103     char buffer[1024];
   1104     strcpy(buffer, testDataPath);
   1105     strcat(buffer, type);
   1106     size_t bufLen = strlen(buffer);
   1107 
   1108     // we try to open 3 files:
   1109     // path/CollationTest_type.txt
   1110     // path/CollationTest_type_SHORT.txt
   1111     // path/CollationTest_type_STUB.txt
   1112     // we are going to test with the first one that we manage to open.
   1113 
   1114     strcpy(buffer+bufLen, ext);
   1115 
   1116     testFile = fopen(buffer, "rb");
   1117 
   1118     if(testFile == 0) {
   1119         strcpy(buffer+bufLen, "_SHORT");
   1120         strcat(buffer, ext);
   1121         testFile = fopen(buffer, "rb");
   1122 
   1123         if(testFile == 0) {
   1124             strcpy(buffer+bufLen, "_STUB");
   1125             strcat(buffer, ext);
   1126             testFile = fopen(buffer, "rb");
   1127 
   1128             if (testFile == 0) {
   1129                 *(buffer+bufLen) = 0;
   1130                 dataerrln("could not open any of the conformance test files, tried opening base %s", buffer);
   1131                 return;
   1132             } else {
   1133                 infoln(
   1134                     "INFO: Working with the stub file.\n"
   1135                     "If you need the full conformance test, please\n"
   1136                     "download the appropriate data files from:\n"
   1137                     "http://source.icu-project.org/repos/icu/tools/trunk/unicodetools/com/ibm/text/data/");
   1138             }
   1139         }
   1140     }
   1141 
   1142     LocalArray<Line> lines(new Line[200000]);
   1143     memset(lines.getAlias(), 0, sizeof(Line)*200000);
   1144     int32_t lineNum = 0;
   1145 
   1146     UChar bufferU[1024];
   1147     uint32_t first = 0;
   1148 
   1149     while (fgets(buffer, 1024, testFile) != NULL) {
   1150         if(*buffer == 0 || buffer[0] == '#') {
   1151             // Store empty and comment lines so that errors are reported
   1152             // for the real test file lines.
   1153             lines[lineNum].buflen = 0;
   1154             lines[lineNum].buff[0] = 0;
   1155         } else {
   1156             int32_t buflen = u_parseString(buffer, bufferU, 1024, &first, &status);
   1157             lines[lineNum].buflen = buflen;
   1158             u_memcpy(lines[lineNum].buff, bufferU, buflen);
   1159             lines[lineNum].buff[buflen] = 0;
   1160         }
   1161         lineNum++;
   1162     }
   1163     fclose(testFile);
   1164     if(U_FAILURE(status)) {
   1165       dataerrln("Couldn't read the test file!");
   1166       return;
   1167     }
   1168 
   1169     UVersionInfo uniVersion;
   1170     static const UVersionInfo v62 = { 6, 2, 0, 0 };
   1171     u_getUnicodeVersion(uniVersion);
   1172     UBool isAtLeastUCA62 = uprv_memcmp(uniVersion, v62, 4) >= 0;
   1173 
   1174     LocalPointer<Collator> coll(Collator::createInstance(Locale::getRoot(), status));
   1175     if(U_FAILURE(status)) {
   1176         errcheckln(status, "Couldn't open UCA collator");
   1177         return;
   1178     }
   1179     coll->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status);
   1180     coll->setAttribute(UCOL_CASE_FIRST, UCOL_OFF, status);
   1181     coll->setAttribute(UCOL_CASE_LEVEL, UCOL_OFF, status);
   1182     coll->setAttribute(UCOL_STRENGTH, isAtLeastUCA62 ? UCOL_IDENTICAL : UCOL_TERTIARY, status);
   1183     coll->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_NON_IGNORABLE, status);
   1184 
   1185     int32_t noSpawned = 0;
   1186     int32_t spawnResult = 0;
   1187     LocalArray<CollatorThreadTest> tests(new CollatorThreadTest[kCollatorThreadThreads]);
   1188 
   1189     logln(UnicodeString("Spawning: ") + kCollatorThreadThreads + " threads * " + kFormatThreadIterations + " iterations each.");
   1190     int32_t j = 0;
   1191     for(j = 0; j < kCollatorThreadThreads; j++) {
   1192         //logln("Setting collator %i", j);
   1193         tests[j].setCollator(coll.getAlias(), lines.getAlias(), lineNum, isAtLeastUCA62);
   1194     }
   1195     for(j = 0; j < kCollatorThreadThreads; j++) {
   1196         log("%i ", j);
   1197         spawnResult = tests[j].start();
   1198         if(spawnResult != 0) {
   1199             infoln("THREAD INFO: Couldn't spawn more than %i threads", noSpawned);
   1200             break;
   1201         }
   1202         noSpawned++;
   1203     }
   1204     logln("Spawned all");
   1205     if (noSpawned == 0) {
   1206         errln("No threads could be spawned.");
   1207         return;
   1208     }
   1209 
   1210     for(int32_t patience = kCollatorThreadPatience;patience > 0; patience --)
   1211     {
   1212         logln("Waiting...");
   1213 
   1214         int32_t i;
   1215         int32_t terrs = 0;
   1216         int32_t completed =0;
   1217 
   1218         for(i=0;i<kCollatorThreadThreads;i++)
   1219         {
   1220             if (tests[i].isRunning() == FALSE)
   1221             {
   1222                 completed++;
   1223 
   1224                 //logln(UnicodeString("Test #") + i + " is complete.. ");
   1225 
   1226                 UnicodeString theErr;
   1227                 if(tests[i].getError(theErr))
   1228                 {
   1229                     terrs++;
   1230                     errln(UnicodeString("#") + i + ": " + theErr);
   1231                 }
   1232                 // print out the error, too, if any.
   1233             }
   1234         }
   1235         logln("Completed %i tests", completed);
   1236 
   1237         if(completed == noSpawned)
   1238         {
   1239             logln("Done! All %i tests are finished", noSpawned);
   1240 
   1241             if(terrs)
   1242             {
   1243                 errln("There were errors.");
   1244                 SimpleThread::errorFunc();
   1245             }
   1246             return;
   1247         }
   1248 
   1249         SimpleThread::sleep(900);
   1250     }
   1251     errln("patience exceeded. ");
   1252     SimpleThread::errorFunc();
   1253 }
   1254 
   1255 #endif /* #if !UCONFIG_NO_COLLATION */
   1256 
   1257 
   1258 
   1259 
   1260 //-------------------------------------------------------------------------------------------
   1261 //
   1262 //   StringThreadTest2
   1263 //
   1264 //-------------------------------------------------------------------------------------------
   1265 
   1266 const int kStringThreadIterations = 2500;// # of iterations per thread
   1267 const int kStringThreadThreads    = 10;  // # of threads to spawn
   1268 const int kStringThreadPatience   = 120; // time in seconds to wait for all threads
   1269 
   1270 
   1271 class StringThreadTest2 : public ThreadWithStatus
   1272 {
   1273 public:
   1274     int                 fNum;
   1275     int                 fTraceInfo;
   1276     const UnicodeString *fSharedString;
   1277 
   1278     StringThreadTest2(const UnicodeString *sharedString, int num) // constructor is NOT multithread safe.
   1279         : ThreadWithStatus(),
   1280         fNum(num),
   1281         fTraceInfo(0),
   1282         fSharedString(sharedString)
   1283     {
   1284     };
   1285 
   1286 
   1287     virtual void run()
   1288     {
   1289         fTraceInfo    = 1;
   1290         int loopCount = 0;
   1291 
   1292         for (loopCount = 0; loopCount < kStringThreadIterations; loopCount++) {
   1293             if (*fSharedString != "This is the original test string.") {
   1294                 error("Original string is corrupt.");
   1295                 break;
   1296             }
   1297             UnicodeString s1 = *fSharedString;
   1298             s1 += "cat this";
   1299             UnicodeString s2(s1);
   1300             UnicodeString s3 = *fSharedString;
   1301             s2 = s3;
   1302             s3.truncate(12);
   1303             s2.truncate(0);
   1304         }
   1305 
   1306         //  while (fNum == 4) {SimpleThread::sleep(10000);}   // Force a failure by preventing thread from finishing
   1307         fTraceInfo = 2;
   1308     }
   1309 
   1310 };
   1311 
   1312 // ** The actual test function.
   1313 
   1314 void MultithreadTest::TestString()
   1315 {
   1316     int     patience;
   1317     int     terrs = 0;
   1318     int     j;
   1319 
   1320     UnicodeString *testString = new UnicodeString("This is the original test string.");
   1321 
   1322     // Not using LocalArray<StringThreadTest2> tests[kStringThreadThreads];
   1323     // because we don't always want to delete them.
   1324     // See the comments below the cleanupAndReturn label.
   1325     StringThreadTest2  *tests[kStringThreadThreads];
   1326     for(j = 0; j < kStringThreadThreads; j++) {
   1327         tests[j] = new StringThreadTest2(testString, j);
   1328     }
   1329 
   1330     logln(UnicodeString("Spawning: ") + kStringThreadThreads + " threads * " + kStringThreadIterations + " iterations each.");
   1331     for(j = 0; j < kStringThreadThreads; j++) {
   1332         int32_t threadStatus = tests[j]->start();
   1333         if (threadStatus != 0) {
   1334             errln("System Error %d starting thread number %d.", threadStatus, j);
   1335             SimpleThread::errorFunc();
   1336             goto cleanupAndReturn;
   1337         }
   1338     }
   1339 
   1340     for(patience = kStringThreadPatience;patience > 0; patience --)
   1341     {
   1342         logln("Waiting...");
   1343 
   1344         int32_t i;
   1345         terrs = 0;
   1346         int32_t completed =0;
   1347 
   1348         for(i=0;i<kStringThreadThreads;i++) {
   1349             if (tests[i]->isRunning() == FALSE)
   1350             {
   1351                 completed++;
   1352 
   1353                 logln(UnicodeString("Test #") + i + " is complete.. ");
   1354 
   1355                 UnicodeString theErr;
   1356                 if(tests[i]->getError(theErr))
   1357                 {
   1358                     terrs++;
   1359                     errln(UnicodeString("#") + i + ": " + theErr);
   1360                 }
   1361                 // print out the error, too, if any.
   1362             }
   1363         }
   1364 
   1365         if(completed == kStringThreadThreads)
   1366         {
   1367             logln("Done!");
   1368             if(terrs) {
   1369                 errln("There were errors.");
   1370             }
   1371             break;
   1372         }
   1373 
   1374         SimpleThread::sleep(900);
   1375     }
   1376 
   1377     if (patience <= 0) {
   1378         errln("patience exceeded. ");
   1379         // while (TRUE) {SimpleThread::sleep(10000);}   // TODO:   for debugging.  Sleep forever on failure.
   1380         terrs++;
   1381     }
   1382 
   1383     if (terrs > 0) {
   1384         SimpleThread::errorFunc();
   1385     }
   1386 
   1387 cleanupAndReturn:
   1388     if (terrs == 0) {
   1389         /*
   1390         Don't clean up if there are errors. This prevents crashes if the
   1391         threads are still running and using this data. This will only happen
   1392         if there is an error with the test, ICU, or the machine is too slow.
   1393         It's better to leak than crash.
   1394         */
   1395         for(j = 0; j < kStringThreadThreads; j++) {
   1396             delete tests[j];
   1397         }
   1398         delete testString;
   1399     }
   1400 }
   1401 
   1402 #endif // ICU_USE_THREADS
   1403