Home | History | Annotate | Download | only in intltest
      1 /********************************************************************
      2  * COPYRIGHT:
      3  * Copyright (c) 1999-2014, 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 #include "unicode/translit.h"
     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     case 6:
    199         name = "TestAnyTranslit";
    200         if (exec) {
    201             TestAnyTranslit();
    202         }
    203         break;
    204 
    205     default:
    206         name = "";
    207         break; //needed to end loop
    208     }
    209 }
    210 
    211 
    212 //-----------------------------------------------------------------------------------
    213 //
    214 //   TestThreads -- see if threads really work at all.
    215 //
    216 //   Set up N threads pointing at N chars. When they are started, they will
    217 //   each sleep 1 second and then set their chars. At the end we make sure they
    218 //   are all set.
    219 //
    220 //-----------------------------------------------------------------------------------
    221 #define THREADTEST_NRTHREADS 8
    222 #define ARABICSHAPE_THREADTEST 30
    223 
    224 class TestThreadsThread : public SimpleThread
    225 {
    226 public:
    227     TestThreadsThread(char* whatToChange) { fWhatToChange = whatToChange; }
    228     virtual void run() { SimpleThread::sleep(1000);
    229                          Mutex m;
    230                          *fWhatToChange = '*';
    231     }
    232 private:
    233     char *fWhatToChange;
    234 };
    235 //-----------------------------------------------------------------------------------
    236 //
    237 //   TestArabicShapeThreads -- see if calls to u_shapeArabic in many threads works successfully
    238 //
    239 //   Set up N threads pointing at N chars. When they are started, they will make calls to doTailTest which tests
    240 //   u_shapeArabic, if the calls are successful it will the set * chars.
    241 //   At the end we make sure all threads managed to run u_shapeArabic successfully.
    242 //   This is a unit test for ticket 9473
    243 //
    244 //-----------------------------------------------------------------------------------
    245 class TestArabicShapeThreads : public SimpleThread
    246 {
    247 public:
    248     TestArabicShapeThreads(char* whatToChange) { fWhatToChange = whatToChange;}
    249     virtual void run() {
    250 	    if(doTailTest()==TRUE)
    251 			*fWhatToChange = '*';
    252     }
    253 private:
    254     char *fWhatToChange;
    255 
    256 	UBool doTailTest(void) {
    257   static const UChar src[] = { 0x0020, 0x0633, 0 };
    258   static const UChar dst_old[] = { 0xFEB1, 0x200B,0 };
    259   static const UChar dst_new[] = { 0xFEB1, 0xFE73,0 };
    260   UChar dst[3] = { 0x0000, 0x0000,0 };
    261   int32_t length;
    262   UErrorCode status;
    263   IntlTest inteltst =  IntlTest();
    264 
    265   status = U_ZERO_ERROR;
    266   length = u_shapeArabic(src, -1, dst, LENGTHOF(dst),
    267                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_SEEN_TWOCELL_NEAR, &status);
    268   if(U_FAILURE(status)) {
    269 	   inteltst.errln("Fail: status %s\n", u_errorName(status));
    270 	return FALSE;
    271   } else if(length!=2) {
    272     inteltst.errln("Fail: len %d expected 3\n", length);
    273 	return FALSE;
    274   } else if(u_strncmp(dst,dst_old,LENGTHOF(dst))) {
    275     inteltst.errln("Fail: got U+%04X U+%04X expected U+%04X U+%04X\n",
    276             dst[0],dst[1],dst_old[0],dst_old[1]);
    277 	return FALSE;
    278   }
    279 
    280 
    281   //"Trying new tail
    282   status = U_ZERO_ERROR;
    283   length = u_shapeArabic(src, -1, dst, LENGTHOF(dst),
    284                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_SEEN_TWOCELL_NEAR|U_SHAPE_TAIL_NEW_UNICODE, &status);
    285   if(U_FAILURE(status)) {
    286     inteltst.errln("Fail: status %s\n", u_errorName(status));
    287 	return FALSE;
    288   } else if(length!=2) {
    289     inteltst.errln("Fail: len %d expected 3\n", length);
    290 	return FALSE;
    291   } else if(u_strncmp(dst,dst_new,LENGTHOF(dst))) {
    292     inteltst.errln("Fail: got U+%04X U+%04X expected U+%04X U+%04X\n",
    293             dst[0],dst[1],dst_new[0],dst_new[1]);
    294 	return FALSE;
    295   }
    296 
    297 
    298   return TRUE;
    299 
    300 }
    301 
    302 
    303 };
    304 
    305 void MultithreadTest::TestThreads()
    306 {
    307     char threadTestChars[THREADTEST_NRTHREADS + 1];
    308     SimpleThread *threads[THREADTEST_NRTHREADS];
    309     int32_t numThreadsStarted = 0;
    310 
    311     int32_t i;
    312     for(i=0;i<THREADTEST_NRTHREADS;i++)
    313     {
    314         threadTestChars[i] = ' ';
    315         threads[i] = new TestThreadsThread(&threadTestChars[i]);
    316     }
    317     threadTestChars[THREADTEST_NRTHREADS] = '\0';
    318 
    319     logln("->" + UnicodeString(threadTestChars) + "<- Firing off threads.. ");
    320     for(i=0;i<THREADTEST_NRTHREADS;i++)
    321     {
    322         if (threads[i]->start() != 0) {
    323             errln("Error starting thread %d", i);
    324         }
    325         else {
    326             numThreadsStarted++;
    327         }
    328         SimpleThread::sleep(100);
    329         logln(" Subthread started.");
    330     }
    331 
    332     logln("Waiting for threads to be set..");
    333     if (numThreadsStarted == 0) {
    334         errln("No threads could be started for testing!");
    335         return;
    336     }
    337 
    338     int32_t patience = 40; // seconds to wait
    339 
    340     while(patience--)
    341     {
    342         int32_t count = 0;
    343         umtx_lock(NULL);
    344         for(i=0;i<THREADTEST_NRTHREADS;i++)
    345         {
    346             if(threadTestChars[i] == '*')
    347             {
    348                 count++;
    349             }
    350         }
    351         umtx_unlock(NULL);
    352 
    353         if(count == THREADTEST_NRTHREADS)
    354         {
    355             logln("->" + UnicodeString(threadTestChars) + "<- Got all threads! cya");
    356             for(i=0;i<THREADTEST_NRTHREADS;i++)
    357             {
    358                 delete threads[i];
    359             }
    360             return;
    361         }
    362 
    363         logln("->" + UnicodeString(threadTestChars) + "<- Waiting..");
    364         SimpleThread::sleep(500);
    365     }
    366 
    367     errln("->" + UnicodeString(threadTestChars) + "<- PATIENCE EXCEEDED!! Still missing some.");
    368     for(i=0;i<THREADTEST_NRTHREADS;i++)
    369     {
    370         delete threads[i];
    371     }
    372 }
    373 
    374 
    375 void MultithreadTest::TestArabicShapingThreads()
    376 {
    377     char threadTestChars[ARABICSHAPE_THREADTEST + 1];
    378     SimpleThread *threads[ARABICSHAPE_THREADTEST];
    379     int32_t numThreadsStarted = 0;
    380 
    381     int32_t i;
    382 
    383     for(i=0;i<ARABICSHAPE_THREADTEST;i++)
    384     {
    385         threadTestChars[i] = ' ';
    386         threads[i] = new TestArabicShapeThreads(&threadTestChars[i]);
    387     }
    388     threadTestChars[ARABICSHAPE_THREADTEST] = '\0';
    389 
    390     logln("-> do TestArabicShapingThreads <- Firing off threads.. ");
    391     for(i=0;i<ARABICSHAPE_THREADTEST;i++)
    392     {
    393         if (threads[i]->start() != 0) {
    394             errln("Error starting thread %d", i);
    395         }
    396         else {
    397             numThreadsStarted++;
    398         }
    399         //SimpleThread::sleep(100);
    400         logln(" Subthread started.");
    401     }
    402 
    403     logln("Waiting for threads to be set..");
    404     if (numThreadsStarted == 0) {
    405         errln("No threads could be started for testing!");
    406         return;
    407     }
    408 
    409     int32_t patience = 100; // seconds to wait
    410 
    411     while(patience--)
    412     {
    413         int32_t count = 0;
    414         umtx_lock(NULL);
    415         for(i=0;i<ARABICSHAPE_THREADTEST;i++)
    416         {
    417             if(threadTestChars[i] == '*')
    418             {
    419                 count++;
    420             }
    421         }
    422         umtx_unlock(NULL);
    423 
    424         if(count == ARABICSHAPE_THREADTEST)
    425         {
    426             logln("->TestArabicShapingThreads <- Got all threads! cya");
    427             for(i=0;i<ARABICSHAPE_THREADTEST;i++)
    428             {
    429                 delete threads[i];
    430             }
    431             return;
    432         }
    433 
    434         logln("-> TestArabicShapingThreads <- Waiting..");
    435         SimpleThread::sleep(500);
    436     }
    437 
    438     errln("-> TestArabicShapingThreads <- PATIENCE EXCEEDED!! Still missing some.");
    439     for(i=0;i<ARABICSHAPE_THREADTEST;i++)
    440     {
    441         delete threads[i];
    442     }
    443 
    444 }
    445 
    446 
    447 //-----------------------------------------------------------------------
    448 //
    449 //  TestMutex  - a simple (non-stress) test to verify that ICU mutexes
    450 //               are actually mutexing.  Does not test the use of
    451 //               mutexes within ICU services, but rather that the
    452 //               platform's mutex support is at least superficially there.
    453 //
    454 //----------------------------------------------------------------------
    455 static UMutex    gTestMutexA = U_MUTEX_INITIALIZER;
    456 static UMutex    gTestMutexB = U_MUTEX_INITIALIZER;
    457 
    458 static int     gThreadsStarted = 0;
    459 static int     gThreadsInMiddle = 0;
    460 static int     gThreadsDone = 0;
    461 
    462 static const int TESTMUTEX_THREAD_COUNT = 4;
    463 
    464 static int safeIncr(int &var, int amt) {
    465     // Thread safe (using global mutex) increment of a variable.
    466     // Return the updated value.
    467     // Can also be used as a safe load of a variable by incrementing it by 0.
    468     Mutex m;
    469     var += amt;
    470     return var;
    471 }
    472 
    473 class TestMutexThread : public SimpleThread
    474 {
    475 public:
    476     virtual void run()
    477     {
    478         // This is the code that each of the spawned threads runs.
    479         // All of the spawned threads bunch up together at each of the two mutexes
    480         // because the main holds the mutexes until they do.
    481         //
    482         safeIncr(gThreadsStarted, 1);
    483         umtx_lock(&gTestMutexA);
    484         umtx_unlock(&gTestMutexA);
    485         safeIncr(gThreadsInMiddle, 1);
    486         umtx_lock(&gTestMutexB);
    487         umtx_unlock(&gTestMutexB);
    488         safeIncr(gThreadsDone, 1);
    489     }
    490 };
    491 
    492 void MultithreadTest::TestMutex()
    493 {
    494     // Start up the test threads.  They should all pile up waiting on
    495     // gTestMutexA, which we (the main thread) hold until the test threads
    496     //   all get there.
    497     gThreadsStarted = 0;
    498     gThreadsInMiddle = 0;
    499     gThreadsDone = 0;
    500     umtx_lock(&gTestMutexA);
    501     TestMutexThread  *threads[TESTMUTEX_THREAD_COUNT];
    502     int i;
    503     int32_t numThreadsStarted = 0;
    504     for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) {
    505         threads[i] = new TestMutexThread;
    506         if (threads[i]->start() != 0) {
    507             errln("Error starting thread %d", i);
    508         }
    509         else {
    510             numThreadsStarted++;
    511         }
    512     }
    513     if (numThreadsStarted == 0) {
    514         errln("No threads could be started for testing!");
    515         return;
    516     }
    517 
    518     int patience = 0;
    519     while (safeIncr(gThreadsStarted, 0) != TESTMUTEX_THREAD_COUNT) {
    520         if (patience++ > 24) {
    521             TSMTHREAD_FAIL("Patience Exceeded");
    522             return;
    523         }
    524         SimpleThread::sleep(500);
    525     }
    526     // None of the test threads should have advanced past the first mutex.
    527     TSMTHREAD_ASSERT(gThreadsInMiddle==0);
    528     TSMTHREAD_ASSERT(gThreadsDone==0);
    529 
    530     //  All of the test threads have made it to the first mutex.
    531     //  We (the main thread) now let them advance to the second mutex,
    532     //   where they should all pile up again.
    533     umtx_lock(&gTestMutexB);
    534     umtx_unlock(&gTestMutexA);
    535 
    536     patience = 0;
    537     while (safeIncr(gThreadsInMiddle, 0) != TESTMUTEX_THREAD_COUNT) {
    538         if (patience++ > 24) {
    539             TSMTHREAD_FAIL("Patience Exceeded");
    540             return;
    541         }
    542         SimpleThread::sleep(500);
    543     }
    544     TSMTHREAD_ASSERT(gThreadsDone==0);
    545 
    546     //  All test threads made it to the second mutex.
    547     //   Now let them proceed from there.  They will all terminate.
    548     umtx_unlock(&gTestMutexB);
    549     patience = 0;
    550     while (safeIncr(gThreadsDone, 0) != TESTMUTEX_THREAD_COUNT) {
    551         if (patience++ > 24) {
    552             TSMTHREAD_FAIL("Patience Exceeded");
    553             return;
    554         }
    555         SimpleThread::sleep(500);
    556     }
    557 
    558     // All threads made it by both mutexes.
    559 
    560     for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) {
    561         delete threads[i];
    562     }
    563 
    564 }
    565 
    566 
    567 //-------------------------------------------------------------------------------------------
    568 //
    569 // class ThreadWithStatus - a thread that we can check the status and error condition of
    570 //
    571 //-------------------------------------------------------------------------------------------
    572 class ThreadWithStatus : public SimpleThread
    573 {
    574 public:
    575     UBool  getError() { return (fErrors > 0); }
    576     UBool  getError(UnicodeString& fillinError) { fillinError = fErrorString; return (fErrors > 0); }
    577     virtual ~ThreadWithStatus(){}
    578 protected:
    579     ThreadWithStatus() :  fErrors(0) {}
    580     void error(const UnicodeString &error) {
    581         fErrors++; fErrorString = error;
    582         SimpleThread::errorFunc();
    583     }
    584     void error() { error("An error occured."); }
    585 private:
    586     int32_t fErrors;
    587     UnicodeString fErrorString;
    588 };
    589 
    590 
    591 
    592 //-------------------------------------------------------------------------------------------
    593 //
    594 //   TestMultithreadedIntl.  Test ICU Formatting n a multi-threaded environment
    595 //
    596 //-------------------------------------------------------------------------------------------
    597 
    598 
    599 // * Show exactly where the string's differences lie.
    600 UnicodeString showDifference(const UnicodeString& expected, const UnicodeString& result)
    601 {
    602     UnicodeString res;
    603     res = expected + "<Expected\n";
    604     if(expected.length() != result.length())
    605         res += " [ Different lengths ] \n";
    606     else
    607     {
    608         for(int32_t i=0;i<expected.length();i++)
    609         {
    610             if(expected[i] == result[i])
    611             {
    612                 res += " ";
    613             }
    614             else
    615             {
    616                 res += "|";
    617             }
    618         }
    619         res += "<Differences";
    620         res += "\n";
    621     }
    622     res += result + "<Result\n";
    623 
    624     return res;
    625 }
    626 
    627 
    628 
    629 
    630 //-------------------------------------------------------------------------------------------
    631 //
    632 //   FormatThreadTest - a thread that tests performing a number of numberformats.
    633 //
    634 //-------------------------------------------------------------------------------------------
    635 
    636 const int kFormatThreadIterations = 100;  // # of iterations per thread
    637 const int kFormatThreadThreads    = 10;  // # of threads to spawn
    638 
    639 #if !UCONFIG_NO_FORMATTING
    640 
    641 
    642 
    643 struct FormatThreadTestData
    644 {
    645     double number;
    646     UnicodeString string;
    647     FormatThreadTestData(double a, const UnicodeString& b) : number(a),string(b) {}
    648 } ;
    649 
    650 
    651 // "Someone from {2} is receiving a #{0} error - {1}. Their telephone call is costing {3 number,currency}."
    652 
    653 static void formatErrorMessage(UErrorCode &realStatus, const UnicodeString& pattern, const Locale& theLocale,
    654                      UErrorCode inStatus0, /* statusString 1 */ const Locale &inCountry2, double currency3, // these numbers are the message arguments.
    655                      UnicodeString &result)
    656 {
    657     if(U_FAILURE(realStatus))
    658         return; // you messed up
    659 
    660     UnicodeString errString1(u_errorName(inStatus0));
    661 
    662     UnicodeString countryName2;
    663     inCountry2.getDisplayCountry(theLocale,countryName2);
    664 
    665     Formattable myArgs[] = {
    666         Formattable((int32_t)inStatus0),   // inStatus0      {0}
    667         Formattable(errString1), // statusString1 {1}
    668         Formattable(countryName2),  // inCountry2 {2}
    669         Formattable(currency3)// currency3  {3,number,currency}
    670     };
    671 
    672     MessageFormat *fmt = new MessageFormat("MessageFormat's API is broken!!!!!!!!!!!",realStatus);
    673     fmt->setLocale(theLocale);
    674     fmt->applyPattern(pattern, realStatus);
    675 
    676     if (U_FAILURE(realStatus)) {
    677         delete fmt;
    678         return;
    679     }
    680 
    681     FieldPosition ignore = 0;
    682     fmt->format(myArgs,4,result,ignore,realStatus);
    683 
    684     delete fmt;
    685 }
    686 
    687 /**
    688  * Class for thread-safe (theoretically) format.
    689  *
    690  *
    691  * Its constructor, destructor, and init/fini are NOT thread safe.
    692  */
    693 class ThreadSafeFormat {
    694 public:
    695   /* give a unique offset to each thread */
    696   ThreadSafeFormat();
    697   UBool doStuff(int32_t offset, UnicodeString &appendErr, UErrorCode &status);
    698 private:
    699   LocalPointer<NumberFormat> fFormat; // formtter - default constructed currency
    700   Formattable  fYDDThing;    // Formattable currency - YDD
    701   Formattable  fBBDThing;   // Formattable currency - BBD
    702 
    703   // statics
    704 private:
    705   static LocalPointer<NumberFormat> gFormat;
    706   static NumberFormat *createFormat(UErrorCode &status);
    707   static Formattable gYDDThing, gBBDThing;
    708 public:
    709   static void init(UErrorCode &status); // avoid static init.
    710   static void fini(UErrorCode &status); // avoid static fini
    711 };
    712 
    713 LocalPointer<NumberFormat> ThreadSafeFormat::gFormat;
    714 Formattable ThreadSafeFormat::gYDDThing;
    715 Formattable ThreadSafeFormat::gBBDThing;
    716 UnicodeString gYDDStr, gBBDStr;
    717 NumberFormat *ThreadSafeFormat::createFormat(UErrorCode &status) {
    718   LocalPointer<NumberFormat> fmt(NumberFormat::createCurrencyInstance(Locale::getUS(), status));
    719   return fmt.orphan();
    720 }
    721 
    722 
    723 static const UChar kYDD[] = { 0x59, 0x44, 0x44, 0x00 };
    724 static const UChar kBBD[] = { 0x42, 0x42, 0x44, 0x00 };
    725 static const UChar kUSD[] = { 0x55, 0x53, 0x44, 0x00 };
    726 
    727 void ThreadSafeFormat::init(UErrorCode &status) {
    728   gFormat.adoptInstead(createFormat(status));
    729   gYDDThing.adoptObject(new CurrencyAmount(123.456, kYDD, status));
    730   gBBDThing.adoptObject(new CurrencyAmount(987.654, kBBD, status));
    731   if (U_FAILURE(status)) {
    732       return;
    733   }
    734   gFormat->format(gYDDThing, gYDDStr, NULL, status);
    735   gFormat->format(gBBDThing, gBBDStr, NULL, status);
    736 }
    737 
    738 void ThreadSafeFormat::fini(UErrorCode &/*status*/) {
    739   gFormat.adoptInstead(NULL);
    740 }
    741 
    742 ThreadSafeFormat::ThreadSafeFormat() {
    743 }
    744 
    745 UBool ThreadSafeFormat::doStuff(int32_t offset, UnicodeString &appendErr, UErrorCode &status) {
    746   UBool okay = TRUE;
    747   if(fFormat.isNull()) {
    748     fFormat.adoptInstead(createFormat(status));
    749   }
    750 
    751   if(u_strcmp(fFormat->getCurrency(), kUSD)) {
    752     appendErr.append("fFormat currency != ")
    753       .append(kUSD)
    754       .append(", =")
    755       .append(fFormat->getCurrency())
    756       .append("! ");
    757     okay = FALSE;
    758   }
    759 
    760   if(u_strcmp(gFormat->getCurrency(), kUSD)) {
    761     appendErr.append("gFormat currency != ")
    762       .append(kUSD)
    763       .append(", =")
    764       .append(gFormat->getCurrency())
    765       .append("! ");
    766     okay = FALSE;
    767   }
    768   UnicodeString str;
    769   const UnicodeString *o=NULL;
    770   Formattable f;
    771   const NumberFormat *nf = NULL; // only operate on it as const.
    772   switch(offset%4) {
    773   case 0:  f = gYDDThing;  o = &gYDDStr;  nf = gFormat.getAlias();  break;
    774   case 1:  f = gBBDThing;  o = &gBBDStr;  nf = gFormat.getAlias();  break;
    775   case 2:  f = gYDDThing;  o = &gYDDStr;  nf = fFormat.getAlias();  break;
    776   case 3:  f = gBBDThing;  o = &gBBDStr;  nf = fFormat.getAlias();  break;
    777   }
    778   nf->format(f, str, NULL, status);
    779 
    780   if(*o != str) {
    781     appendErr.append(showDifference(*o, str));
    782     okay = FALSE;
    783   }
    784   return okay;
    785 }
    786 
    787 UBool U_CALLCONV isAcceptable(void *, const char *, const char *, const UDataInfo *) {
    788     return TRUE;
    789 }
    790 
    791 //static UMTX debugMutex = NULL;
    792 //static UMTX gDebugMutex;
    793 
    794 
    795 class FormatThreadTest : public ThreadWithStatus
    796 {
    797 public:
    798     int     fNum;
    799     int     fTraceInfo;
    800 
    801     ThreadSafeFormat fTSF;
    802 
    803     FormatThreadTest() // constructor is NOT multithread safe.
    804         : ThreadWithStatus(),
    805         fNum(0),
    806         fTraceInfo(0),
    807         fOffset(0)
    808         // the locale to use
    809     {
    810         static int32_t fgOffset = 0;
    811         fgOffset += 3;
    812         fOffset = fgOffset;
    813     }
    814 
    815 
    816     virtual void run()
    817     {
    818         fTraceInfo                     = 1;
    819         LocalPointer<NumberFormat> percentFormatter;
    820         UErrorCode status = U_ZERO_ERROR;
    821 
    822 #if 0
    823         // debugging code,
    824         for (int i=0; i<4000; i++) {
    825             status = U_ZERO_ERROR;
    826             UDataMemory *data1 = udata_openChoice(0, "res", "en_US", isAcceptable, 0, &status);
    827             UDataMemory *data2 = udata_openChoice(0, "res", "fr", isAcceptable, 0, &status);
    828             udata_close(data1);
    829             udata_close(data2);
    830             if (U_FAILURE(status)) {
    831                 error("udata_openChoice failed.\n");
    832                 break;
    833             }
    834         }
    835         return;
    836 #endif
    837 
    838 #if 0
    839         // debugging code,
    840         int m;
    841         for (m=0; m<4000; m++) {
    842             status         = U_ZERO_ERROR;
    843             UResourceBundle *res   = NULL;
    844             const char *localeName = NULL;
    845 
    846             Locale  loc = Locale::getEnglish();
    847 
    848             localeName = loc.getName();
    849             // localeName = "en";
    850 
    851             // ResourceBundle bund = ResourceBundle(0, loc, status);
    852             //umtx_lock(&gDebugMutex);
    853             res = ures_open(NULL, localeName, &status);
    854             //umtx_unlock(&gDebugMutex);
    855 
    856             //umtx_lock(&gDebugMutex);
    857             ures_close(res);
    858             //umtx_unlock(&gDebugMutex);
    859 
    860             if (U_FAILURE(status)) {
    861                 error("Resource bundle construction failed.\n");
    862                 break;
    863             }
    864         }
    865         return;
    866 #endif
    867 
    868         // Keep this data here to avoid static initialization.
    869         FormatThreadTestData kNumberFormatTestData[] =
    870         {
    871             FormatThreadTestData((double)5.0, UnicodeString("5", "")),
    872                 FormatThreadTestData( 6.0, UnicodeString("6", "")),
    873                 FormatThreadTestData( 20.0, UnicodeString("20", "")),
    874                 FormatThreadTestData( 8.0, UnicodeString("8", "")),
    875                 FormatThreadTestData( 8.3, UnicodeString("8.3", "")),
    876                 FormatThreadTestData( 12345, UnicodeString("12,345", "")),
    877                 FormatThreadTestData( 81890.23, UnicodeString("81,890.23", "")),
    878         };
    879         int32_t kNumberFormatTestDataLength = (int32_t)(sizeof(kNumberFormatTestData) /
    880                                                         sizeof(kNumberFormatTestData[0]));
    881 
    882         // Keep this data here to avoid static initialization.
    883         FormatThreadTestData kPercentFormatTestData[] =
    884         {
    885             FormatThreadTestData((double)5.0, CharsToUnicodeString("500\\u00a0%")),
    886                 FormatThreadTestData( 1.0, CharsToUnicodeString("100\\u00a0%")),
    887                 FormatThreadTestData( 0.26, CharsToUnicodeString("26\\u00a0%")),
    888                 FormatThreadTestData(
    889                    16384.99, CharsToUnicodeString("1\\u00a0638\\u00a0499\\u00a0%")), // U+00a0 = NBSP
    890                 FormatThreadTestData(
    891                     81890.23, CharsToUnicodeString("8\\u00a0189\\u00a0023\\u00a0%")),
    892         };
    893         int32_t kPercentFormatTestDataLength =
    894                 (int32_t)(sizeof(kPercentFormatTestData) / sizeof(kPercentFormatTestData[0]));
    895         int32_t iteration;
    896 
    897         status = U_ZERO_ERROR;
    898         LocalPointer<NumberFormat> formatter(NumberFormat::createInstance(Locale::getEnglish(),status));
    899         if(U_FAILURE(status)) {
    900             error("Error on NumberFormat::createInstance().");
    901             goto cleanupAndReturn;
    902         }
    903 
    904         percentFormatter.adoptInstead(NumberFormat::createPercentInstance(Locale::getFrench(),status));
    905         if(U_FAILURE(status))             {
    906             error("Error on NumberFormat::createPercentInstance().");
    907             goto cleanupAndReturn;
    908         }
    909 
    910         for(iteration = 0;!getError() && iteration<kFormatThreadIterations;iteration++)
    911         {
    912 
    913             int32_t whichLine = (iteration + fOffset)%kNumberFormatTestDataLength;
    914 
    915             UnicodeString  output;
    916 
    917             formatter->format(kNumberFormatTestData[whichLine].number, output);
    918 
    919             if(0 != output.compare(kNumberFormatTestData[whichLine].string)) {
    920                 error("format().. expected " + kNumberFormatTestData[whichLine].string
    921                         + " got " + output);
    922                 goto cleanupAndReturn;
    923             }
    924 
    925             // Now check percent.
    926             output.remove();
    927             whichLine = (iteration + fOffset)%kPercentFormatTestDataLength;
    928 
    929             percentFormatter->format(kPercentFormatTestData[whichLine].number, output);
    930             if(0 != output.compare(kPercentFormatTestData[whichLine].string))
    931             {
    932                 error("percent format().. \n" +
    933                         showDifference(kPercentFormatTestData[whichLine].string,output));
    934                 goto cleanupAndReturn;
    935             }
    936 
    937             // Test message error
    938             const int       kNumberOfMessageTests = 3;
    939             UErrorCode      statusToCheck;
    940             UnicodeString   patternToCheck;
    941             Locale          messageLocale;
    942             Locale          countryToCheck;
    943             double          currencyToCheck;
    944 
    945             UnicodeString   expected;
    946 
    947             // load the cases.
    948             switch((iteration+fOffset) % kNumberOfMessageTests)
    949             {
    950             default:
    951             case 0:
    952                 statusToCheck=                      U_FILE_ACCESS_ERROR;
    953                 patternToCheck=        "0:Someone from {2} is receiving a #{0}"
    954                                        " error - {1}. Their telephone call is costing "
    955                                        "{3,number,currency}."; // number,currency
    956                 messageLocale=                      Locale("en","US");
    957                 countryToCheck=                     Locale("","HR");
    958                 currencyToCheck=                    8192.77;
    959                 expected=  "0:Someone from Croatia is receiving a #4 error - "
    960                             "U_FILE_ACCESS_ERROR. Their telephone call is costing $8,192.77.";
    961                 break;
    962             case 1:
    963                 statusToCheck=                      U_INDEX_OUTOFBOUNDS_ERROR;
    964                 patternToCheck=                     "1:A customer in {2} is receiving a #{0} error - {1}. Their telephone call is costing {3,number,currency}."; // number,currency
    965                 messageLocale=                      Locale("de","DE@currency=DEM");
    966                 countryToCheck=                     Locale("","BF");
    967                 currencyToCheck=                    2.32;
    968                 expected=                           CharsToUnicodeString(
    969                                                     "1:A customer in Burkina Faso is receiving a #8 error - U_INDEX_OUTOFBOUNDS_ERROR. Their telephone call is costing 2,32\\u00A0DEM.");
    970                 break;
    971             case 2:
    972                 statusToCheck=                      U_MEMORY_ALLOCATION_ERROR;
    973                 patternToCheck=   "2:user in {2} is receiving a #{0} error - {1}. "
    974                                   "They insist they just spent {3,number,currency} "
    975                                   "on memory."; // number,currency
    976                 messageLocale=                      Locale("de","AT@currency=ATS"); // Austrian German
    977                 countryToCheck=                     Locale("","US"); // hmm
    978                 currencyToCheck=                    40193.12;
    979                 expected=       CharsToUnicodeString(
    980                             "2:user in Vereinigte Staaten is receiving a #7 error"
    981                             " - U_MEMORY_ALLOCATION_ERROR. They insist they just spent"
    982                             " \\u00f6S\\u00A040.193,12 on memory.");
    983                 break;
    984             }
    985 
    986             UnicodeString result;
    987             UErrorCode status = U_ZERO_ERROR;
    988             formatErrorMessage(status,patternToCheck,messageLocale,statusToCheck,
    989                                 countryToCheck,currencyToCheck,result);
    990             if(U_FAILURE(status))
    991             {
    992                 UnicodeString tmp(u_errorName(status));
    993                 error("Failure on message format, pattern=" + patternToCheck +
    994                         ", error = " + tmp);
    995                 goto cleanupAndReturn;
    996             }
    997 
    998             if(result != expected)
    999             {
   1000                 error("PatternFormat: \n" + showDifference(expected,result));
   1001                 goto cleanupAndReturn;
   1002             }
   1003             // test the Thread Safe Format
   1004             UnicodeString appendErr;
   1005             if(!fTSF.doStuff(fNum, appendErr, status)) {
   1006               error(appendErr);
   1007               goto cleanupAndReturn;
   1008             }
   1009         }   /*  end of for loop */
   1010 
   1011 
   1012 
   1013 cleanupAndReturn:
   1014         //  while (fNum == 4) {SimpleThread::sleep(10000);}   // Force a failure by preventing thread from finishing
   1015         fTraceInfo = 2;
   1016     }
   1017 
   1018 private:
   1019     int32_t fOffset; // where we are testing from.
   1020 };
   1021 
   1022 // ** The actual test function.
   1023 
   1024 void MultithreadTest::TestThreadedIntl()
   1025 {
   1026     int i;
   1027     UnicodeString theErr;
   1028     UBool   haveDisplayedInfo[kFormatThreadThreads];
   1029     static const int32_t PATIENCE_SECONDS = 45;
   1030 
   1031     UErrorCode threadSafeErr = U_ZERO_ERROR;
   1032 
   1033     ThreadSafeFormat::init(threadSafeErr);
   1034     assertSuccess("initializing ThreadSafeFormat", threadSafeErr, TRUE);
   1035 
   1036     //
   1037     //  Create and start the test threads
   1038     //
   1039     logln("Spawning: %d threads * %d iterations each.",
   1040                 kFormatThreadThreads, kFormatThreadIterations);
   1041     LocalArray<FormatThreadTest> tests(new FormatThreadTest[kFormatThreadThreads]);
   1042     for(int32_t j = 0; j < kFormatThreadThreads; j++) {
   1043         tests[j].fNum = j;
   1044         int32_t threadStatus = tests[j].start();
   1045         if (threadStatus != 0) {
   1046             errln("System Error %d starting thread number %d.", threadStatus, j);
   1047             SimpleThread::errorFunc();
   1048             return;
   1049         }
   1050         haveDisplayedInfo[j] = FALSE;
   1051     }
   1052 
   1053 
   1054     // Spin, waiting for the test threads to finish.
   1055     UBool   stillRunning;
   1056     UDate startTime, endTime;
   1057     startTime = Calendar::getNow();
   1058     double lastComplaint = 0;
   1059     do {
   1060         /*  Spin until the test threads  complete. */
   1061         stillRunning = FALSE;
   1062         endTime = Calendar::getNow();
   1063         double elapsedSeconds =  ((int32_t)(endTime - startTime)/U_MILLIS_PER_SECOND);
   1064         if (elapsedSeconds > PATIENCE_SECONDS) {
   1065             errln("Patience exceeded. Test is taking too long.");
   1066             return;
   1067         } else if((elapsedSeconds-lastComplaint) > 2.0) {
   1068             infoln("%.1f seconds elapsed (still waiting..)", elapsedSeconds);
   1069             lastComplaint = elapsedSeconds;
   1070         }
   1071         /*
   1072          The following sleep must be here because the *BSD operating systems
   1073          have a brain dead thread scheduler. They starve the child threads from
   1074          CPU time.
   1075         */
   1076         SimpleThread::sleep(1); // yield
   1077         for(i=0;i<kFormatThreadThreads;i++) {
   1078             if (tests[i].isRunning()) {
   1079                 stillRunning = TRUE;
   1080             } else if (haveDisplayedInfo[i] == FALSE) {
   1081                 logln("Thread # %d is complete..", i);
   1082                 if(tests[i].getError(theErr)) {
   1083                     dataerrln(UnicodeString("#") + i + ": " + theErr);
   1084                     SimpleThread::errorFunc();
   1085                 }
   1086                 haveDisplayedInfo[i] = TRUE;
   1087             }
   1088         }
   1089     } while (stillRunning);
   1090 
   1091     //
   1092     //  All threads have finished.
   1093     //
   1094     ThreadSafeFormat::fini(threadSafeErr);
   1095     assertSuccess("finalizing ThreadSafeFormat", threadSafeErr, TRUE);
   1096 }
   1097 #endif /* #if !UCONFIG_NO_FORMATTING */
   1098 
   1099 
   1100 
   1101 
   1102 
   1103 //-------------------------------------------------------------------------------------------
   1104 //
   1105 // Collation threading test
   1106 //
   1107 //-------------------------------------------------------------------------------------------
   1108 #if !UCONFIG_NO_COLLATION
   1109 
   1110 #define kCollatorThreadThreads   10  // # of threads to spawn
   1111 #define kCollatorThreadPatience kCollatorThreadThreads*30
   1112 
   1113 struct Line {
   1114     UChar buff[25];
   1115     int32_t buflen;
   1116 } ;
   1117 
   1118 static UBool
   1119 skipLineBecauseOfBug(const UChar *s, int32_t length) {
   1120     // TODO: Fix ICU ticket #8052
   1121     if(length >= 3 &&
   1122             (s[0] == 0xfb2 || s[0] == 0xfb3) &&
   1123             s[1] == 0x334 &&
   1124             (s[2] == 0xf73 || s[2] == 0xf75 || s[2] == 0xf81)) {
   1125         return TRUE;
   1126     }
   1127     return FALSE;
   1128 }
   1129 
   1130 static UCollationResult
   1131 normalizeResult(int32_t result) {
   1132     return result<0 ? UCOL_LESS : result==0 ? UCOL_EQUAL : UCOL_GREATER;
   1133 }
   1134 
   1135 class CollatorThreadTest : public ThreadWithStatus
   1136 {
   1137 private:
   1138     const Collator *coll;
   1139     const Line *lines;
   1140     int32_t noLines;
   1141     UBool isAtLeastUCA62;
   1142 public:
   1143     CollatorThreadTest()  : ThreadWithStatus(),
   1144         coll(NULL),
   1145         lines(NULL),
   1146         noLines(0),
   1147         isAtLeastUCA62(TRUE)
   1148     {
   1149     };
   1150     void setCollator(Collator *c, Line *l, int32_t nl, UBool atLeastUCA62)
   1151     {
   1152         coll = c;
   1153         lines = l;
   1154         noLines = nl;
   1155         isAtLeastUCA62 = atLeastUCA62;
   1156     }
   1157     virtual void run() {
   1158         uint8_t sk1[1024], sk2[1024];
   1159         uint8_t *oldSk = NULL, *newSk = sk1;
   1160         int32_t oldLen = 0;
   1161         int32_t prev = 0;
   1162         int32_t i = 0;
   1163 
   1164         for(i = 0; i < noLines; i++) {
   1165             if(lines[i].buflen == 0) { continue; }
   1166 
   1167             if(skipLineBecauseOfBug(lines[i].buff, lines[i].buflen)) { continue; }
   1168 
   1169             int32_t resLen = coll->getSortKey(lines[i].buff, lines[i].buflen, newSk, 1024);
   1170 
   1171             if(oldSk != NULL) {
   1172                 int32_t skres = strcmp((char *)oldSk, (char *)newSk);
   1173                 int32_t cmpres = coll->compare(lines[prev].buff, lines[prev].buflen, lines[i].buff, lines[i].buflen);
   1174                 int32_t cmpres2 = coll->compare(lines[i].buff, lines[i].buflen, lines[prev].buff, lines[prev].buflen);
   1175 
   1176                 if(cmpres != -cmpres2) {
   1177                     error(UnicodeString("Compare result not symmetrical on line ") + (i + 1));
   1178                     break;
   1179                 }
   1180 
   1181                 if(cmpres != normalizeResult(skres)) {
   1182                     error(UnicodeString("Difference between coll->compare and sortkey compare on line ") + (i + 1));
   1183                     break;
   1184                 }
   1185 
   1186                 int32_t res = cmpres;
   1187                 if(res == 0 && !isAtLeastUCA62) {
   1188                     // Up to UCA 6.1, the collation test files use a custom tie-breaker,
   1189                     // comparing the raw input strings.
   1190                     res = u_strcmpCodePointOrder(lines[prev].buff, lines[i].buff);
   1191                     // Starting with UCA 6.2, the collation test files use the standard UCA tie-breaker,
   1192                     // comparing the NFD versions of the input strings,
   1193                     // which we do via setting strength=identical.
   1194                 }
   1195                 if(res > 0) {
   1196                     error(UnicodeString("Line is not greater or equal than previous line, for line ") + (i + 1));
   1197                     break;
   1198                 }
   1199             }
   1200 
   1201             oldSk = newSk;
   1202             oldLen = resLen;
   1203             (void)oldLen;   // Suppress set but not used warning.
   1204             prev = i;
   1205 
   1206             newSk = (newSk == sk1)?sk2:sk1;
   1207         }
   1208     }
   1209 };
   1210 
   1211 void MultithreadTest::TestCollators()
   1212 {
   1213 
   1214     UErrorCode status = U_ZERO_ERROR;
   1215     FILE *testFile = NULL;
   1216     char testDataPath[1024];
   1217     strcpy(testDataPath, IntlTest::getSourceTestData(status));
   1218     if (U_FAILURE(status)) {
   1219         errln("ERROR: could not open test data %s", u_errorName(status));
   1220         return;
   1221     }
   1222     strcat(testDataPath, "CollationTest_");
   1223 
   1224     const char* type = "NON_IGNORABLE";
   1225 
   1226     const char *ext = ".txt";
   1227     if(testFile) {
   1228         fclose(testFile);
   1229     }
   1230     char buffer[1024];
   1231     strcpy(buffer, testDataPath);
   1232     strcat(buffer, type);
   1233     size_t bufLen = strlen(buffer);
   1234 
   1235     // we try to open 3 files:
   1236     // path/CollationTest_type.txt
   1237     // path/CollationTest_type_SHORT.txt
   1238     // path/CollationTest_type_STUB.txt
   1239     // we are going to test with the first one that we manage to open.
   1240 
   1241     strcpy(buffer+bufLen, ext);
   1242 
   1243     testFile = fopen(buffer, "rb");
   1244 
   1245     if(testFile == 0) {
   1246         strcpy(buffer+bufLen, "_SHORT");
   1247         strcat(buffer, ext);
   1248         testFile = fopen(buffer, "rb");
   1249 
   1250         if(testFile == 0) {
   1251             strcpy(buffer+bufLen, "_STUB");
   1252             strcat(buffer, ext);
   1253             testFile = fopen(buffer, "rb");
   1254 
   1255             if (testFile == 0) {
   1256                 *(buffer+bufLen) = 0;
   1257                 dataerrln("could not open any of the conformance test files, tried opening base %s", buffer);
   1258                 return;
   1259             } else {
   1260                 infoln(
   1261                     "INFO: Working with the stub file.\n"
   1262                     "If you need the full conformance test, please\n"
   1263                     "download the appropriate data files from:\n"
   1264                     "http://source.icu-project.org/repos/icu/tools/trunk/unicodetools/com/ibm/text/data/");
   1265             }
   1266         }
   1267     }
   1268 
   1269     LocalArray<Line> lines(new Line[200000]);
   1270     memset(lines.getAlias(), 0, sizeof(Line)*200000);
   1271     int32_t lineNum = 0;
   1272 
   1273     UChar bufferU[1024];
   1274     uint32_t first = 0;
   1275 
   1276     while (fgets(buffer, 1024, testFile) != NULL) {
   1277         if(*buffer == 0 || buffer[0] == '#') {
   1278             // Store empty and comment lines so that errors are reported
   1279             // for the real test file lines.
   1280             lines[lineNum].buflen = 0;
   1281             lines[lineNum].buff[0] = 0;
   1282         } else {
   1283             int32_t buflen = u_parseString(buffer, bufferU, 1024, &first, &status);
   1284             lines[lineNum].buflen = buflen;
   1285             u_memcpy(lines[lineNum].buff, bufferU, buflen);
   1286             lines[lineNum].buff[buflen] = 0;
   1287         }
   1288         lineNum++;
   1289     }
   1290     fclose(testFile);
   1291     if(U_FAILURE(status)) {
   1292       dataerrln("Couldn't read the test file!");
   1293       return;
   1294     }
   1295 
   1296     UVersionInfo uniVersion;
   1297     static const UVersionInfo v62 = { 6, 2, 0, 0 };
   1298     u_getUnicodeVersion(uniVersion);
   1299     UBool isAtLeastUCA62 = uprv_memcmp(uniVersion, v62, 4) >= 0;
   1300 
   1301     LocalPointer<Collator> coll(Collator::createInstance(Locale::getRoot(), status));
   1302     if(U_FAILURE(status)) {
   1303         errcheckln(status, "Couldn't open UCA collator");
   1304         return;
   1305     }
   1306     coll->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status);
   1307     coll->setAttribute(UCOL_CASE_FIRST, UCOL_OFF, status);
   1308     coll->setAttribute(UCOL_CASE_LEVEL, UCOL_OFF, status);
   1309     coll->setAttribute(UCOL_STRENGTH, isAtLeastUCA62 ? UCOL_IDENTICAL : UCOL_TERTIARY, status);
   1310     coll->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_NON_IGNORABLE, status);
   1311 
   1312     int32_t noSpawned = 0;
   1313     int32_t spawnResult = 0;
   1314     LocalArray<CollatorThreadTest> tests(new CollatorThreadTest[kCollatorThreadThreads]);
   1315 
   1316     logln(UnicodeString("Spawning: ") + kCollatorThreadThreads + " threads * " + kFormatThreadIterations + " iterations each.");
   1317     int32_t j = 0;
   1318     for(j = 0; j < kCollatorThreadThreads; j++) {
   1319         //logln("Setting collator %i", j);
   1320         tests[j].setCollator(coll.getAlias(), lines.getAlias(), lineNum, isAtLeastUCA62);
   1321     }
   1322     for(j = 0; j < kCollatorThreadThreads; j++) {
   1323         log("%i ", j);
   1324         spawnResult = tests[j].start();
   1325         if(spawnResult != 0) {
   1326             infoln("THREAD INFO: Couldn't spawn more than %i threads", noSpawned);
   1327             break;
   1328         }
   1329         noSpawned++;
   1330     }
   1331     logln("Spawned all");
   1332     if (noSpawned == 0) {
   1333         errln("No threads could be spawned.");
   1334         return;
   1335     }
   1336 
   1337     for(int32_t patience = kCollatorThreadPatience;patience > 0; patience --)
   1338     {
   1339         logln("Waiting...");
   1340 
   1341         int32_t i;
   1342         int32_t terrs = 0;
   1343         int32_t completed =0;
   1344 
   1345         for(i=0;i<kCollatorThreadThreads;i++)
   1346         {
   1347             if (tests[i].isRunning() == FALSE)
   1348             {
   1349                 completed++;
   1350 
   1351                 //logln(UnicodeString("Test #") + i + " is complete.. ");
   1352 
   1353                 UnicodeString theErr;
   1354                 if(tests[i].getError(theErr))
   1355                 {
   1356                     terrs++;
   1357                     errln(UnicodeString("#") + i + ": " + theErr);
   1358                 }
   1359                 // print out the error, too, if any.
   1360             }
   1361         }
   1362         logln("Completed %i tests", completed);
   1363 
   1364         if(completed == noSpawned)
   1365         {
   1366             logln("Done! All %i tests are finished", noSpawned);
   1367 
   1368             if(terrs)
   1369             {
   1370                 errln("There were errors.");
   1371                 SimpleThread::errorFunc();
   1372             }
   1373             return;
   1374         }
   1375 
   1376         SimpleThread::sleep(900);
   1377     }
   1378     errln("patience exceeded. ");
   1379     SimpleThread::errorFunc();
   1380 }
   1381 
   1382 #endif /* #if !UCONFIG_NO_COLLATION */
   1383 
   1384 
   1385 
   1386 
   1387 //-------------------------------------------------------------------------------------------
   1388 //
   1389 //   StringThreadTest2
   1390 //
   1391 //-------------------------------------------------------------------------------------------
   1392 
   1393 const int kStringThreadIterations = 2500;// # of iterations per thread
   1394 const int kStringThreadThreads    = 10;  // # of threads to spawn
   1395 const int kStringThreadPatience   = 120; // time in seconds to wait for all threads
   1396 
   1397 
   1398 class StringThreadTest2 : public ThreadWithStatus
   1399 {
   1400 public:
   1401     int                 fNum;
   1402     int                 fTraceInfo;
   1403     const UnicodeString *fSharedString;
   1404 
   1405     StringThreadTest2(const UnicodeString *sharedString, int num) // constructor is NOT multithread safe.
   1406         : ThreadWithStatus(),
   1407         fNum(num),
   1408         fTraceInfo(0),
   1409         fSharedString(sharedString)
   1410     {
   1411     };
   1412 
   1413 
   1414     virtual void run()
   1415     {
   1416         fTraceInfo    = 1;
   1417         int loopCount = 0;
   1418 
   1419         for (loopCount = 0; loopCount < kStringThreadIterations; loopCount++) {
   1420             if (*fSharedString != "This is the original test string.") {
   1421                 error("Original string is corrupt.");
   1422                 break;
   1423             }
   1424             UnicodeString s1 = *fSharedString;
   1425             s1 += "cat this";
   1426             UnicodeString s2(s1);
   1427             UnicodeString s3 = *fSharedString;
   1428             s2 = s3;
   1429             s3.truncate(12);
   1430             s2.truncate(0);
   1431         }
   1432 
   1433         //  while (fNum == 4) {SimpleThread::sleep(10000);}   // Force a failure by preventing thread from finishing
   1434         fTraceInfo = 2;
   1435     }
   1436 
   1437 };
   1438 
   1439 // ** The actual test function.
   1440 
   1441 void MultithreadTest::TestString()
   1442 {
   1443     int     patience;
   1444     int     terrs = 0;
   1445     int     j;
   1446 
   1447     UnicodeString *testString = new UnicodeString("This is the original test string.");
   1448 
   1449     // Not using LocalArray<StringThreadTest2> tests[kStringThreadThreads];
   1450     // because we don't always want to delete them.
   1451     // See the comments below the cleanupAndReturn label.
   1452     StringThreadTest2  *tests[kStringThreadThreads];
   1453     for(j = 0; j < kStringThreadThreads; j++) {
   1454         tests[j] = new StringThreadTest2(testString, j);
   1455     }
   1456 
   1457     logln(UnicodeString("Spawning: ") + kStringThreadThreads + " threads * " + kStringThreadIterations + " iterations each.");
   1458     for(j = 0; j < kStringThreadThreads; j++) {
   1459         int32_t threadStatus = tests[j]->start();
   1460         if (threadStatus != 0) {
   1461             errln("System Error %d starting thread number %d.", threadStatus, j);
   1462             SimpleThread::errorFunc();
   1463             goto cleanupAndReturn;
   1464         }
   1465     }
   1466 
   1467     for(patience = kStringThreadPatience;patience > 0; patience --)
   1468     {
   1469         logln("Waiting...");
   1470 
   1471         int32_t i;
   1472         terrs = 0;
   1473         int32_t completed =0;
   1474 
   1475         for(i=0;i<kStringThreadThreads;i++) {
   1476             if (tests[i]->isRunning() == FALSE)
   1477             {
   1478                 completed++;
   1479 
   1480                 logln(UnicodeString("Test #") + i + " is complete.. ");
   1481 
   1482                 UnicodeString theErr;
   1483                 if(tests[i]->getError(theErr))
   1484                 {
   1485                     terrs++;
   1486                     errln(UnicodeString("#") + i + ": " + theErr);
   1487                 }
   1488                 // print out the error, too, if any.
   1489             }
   1490         }
   1491 
   1492         if(completed == kStringThreadThreads)
   1493         {
   1494             logln("Done!");
   1495             if(terrs) {
   1496                 errln("There were errors.");
   1497             }
   1498             break;
   1499         }
   1500 
   1501         SimpleThread::sleep(900);
   1502     }
   1503 
   1504     if (patience <= 0) {
   1505         errln("patience exceeded. ");
   1506         // while (TRUE) {SimpleThread::sleep(10000);}   // TODO:   for debugging.  Sleep forever on failure.
   1507         terrs++;
   1508     }
   1509 
   1510     if (terrs > 0) {
   1511         SimpleThread::errorFunc();
   1512     }
   1513 
   1514 cleanupAndReturn:
   1515     if (terrs == 0) {
   1516         /*
   1517         Don't clean up if there are errors. This prevents crashes if the
   1518         threads are still running and using this data. This will only happen
   1519         if there is an error with the test, ICU, or the machine is too slow.
   1520         It's better to leak than crash.
   1521         */
   1522         for(j = 0; j < kStringThreadThreads; j++) {
   1523             delete tests[j];
   1524         }
   1525         delete testString;
   1526     }
   1527 }
   1528 
   1529 
   1530 // Test for ticket #10673, race in cache code in AnyTransliterator.
   1531 // It's difficult to make the original unsafe code actually fail, but
   1532 // this test will fairly reliably take the code path for races in
   1533 // populating the cache.
   1534 
   1535 #if !UCONFIG_NO_TRANSLITERATION
   1536 class TxThread: public SimpleThread {
   1537   private:
   1538     Transliterator *fSharedTranslit;
   1539   public:
   1540     UBool fSuccess;
   1541     TxThread(Transliterator *tx) : fSharedTranslit(tx), fSuccess(FALSE) {};
   1542     ~TxThread();
   1543     void run();
   1544 };
   1545 
   1546 TxThread::~TxThread() {}
   1547 void TxThread::run() {
   1548     UnicodeString greekString("\\u03B4\\u03B9\\u03B1\\u03C6\\u03BF\\u03C1\\u03B5\\u03C4\\u03B9\\u03BA\\u03BF\\u03CD\\u03C2");
   1549     greekString = greekString.unescape();
   1550     fSharedTranslit->transliterate(greekString);
   1551     fSuccess = greekString[0] == 0x64; // 'd'. The whole transliterated string is "diaphoretikous" (accented u).
   1552 }
   1553 #endif
   1554 
   1555 
   1556 void MultithreadTest::TestAnyTranslit() {
   1557 #if !UCONFIG_NO_TRANSLITERATION
   1558     UErrorCode status = U_ZERO_ERROR;
   1559     LocalPointer<Transliterator> tx(Transliterator::createInstance("Any-Latin", UTRANS_FORWARD, status));
   1560     if (U_FAILURE(status)) {
   1561         dataerrln("File %s, Line %d: Error, status = %s", __FILE__, __LINE__, u_errorName(status));
   1562         return;
   1563     }
   1564     TxThread * threads[4];
   1565     int32_t i;
   1566     for (i=0; i<4; i++) {
   1567         threads[i] = new TxThread(tx.getAlias());
   1568     }
   1569     for (i=0; i<4; i++) {
   1570         threads[i]->start();
   1571     }
   1572     int32_t patience = 100;
   1573     UBool success;
   1574     UBool someThreadRunning;
   1575     do {
   1576         someThreadRunning = FALSE;
   1577         success = TRUE;
   1578         for (i=0; i<4; i++) {
   1579             if (threads[i]->isRunning()) {
   1580                 someThreadRunning = TRUE;
   1581                 SimpleThread::sleep(10);
   1582                 break;
   1583             } else {
   1584                 if (threads[i]->fSuccess == FALSE) {
   1585                     success = FALSE;
   1586                 }
   1587             }
   1588         }
   1589     } while (someThreadRunning && --patience > 0);
   1590 
   1591     if (patience <= 0) {
   1592         errln("File %s, Line %d: Error, one or more threads did not complete.", __FILE__, __LINE__);
   1593     }
   1594     if (success == FALSE) {
   1595         errln("File %s, Line %d: Error, transliteration result incorrect.", __FILE__, __LINE__);
   1596     }
   1597 
   1598     for (i=0; i<4; i++) {
   1599         delete threads[i];
   1600     }
   1601 #endif  // !UCONFIG_NO_TRANSLITERATION
   1602 }
   1603 
   1604 #endif // ICU_USE_THREADS
   1605