Home | History | Annotate | Download | only in intltest
      1 /********************************************************************
      2  * COPYRIGHT:
      3  * Copyright (c) 1999-2013, 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 = 100;  // # 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 static 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  * Class for thread-safe (theoretically) format.
    684  *
    685  *
    686  * Its constructor, destructor, and init/fini are NOT thread safe.
    687  */
    688 class ThreadSafeFormat {
    689 public:
    690   /* give a unique offset to each thread */
    691   ThreadSafeFormat();
    692   UBool doStuff(int32_t offset, UnicodeString &appendErr, UErrorCode &status);
    693 private:
    694   LocalPointer<NumberFormat> fFormat; // formtter - default constructed currency
    695   Formattable  fYDDThing;    // Formattable currency - YDD
    696   Formattable  fBBDThing;   // Formattable currency - BBD
    697 
    698   // statics
    699 private:
    700   static LocalPointer<NumberFormat> gFormat;
    701   static NumberFormat *createFormat(UErrorCode &status);
    702   static Formattable gYDDThing, gBBDThing;
    703 public:
    704   static void init(UErrorCode &status); // avoid static init.
    705   static void fini(UErrorCode &status); // avoid static fini
    706 };
    707 
    708 LocalPointer<NumberFormat> ThreadSafeFormat::gFormat;
    709 Formattable ThreadSafeFormat::gYDDThing;
    710 Formattable ThreadSafeFormat::gBBDThing;
    711 UnicodeString gYDDStr, gBBDStr;
    712 NumberFormat *ThreadSafeFormat::createFormat(UErrorCode &status) {
    713   LocalPointer<NumberFormat> fmt(NumberFormat::createCurrencyInstance(Locale::getUS(), status));
    714   return fmt.orphan();
    715 }
    716 
    717 
    718 static const UChar kYDD[] = { 0x59, 0x44, 0x44, 0x00 };
    719 static const UChar kBBD[] = { 0x42, 0x42, 0x44, 0x00 };
    720 static const UChar kUSD[] = { 0x55, 0x53, 0x44, 0x00 };
    721 
    722 void ThreadSafeFormat::init(UErrorCode &status) {
    723   gFormat.adoptInstead(createFormat(status));
    724   gYDDThing.adoptObject(new CurrencyAmount(123.456, kYDD, status));
    725   gBBDThing.adoptObject(new CurrencyAmount(987.654, kBBD, status));
    726   if (U_FAILURE(status)) {
    727       return;
    728   }
    729   gFormat->format(gYDDThing, gYDDStr, NULL, status);
    730   gFormat->format(gBBDThing, gBBDStr, NULL, status);
    731 }
    732 
    733 void ThreadSafeFormat::fini(UErrorCode &/*status*/) {
    734   gFormat.adoptInstead(NULL);
    735 }
    736 
    737 ThreadSafeFormat::ThreadSafeFormat() {
    738 }
    739 
    740 UBool ThreadSafeFormat::doStuff(int32_t offset, UnicodeString &appendErr, UErrorCode &status) {
    741   UBool okay = TRUE;
    742   if(fFormat.isNull()) {
    743     fFormat.adoptInstead(createFormat(status));
    744   }
    745 
    746   if(u_strcmp(fFormat->getCurrency(), kUSD)) {
    747     appendErr.append("fFormat currency != ")
    748       .append(kUSD)
    749       .append(", =")
    750       .append(fFormat->getCurrency())
    751       .append("! ");
    752     okay = FALSE;
    753   }
    754 
    755   if(u_strcmp(gFormat->getCurrency(), kUSD)) {
    756     appendErr.append("gFormat currency != ")
    757       .append(kUSD)
    758       .append(", =")
    759       .append(gFormat->getCurrency())
    760       .append("! ");
    761     okay = FALSE;
    762   }
    763   UnicodeString str;
    764   const UnicodeString *o=NULL;
    765   Formattable f;
    766   const NumberFormat *nf = NULL; // only operate on it as const.
    767   switch(offset%4) {
    768   case 0:  f = gYDDThing;  o = &gYDDStr;  nf = gFormat.getAlias();  break;
    769   case 1:  f = gBBDThing;  o = &gBBDStr;  nf = gFormat.getAlias();  break;
    770   case 2:  f = gYDDThing;  o = &gYDDStr;  nf = fFormat.getAlias();  break;
    771   case 3:  f = gBBDThing;  o = &gBBDStr;  nf = fFormat.getAlias();  break;
    772   }
    773   nf->format(f, str, NULL, status);
    774 
    775   if(*o != str) {
    776     appendErr.append(showDifference(*o, str));
    777     okay = FALSE;
    778   }
    779   return okay;
    780 }
    781 
    782 UBool U_CALLCONV isAcceptable(void *, const char *, const char *, const UDataInfo *) {
    783     return TRUE;
    784 }
    785 
    786 //static UMTX debugMutex = NULL;
    787 //static UMTX gDebugMutex;
    788 
    789 
    790 class FormatThreadTest : public ThreadWithStatus
    791 {
    792 public:
    793     int     fNum;
    794     int     fTraceInfo;
    795 
    796     ThreadSafeFormat fTSF;
    797 
    798     FormatThreadTest() // constructor is NOT multithread safe.
    799         : ThreadWithStatus(),
    800         fNum(0),
    801         fTraceInfo(0),
    802         fOffset(0)
    803         // the locale to use
    804     {
    805         static int32_t fgOffset = 0;
    806         fgOffset += 3;
    807         fOffset = fgOffset;
    808     }
    809 
    810 
    811     virtual void run()
    812     {
    813         fTraceInfo                     = 1;
    814         LocalPointer<NumberFormat> percentFormatter;
    815         UErrorCode status = U_ZERO_ERROR;
    816 
    817 #if 0
    818         // debugging code,
    819         for (int i=0; i<4000; i++) {
    820             status = U_ZERO_ERROR;
    821             UDataMemory *data1 = udata_openChoice(0, "res", "en_US", isAcceptable, 0, &status);
    822             UDataMemory *data2 = udata_openChoice(0, "res", "fr", isAcceptable, 0, &status);
    823             udata_close(data1);
    824             udata_close(data2);
    825             if (U_FAILURE(status)) {
    826                 error("udata_openChoice failed.\n");
    827                 break;
    828             }
    829         }
    830         return;
    831 #endif
    832 
    833 #if 0
    834         // debugging code,
    835         int m;
    836         for (m=0; m<4000; m++) {
    837             status         = U_ZERO_ERROR;
    838             UResourceBundle *res   = NULL;
    839             const char *localeName = NULL;
    840 
    841             Locale  loc = Locale::getEnglish();
    842 
    843             localeName = loc.getName();
    844             // localeName = "en";
    845 
    846             // ResourceBundle bund = ResourceBundle(0, loc, status);
    847             //umtx_lock(&gDebugMutex);
    848             res = ures_open(NULL, localeName, &status);
    849             //umtx_unlock(&gDebugMutex);
    850 
    851             //umtx_lock(&gDebugMutex);
    852             ures_close(res);
    853             //umtx_unlock(&gDebugMutex);
    854 
    855             if (U_FAILURE(status)) {
    856                 error("Resource bundle construction failed.\n");
    857                 break;
    858             }
    859         }
    860         return;
    861 #endif
    862 
    863         // Keep this data here to avoid static initialization.
    864         FormatThreadTestData kNumberFormatTestData[] =
    865         {
    866             FormatThreadTestData((double)5.0, UnicodeString("5", "")),
    867                 FormatThreadTestData( 6.0, UnicodeString("6", "")),
    868                 FormatThreadTestData( 20.0, UnicodeString("20", "")),
    869                 FormatThreadTestData( 8.0, UnicodeString("8", "")),
    870                 FormatThreadTestData( 8.3, UnicodeString("8.3", "")),
    871                 FormatThreadTestData( 12345, UnicodeString("12,345", "")),
    872                 FormatThreadTestData( 81890.23, UnicodeString("81,890.23", "")),
    873         };
    874         int32_t kNumberFormatTestDataLength = (int32_t)(sizeof(kNumberFormatTestData) /
    875                                                         sizeof(kNumberFormatTestData[0]));
    876 
    877         // Keep this data here to avoid static initialization.
    878         FormatThreadTestData kPercentFormatTestData[] =
    879         {
    880             FormatThreadTestData((double)5.0, CharsToUnicodeString("500\\u00a0%")),
    881                 FormatThreadTestData( 1.0, CharsToUnicodeString("100\\u00a0%")),
    882                 FormatThreadTestData( 0.26, CharsToUnicodeString("26\\u00a0%")),
    883                 FormatThreadTestData(
    884                    16384.99, CharsToUnicodeString("1\\u00a0638\\u00a0499\\u00a0%")), // U+00a0 = NBSP
    885                 FormatThreadTestData(
    886                     81890.23, CharsToUnicodeString("8\\u00a0189\\u00a0023\\u00a0%")),
    887         };
    888         int32_t kPercentFormatTestDataLength =
    889                 (int32_t)(sizeof(kPercentFormatTestData) / sizeof(kPercentFormatTestData[0]));
    890         int32_t iteration;
    891 
    892         status = U_ZERO_ERROR;
    893         LocalPointer<NumberFormat> formatter(NumberFormat::createInstance(Locale::getEnglish(),status));
    894         if(U_FAILURE(status)) {
    895             error("Error on NumberFormat::createInstance().");
    896             goto cleanupAndReturn;
    897         }
    898 
    899         percentFormatter.adoptInstead(NumberFormat::createPercentInstance(Locale::getFrench(),status));
    900         if(U_FAILURE(status))             {
    901             error("Error on NumberFormat::createPercentInstance().");
    902             goto cleanupAndReturn;
    903         }
    904 
    905         for(iteration = 0;!getError() && iteration<kFormatThreadIterations;iteration++)
    906         {
    907 
    908             int32_t whichLine = (iteration + fOffset)%kNumberFormatTestDataLength;
    909 
    910             UnicodeString  output;
    911 
    912             formatter->format(kNumberFormatTestData[whichLine].number, output);
    913 
    914             if(0 != output.compare(kNumberFormatTestData[whichLine].string)) {
    915                 error("format().. expected " + kNumberFormatTestData[whichLine].string
    916                         + " got " + output);
    917                 goto cleanupAndReturn;
    918             }
    919 
    920             // Now check percent.
    921             output.remove();
    922             whichLine = (iteration + fOffset)%kPercentFormatTestDataLength;
    923 
    924             percentFormatter->format(kPercentFormatTestData[whichLine].number, output);
    925             if(0 != output.compare(kPercentFormatTestData[whichLine].string))
    926             {
    927                 error("percent format().. \n" +
    928                         showDifference(kPercentFormatTestData[whichLine].string,output));
    929                 goto cleanupAndReturn;
    930             }
    931 
    932             // Test message error
    933             const int       kNumberOfMessageTests = 3;
    934             UErrorCode      statusToCheck;
    935             UnicodeString   patternToCheck;
    936             Locale          messageLocale;
    937             Locale          countryToCheck;
    938             double          currencyToCheck;
    939 
    940             UnicodeString   expected;
    941 
    942             // load the cases.
    943             switch((iteration+fOffset) % kNumberOfMessageTests)
    944             {
    945             default:
    946             case 0:
    947                 statusToCheck=                      U_FILE_ACCESS_ERROR;
    948                 patternToCheck=        "0:Someone from {2} is receiving a #{0}"
    949                                        " error - {1}. Their telephone call is costing "
    950                                        "{3,number,currency}."; // number,currency
    951                 messageLocale=                      Locale("en","US");
    952                 countryToCheck=                     Locale("","HR");
    953                 currencyToCheck=                    8192.77;
    954                 expected=  "0:Someone from Croatia is receiving a #4 error - "
    955                             "U_FILE_ACCESS_ERROR. Their telephone call is costing $8,192.77.";
    956                 break;
    957             case 1:
    958                 statusToCheck=                      U_INDEX_OUTOFBOUNDS_ERROR;
    959                 patternToCheck=                     "1:A customer in {2} is receiving a #{0} error - {1}. Their telephone call is costing {3,number,currency}."; // number,currency
    960                 messageLocale=                      Locale("de","DE@currency=DEM");
    961                 countryToCheck=                     Locale("","BF");
    962                 currencyToCheck=                    2.32;
    963                 expected=                           CharsToUnicodeString(
    964                                                     "1:A customer in Burkina Faso is receiving a #8 error - U_INDEX_OUTOFBOUNDS_ERROR. Their telephone call is costing 2,32\\u00A0DEM.");
    965                 break;
    966             case 2:
    967                 statusToCheck=                      U_MEMORY_ALLOCATION_ERROR;
    968                 patternToCheck=   "2:user in {2} is receiving a #{0} error - {1}. "
    969                                   "They insist they just spent {3,number,currency} "
    970                                   "on memory."; // number,currency
    971                 messageLocale=                      Locale("de","AT@currency=ATS"); // Austrian German
    972                 countryToCheck=                     Locale("","US"); // hmm
    973                 currencyToCheck=                    40193.12;
    974                 expected=       CharsToUnicodeString(
    975                             "2:user in Vereinigte Staaten is receiving a #7 error"
    976                             " - U_MEMORY_ALLOCATION_ERROR. They insist they just spent"
    977                             " \\u00f6S\\u00A040.193,12 on memory.");
    978                 break;
    979             }
    980 
    981             UnicodeString result;
    982             UErrorCode status = U_ZERO_ERROR;
    983             formatErrorMessage(status,patternToCheck,messageLocale,statusToCheck,
    984                                 countryToCheck,currencyToCheck,result);
    985             if(U_FAILURE(status))
    986             {
    987                 UnicodeString tmp(u_errorName(status));
    988                 error("Failure on message format, pattern=" + patternToCheck +
    989                         ", error = " + tmp);
    990                 goto cleanupAndReturn;
    991             }
    992 
    993             if(result != expected)
    994             {
    995                 error("PatternFormat: \n" + showDifference(expected,result));
    996                 goto cleanupAndReturn;
    997             }
    998             // test the Thread Safe Format
    999             UnicodeString appendErr;
   1000             if(!fTSF.doStuff(fNum, appendErr, status)) {
   1001               error(appendErr);
   1002               goto cleanupAndReturn;
   1003             }
   1004         }   /*  end of for loop */
   1005 
   1006 
   1007 
   1008 cleanupAndReturn:
   1009         //  while (fNum == 4) {SimpleThread::sleep(10000);}   // Force a failure by preventing thread from finishing
   1010         fTraceInfo = 2;
   1011     }
   1012 
   1013 private:
   1014     int32_t fOffset; // where we are testing from.
   1015 };
   1016 
   1017 // ** The actual test function.
   1018 
   1019 void MultithreadTest::TestThreadedIntl()
   1020 {
   1021     int i;
   1022     UnicodeString theErr;
   1023     UBool   haveDisplayedInfo[kFormatThreadThreads];
   1024     static const int32_t PATIENCE_SECONDS = 45;
   1025 
   1026     UErrorCode threadSafeErr = U_ZERO_ERROR;
   1027 
   1028     ThreadSafeFormat::init(threadSafeErr);
   1029     assertSuccess("initializing ThreadSafeFormat", threadSafeErr, TRUE);
   1030 
   1031     //
   1032     //  Create and start the test threads
   1033     //
   1034     logln("Spawning: %d threads * %d iterations each.",
   1035                 kFormatThreadThreads, kFormatThreadIterations);
   1036     LocalArray<FormatThreadTest> tests(new FormatThreadTest[kFormatThreadThreads]);
   1037     for(int32_t j = 0; j < kFormatThreadThreads; j++) {
   1038         tests[j].fNum = j;
   1039         int32_t threadStatus = tests[j].start();
   1040         if (threadStatus != 0) {
   1041             errln("System Error %d starting thread number %d.", threadStatus, j);
   1042             SimpleThread::errorFunc();
   1043             return;
   1044         }
   1045         haveDisplayedInfo[j] = FALSE;
   1046     }
   1047 
   1048 
   1049     // Spin, waiting for the test threads to finish.
   1050     UBool   stillRunning;
   1051     UDate startTime, endTime;
   1052     startTime = Calendar::getNow();
   1053     double lastComplaint = 0;
   1054     do {
   1055         /*  Spin until the test threads  complete. */
   1056         stillRunning = FALSE;
   1057         endTime = Calendar::getNow();
   1058         double elapsedSeconds =  ((int32_t)(endTime - startTime)/U_MILLIS_PER_SECOND);
   1059         if (elapsedSeconds > PATIENCE_SECONDS) {
   1060             errln("Patience exceeded. Test is taking too long.");
   1061             return;
   1062         } else if((elapsedSeconds-lastComplaint) > 2.0) {
   1063             infoln("%.1f seconds elapsed (still waiting..)", elapsedSeconds);
   1064             lastComplaint = elapsedSeconds;
   1065         }
   1066         /*
   1067          The following sleep must be here because the *BSD operating systems
   1068          have a brain dead thread scheduler. They starve the child threads from
   1069          CPU time.
   1070         */
   1071         SimpleThread::sleep(1); // yield
   1072         for(i=0;i<kFormatThreadThreads;i++) {
   1073             if (tests[i].isRunning()) {
   1074                 stillRunning = TRUE;
   1075             } else if (haveDisplayedInfo[i] == FALSE) {
   1076                 logln("Thread # %d is complete..", i);
   1077                 if(tests[i].getError(theErr)) {
   1078                     dataerrln(UnicodeString("#") + i + ": " + theErr);
   1079                     SimpleThread::errorFunc();
   1080                 }
   1081                 haveDisplayedInfo[i] = TRUE;
   1082             }
   1083         }
   1084     } while (stillRunning);
   1085 
   1086     //
   1087     //  All threads have finished.
   1088     //
   1089     ThreadSafeFormat::fini(threadSafeErr);
   1090     assertSuccess("finalizing ThreadSafeFormat", threadSafeErr, TRUE);
   1091 }
   1092 #endif /* #if !UCONFIG_NO_FORMATTING */
   1093 
   1094 
   1095 
   1096 
   1097 
   1098 //-------------------------------------------------------------------------------------------
   1099 //
   1100 // Collation threading test
   1101 //
   1102 //-------------------------------------------------------------------------------------------
   1103 #if !UCONFIG_NO_COLLATION
   1104 
   1105 #define kCollatorThreadThreads   10  // # of threads to spawn
   1106 #define kCollatorThreadPatience kCollatorThreadThreads*30
   1107 
   1108 struct Line {
   1109     UChar buff[25];
   1110     int32_t buflen;
   1111 } ;
   1112 
   1113 static UBool
   1114 skipLineBecauseOfBug(const UChar *s, int32_t length) {
   1115     // TODO: Fix ICU ticket #8052
   1116     if(length >= 3 &&
   1117             (s[0] == 0xfb2 || s[0] == 0xfb3) &&
   1118             s[1] == 0x334 &&
   1119             (s[2] == 0xf73 || s[2] == 0xf75 || s[2] == 0xf81)) {
   1120         return TRUE;
   1121     }
   1122     return FALSE;
   1123 }
   1124 
   1125 static UCollationResult
   1126 normalizeResult(int32_t result) {
   1127     return result<0 ? UCOL_LESS : result==0 ? UCOL_EQUAL : UCOL_GREATER;
   1128 }
   1129 
   1130 class CollatorThreadTest : public ThreadWithStatus
   1131 {
   1132 private:
   1133     const Collator *coll;
   1134     const Line *lines;
   1135     int32_t noLines;
   1136     UBool isAtLeastUCA62;
   1137 public:
   1138     CollatorThreadTest()  : ThreadWithStatus(),
   1139         coll(NULL),
   1140         lines(NULL),
   1141         noLines(0),
   1142         isAtLeastUCA62(TRUE)
   1143     {
   1144     };
   1145     void setCollator(Collator *c, Line *l, int32_t nl, UBool atLeastUCA62)
   1146     {
   1147         coll = c;
   1148         lines = l;
   1149         noLines = nl;
   1150         isAtLeastUCA62 = atLeastUCA62;
   1151     }
   1152     virtual void run() {
   1153         uint8_t sk1[1024], sk2[1024];
   1154         uint8_t *oldSk = NULL, *newSk = sk1;
   1155         int32_t oldLen = 0;
   1156         int32_t prev = 0;
   1157         int32_t i = 0;
   1158 
   1159         for(i = 0; i < noLines; i++) {
   1160             if(lines[i].buflen == 0) { continue; }
   1161 
   1162             if(skipLineBecauseOfBug(lines[i].buff, lines[i].buflen)) { continue; }
   1163 
   1164             int32_t resLen = coll->getSortKey(lines[i].buff, lines[i].buflen, newSk, 1024);
   1165 
   1166             if(oldSk != NULL) {
   1167                 int32_t skres = strcmp((char *)oldSk, (char *)newSk);
   1168                 int32_t cmpres = coll->compare(lines[prev].buff, lines[prev].buflen, lines[i].buff, lines[i].buflen);
   1169                 int32_t cmpres2 = coll->compare(lines[i].buff, lines[i].buflen, lines[prev].buff, lines[prev].buflen);
   1170 
   1171                 if(cmpres != -cmpres2) {
   1172                     error(UnicodeString("Compare result not symmetrical on line ") + (i + 1));
   1173                     break;
   1174                 }
   1175 
   1176                 if(cmpres != normalizeResult(skres)) {
   1177                     error(UnicodeString("Difference between coll->compare and sortkey compare on line ") + (i + 1));
   1178                     break;
   1179                 }
   1180 
   1181                 int32_t res = cmpres;
   1182                 if(res == 0 && !isAtLeastUCA62) {
   1183                     // Up to UCA 6.1, the collation test files use a custom tie-breaker,
   1184                     // comparing the raw input strings.
   1185                     res = u_strcmpCodePointOrder(lines[prev].buff, lines[i].buff);
   1186                     // Starting with UCA 6.2, the collation test files use the standard UCA tie-breaker,
   1187                     // comparing the NFD versions of the input strings,
   1188                     // which we do via setting strength=identical.
   1189                 }
   1190                 if(res > 0) {
   1191                     error(UnicodeString("Line is not greater or equal than previous line, for line ") + (i + 1));
   1192                     break;
   1193                 }
   1194             }
   1195 
   1196             oldSk = newSk;
   1197             oldLen = resLen;
   1198             (void)oldLen;   // Suppress set but not used warning.
   1199             prev = i;
   1200 
   1201             newSk = (newSk == sk1)?sk2:sk1;
   1202         }
   1203     }
   1204 };
   1205 
   1206 void MultithreadTest::TestCollators()
   1207 {
   1208 
   1209     UErrorCode status = U_ZERO_ERROR;
   1210     FILE *testFile = NULL;
   1211     char testDataPath[1024];
   1212     strcpy(testDataPath, IntlTest::getSourceTestData(status));
   1213     if (U_FAILURE(status)) {
   1214         errln("ERROR: could not open test data %s", u_errorName(status));
   1215         return;
   1216     }
   1217     strcat(testDataPath, "CollationTest_");
   1218 
   1219     const char* type = "NON_IGNORABLE";
   1220 
   1221     const char *ext = ".txt";
   1222     if(testFile) {
   1223         fclose(testFile);
   1224     }
   1225     char buffer[1024];
   1226     strcpy(buffer, testDataPath);
   1227     strcat(buffer, type);
   1228     size_t bufLen = strlen(buffer);
   1229 
   1230     // we try to open 3 files:
   1231     // path/CollationTest_type.txt
   1232     // path/CollationTest_type_SHORT.txt
   1233     // path/CollationTest_type_STUB.txt
   1234     // we are going to test with the first one that we manage to open.
   1235 
   1236     strcpy(buffer+bufLen, ext);
   1237 
   1238     testFile = fopen(buffer, "rb");
   1239 
   1240     if(testFile == 0) {
   1241         strcpy(buffer+bufLen, "_SHORT");
   1242         strcat(buffer, ext);
   1243         testFile = fopen(buffer, "rb");
   1244 
   1245         if(testFile == 0) {
   1246             strcpy(buffer+bufLen, "_STUB");
   1247             strcat(buffer, ext);
   1248             testFile = fopen(buffer, "rb");
   1249 
   1250             if (testFile == 0) {
   1251                 *(buffer+bufLen) = 0;
   1252                 dataerrln("could not open any of the conformance test files, tried opening base %s", buffer);
   1253                 return;
   1254             } else {
   1255                 infoln(
   1256                     "INFO: Working with the stub file.\n"
   1257                     "If you need the full conformance test, please\n"
   1258                     "download the appropriate data files from:\n"
   1259                     "http://source.icu-project.org/repos/icu/tools/trunk/unicodetools/com/ibm/text/data/");
   1260             }
   1261         }
   1262     }
   1263 
   1264     LocalArray<Line> lines(new Line[200000]);
   1265     memset(lines.getAlias(), 0, sizeof(Line)*200000);
   1266     int32_t lineNum = 0;
   1267 
   1268     UChar bufferU[1024];
   1269     uint32_t first = 0;
   1270 
   1271     while (fgets(buffer, 1024, testFile) != NULL) {
   1272         if(*buffer == 0 || buffer[0] == '#') {
   1273             // Store empty and comment lines so that errors are reported
   1274             // for the real test file lines.
   1275             lines[lineNum].buflen = 0;
   1276             lines[lineNum].buff[0] = 0;
   1277         } else {
   1278             int32_t buflen = u_parseString(buffer, bufferU, 1024, &first, &status);
   1279             lines[lineNum].buflen = buflen;
   1280             u_memcpy(lines[lineNum].buff, bufferU, buflen);
   1281             lines[lineNum].buff[buflen] = 0;
   1282         }
   1283         lineNum++;
   1284     }
   1285     fclose(testFile);
   1286     if(U_FAILURE(status)) {
   1287       dataerrln("Couldn't read the test file!");
   1288       return;
   1289     }
   1290 
   1291     UVersionInfo uniVersion;
   1292     static const UVersionInfo v62 = { 6, 2, 0, 0 };
   1293     u_getUnicodeVersion(uniVersion);
   1294     UBool isAtLeastUCA62 = uprv_memcmp(uniVersion, v62, 4) >= 0;
   1295 
   1296     LocalPointer<Collator> coll(Collator::createInstance(Locale::getRoot(), status));
   1297     if(U_FAILURE(status)) {
   1298         errcheckln(status, "Couldn't open UCA collator");
   1299         return;
   1300     }
   1301     coll->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status);
   1302     coll->setAttribute(UCOL_CASE_FIRST, UCOL_OFF, status);
   1303     coll->setAttribute(UCOL_CASE_LEVEL, UCOL_OFF, status);
   1304     coll->setAttribute(UCOL_STRENGTH, isAtLeastUCA62 ? UCOL_IDENTICAL : UCOL_TERTIARY, status);
   1305     coll->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_NON_IGNORABLE, status);
   1306 
   1307     int32_t noSpawned = 0;
   1308     int32_t spawnResult = 0;
   1309     LocalArray<CollatorThreadTest> tests(new CollatorThreadTest[kCollatorThreadThreads]);
   1310 
   1311     logln(UnicodeString("Spawning: ") + kCollatorThreadThreads + " threads * " + kFormatThreadIterations + " iterations each.");
   1312     int32_t j = 0;
   1313     for(j = 0; j < kCollatorThreadThreads; j++) {
   1314         //logln("Setting collator %i", j);
   1315         tests[j].setCollator(coll.getAlias(), lines.getAlias(), lineNum, isAtLeastUCA62);
   1316     }
   1317     for(j = 0; j < kCollatorThreadThreads; j++) {
   1318         log("%i ", j);
   1319         spawnResult = tests[j].start();
   1320         if(spawnResult != 0) {
   1321             infoln("THREAD INFO: Couldn't spawn more than %i threads", noSpawned);
   1322             break;
   1323         }
   1324         noSpawned++;
   1325     }
   1326     logln("Spawned all");
   1327     if (noSpawned == 0) {
   1328         errln("No threads could be spawned.");
   1329         return;
   1330     }
   1331 
   1332     for(int32_t patience = kCollatorThreadPatience;patience > 0; patience --)
   1333     {
   1334         logln("Waiting...");
   1335 
   1336         int32_t i;
   1337         int32_t terrs = 0;
   1338         int32_t completed =0;
   1339 
   1340         for(i=0;i<kCollatorThreadThreads;i++)
   1341         {
   1342             if (tests[i].isRunning() == FALSE)
   1343             {
   1344                 completed++;
   1345 
   1346                 //logln(UnicodeString("Test #") + i + " is complete.. ");
   1347 
   1348                 UnicodeString theErr;
   1349                 if(tests[i].getError(theErr))
   1350                 {
   1351                     terrs++;
   1352                     errln(UnicodeString("#") + i + ": " + theErr);
   1353                 }
   1354                 // print out the error, too, if any.
   1355             }
   1356         }
   1357         logln("Completed %i tests", completed);
   1358 
   1359         if(completed == noSpawned)
   1360         {
   1361             logln("Done! All %i tests are finished", noSpawned);
   1362 
   1363             if(terrs)
   1364             {
   1365                 errln("There were errors.");
   1366                 SimpleThread::errorFunc();
   1367             }
   1368             return;
   1369         }
   1370 
   1371         SimpleThread::sleep(900);
   1372     }
   1373     errln("patience exceeded. ");
   1374     SimpleThread::errorFunc();
   1375 }
   1376 
   1377 #endif /* #if !UCONFIG_NO_COLLATION */
   1378 
   1379 
   1380 
   1381 
   1382 //-------------------------------------------------------------------------------------------
   1383 //
   1384 //   StringThreadTest2
   1385 //
   1386 //-------------------------------------------------------------------------------------------
   1387 
   1388 const int kStringThreadIterations = 2500;// # of iterations per thread
   1389 const int kStringThreadThreads    = 10;  // # of threads to spawn
   1390 const int kStringThreadPatience   = 120; // time in seconds to wait for all threads
   1391 
   1392 
   1393 class StringThreadTest2 : public ThreadWithStatus
   1394 {
   1395 public:
   1396     int                 fNum;
   1397     int                 fTraceInfo;
   1398     const UnicodeString *fSharedString;
   1399 
   1400     StringThreadTest2(const UnicodeString *sharedString, int num) // constructor is NOT multithread safe.
   1401         : ThreadWithStatus(),
   1402         fNum(num),
   1403         fTraceInfo(0),
   1404         fSharedString(sharedString)
   1405     {
   1406     };
   1407 
   1408 
   1409     virtual void run()
   1410     {
   1411         fTraceInfo    = 1;
   1412         int loopCount = 0;
   1413 
   1414         for (loopCount = 0; loopCount < kStringThreadIterations; loopCount++) {
   1415             if (*fSharedString != "This is the original test string.") {
   1416                 error("Original string is corrupt.");
   1417                 break;
   1418             }
   1419             UnicodeString s1 = *fSharedString;
   1420             s1 += "cat this";
   1421             UnicodeString s2(s1);
   1422             UnicodeString s3 = *fSharedString;
   1423             s2 = s3;
   1424             s3.truncate(12);
   1425             s2.truncate(0);
   1426         }
   1427 
   1428         //  while (fNum == 4) {SimpleThread::sleep(10000);}   // Force a failure by preventing thread from finishing
   1429         fTraceInfo = 2;
   1430     }
   1431 
   1432 };
   1433 
   1434 // ** The actual test function.
   1435 
   1436 void MultithreadTest::TestString()
   1437 {
   1438     int     patience;
   1439     int     terrs = 0;
   1440     int     j;
   1441 
   1442     UnicodeString *testString = new UnicodeString("This is the original test string.");
   1443 
   1444     // Not using LocalArray<StringThreadTest2> tests[kStringThreadThreads];
   1445     // because we don't always want to delete them.
   1446     // See the comments below the cleanupAndReturn label.
   1447     StringThreadTest2  *tests[kStringThreadThreads];
   1448     for(j = 0; j < kStringThreadThreads; j++) {
   1449         tests[j] = new StringThreadTest2(testString, j);
   1450     }
   1451 
   1452     logln(UnicodeString("Spawning: ") + kStringThreadThreads + " threads * " + kStringThreadIterations + " iterations each.");
   1453     for(j = 0; j < kStringThreadThreads; j++) {
   1454         int32_t threadStatus = tests[j]->start();
   1455         if (threadStatus != 0) {
   1456             errln("System Error %d starting thread number %d.", threadStatus, j);
   1457             SimpleThread::errorFunc();
   1458             goto cleanupAndReturn;
   1459         }
   1460     }
   1461 
   1462     for(patience = kStringThreadPatience;patience > 0; patience --)
   1463     {
   1464         logln("Waiting...");
   1465 
   1466         int32_t i;
   1467         terrs = 0;
   1468         int32_t completed =0;
   1469 
   1470         for(i=0;i<kStringThreadThreads;i++) {
   1471             if (tests[i]->isRunning() == FALSE)
   1472             {
   1473                 completed++;
   1474 
   1475                 logln(UnicodeString("Test #") + i + " is complete.. ");
   1476 
   1477                 UnicodeString theErr;
   1478                 if(tests[i]->getError(theErr))
   1479                 {
   1480                     terrs++;
   1481                     errln(UnicodeString("#") + i + ": " + theErr);
   1482                 }
   1483                 // print out the error, too, if any.
   1484             }
   1485         }
   1486 
   1487         if(completed == kStringThreadThreads)
   1488         {
   1489             logln("Done!");
   1490             if(terrs) {
   1491                 errln("There were errors.");
   1492             }
   1493             break;
   1494         }
   1495 
   1496         SimpleThread::sleep(900);
   1497     }
   1498 
   1499     if (patience <= 0) {
   1500         errln("patience exceeded. ");
   1501         // while (TRUE) {SimpleThread::sleep(10000);}   // TODO:   for debugging.  Sleep forever on failure.
   1502         terrs++;
   1503     }
   1504 
   1505     if (terrs > 0) {
   1506         SimpleThread::errorFunc();
   1507     }
   1508 
   1509 cleanupAndReturn:
   1510     if (terrs == 0) {
   1511         /*
   1512         Don't clean up if there are errors. This prevents crashes if the
   1513         threads are still running and using this data. This will only happen
   1514         if there is an error with the test, ICU, or the machine is too slow.
   1515         It's better to leak than crash.
   1516         */
   1517         for(j = 0; j < kStringThreadThreads; j++) {
   1518             delete tests[j];
   1519         }
   1520         delete testString;
   1521     }
   1522 }
   1523 
   1524 #endif // ICU_USE_THREADS
   1525