Home | History | Annotate | Download | only in intltest
      1 /********************************************************************
      2  * COPYRIGHT:
      3  * Copyright (c) 1999-2015, International Business Machines Corporation and
      4  * others. All Rights Reserved.
      5  ********************************************************************/
      6 
      7 #include "simplethread.h"
      8 
      9 #include "unicode/utypes.h"
     10 #include "unicode/ustring.h"
     11 #include "umutex.h"
     12 #include "cmemory.h"
     13 #include "cstring.h"
     14 #include "uparse.h"
     15 #include "unicode/localpointer.h"
     16 #include "unicode/resbund.h"
     17 #include "unicode/udata.h"
     18 #include "unicode/uloc.h"
     19 #include "unicode/locid.h"
     20 #include "putilimp.h"
     21 #include "intltest.h"
     22 #include "tsmthred.h"
     23 #include "unicode/ushape.h"
     24 #include "unicode/translit.h"
     25 #include "sharedobject.h"
     26 #include "unifiedcache.h"
     27 #include "uassert.h"
     28 
     29 
     30 #define TSMTHREAD_FAIL(msg) errln("%s at file %s, line %d", msg, __FILE__, __LINE__)
     31 #define TSMTHREAD_ASSERT(expr) {if (!(expr)) {TSMTHREAD_FAIL("Fail");}}
     32 #define TSMTHREAD_ASSERT_SUCCESS(status) {if (U_FAILURE(status)) { \
     33                   errln("file: %s:%d status = %s\n", __FILE__, __LINE__, u_errorName(status));}}
     34 
     35 MultithreadTest::MultithreadTest()
     36 {
     37 }
     38 
     39 MultithreadTest::~MultithreadTest()
     40 {
     41 }
     42 
     43 #include <stdio.h>
     44 #include <string.h>
     45 #include <ctype.h>    // tolower, toupper
     46 
     47 #include "unicode/putil.h"
     48 
     49 // for mthreadtest
     50 #include "unicode/numfmt.h"
     51 #include "unicode/choicfmt.h"
     52 #include "unicode/msgfmt.h"
     53 #include "unicode/locid.h"
     54 #include "unicode/coll.h"
     55 #include "unicode/calendar.h"
     56 #include "ucaconf.h"
     57 
     58 
     59 void MultithreadTest::runIndexedTest( int32_t index, UBool exec,
     60                 const char* &name, char* /*par*/ ) {
     61     if (exec)
     62         logln("TestSuite MultithreadTest: ");
     63     switch (index) {
     64     case 0:
     65         name = "TestThreads";
     66         if (exec)
     67             TestThreads();
     68         break;
     69 
     70     case 1:
     71         name = "TestMutex";
     72         if (exec)
     73             TestMutex();
     74         break;
     75 
     76     case 2:
     77         name = "TestThreadedIntl";
     78 #if !UCONFIG_NO_FORMATTING
     79         if (exec) {
     80             TestThreadedIntl();
     81         }
     82 #endif
     83         break;
     84 
     85     case 3:
     86       name = "TestCollators";
     87 #if !UCONFIG_NO_COLLATION
     88       if (exec) {
     89             TestCollators();
     90       }
     91 #endif /* #if !UCONFIG_NO_COLLATION */
     92       break;
     93 
     94     case 4:
     95         name = "TestString";
     96         if (exec) {
     97             TestString();
     98         }
     99         break;
    100 
    101     case 5:
    102         name = "TestArabicShapingThreads";
    103         if (exec) {
    104             TestArabicShapingThreads();
    105         }
    106         break;
    107 
    108     case 6:
    109         name = "TestAnyTranslit";
    110         if (exec) {
    111             TestAnyTranslit();
    112         }
    113         break;
    114 
    115     case 7:
    116         name = "TestConditionVariables";
    117         if (exec) {
    118             TestConditionVariables();
    119         }
    120         break;
    121     case 8:
    122         name = "TestUnifiedCache";
    123         if (exec) {
    124             TestUnifiedCache();
    125         }
    126         break;
    127 #if !UCONFIG_NO_TRANSLITERATION
    128     case 9:
    129         name = "TestBreakTranslit";
    130         if (exec) {
    131             TestBreakTranslit();
    132         }
    133         break;
    134 #endif
    135     default:
    136         name = "";
    137         break; //needed to end loop
    138     }
    139 }
    140 
    141 
    142 //-----------------------------------------------------------------------------------
    143 //
    144 //   TestThreads -- see if threads really work at all.
    145 //
    146 //   Set up N threads pointing at N chars. When they are started, they will
    147 //   set their chars. At the end we make sure they are all set.
    148 //
    149 //-----------------------------------------------------------------------------------
    150 
    151 class TestThreadsThread : public SimpleThread
    152 {
    153 public:
    154     TestThreadsThread(char* whatToChange) { fWhatToChange = whatToChange; }
    155     virtual void run() { Mutex m;
    156                          *fWhatToChange = '*';
    157     }
    158 private:
    159     char *fWhatToChange;
    160 };
    161 
    162 
    163 void MultithreadTest::TestThreads()
    164 {
    165     static const int32_t THREADTEST_NRTHREADS = 8;
    166     char threadTestChars[THREADTEST_NRTHREADS + 1];
    167     SimpleThread *threads[THREADTEST_NRTHREADS];
    168     int32_t numThreadsStarted = 0;
    169 
    170     int32_t i;
    171     for(i=0;i<THREADTEST_NRTHREADS;i++)
    172     {
    173         threadTestChars[i] = ' ';
    174         threads[i] = new TestThreadsThread(&threadTestChars[i]);
    175     }
    176     threadTestChars[THREADTEST_NRTHREADS] = '\0';
    177 
    178     logln("->" + UnicodeString(threadTestChars) + "<- Firing off threads.. ");
    179     for(i=0;i<THREADTEST_NRTHREADS;i++)
    180     {
    181         if (threads[i]->start() != 0) {
    182             errln("Error starting thread %d", i);
    183         }
    184         else {
    185             numThreadsStarted++;
    186         }
    187         logln(" Subthread started.");
    188     }
    189 
    190     if (numThreadsStarted != THREADTEST_NRTHREADS) {
    191         errln("Not all threads could be started for testing!");
    192         return;
    193     }
    194 
    195     logln("Waiting for threads to be set..");
    196     for(i=0; i<THREADTEST_NRTHREADS; i++) {
    197         threads[i]->join();
    198         if (threadTestChars[i] != '*') {
    199             errln("%s:%d Thread %d failed.", __FILE__, __LINE__, i);
    200         }
    201         delete threads[i];
    202     }
    203 }
    204 
    205 
    206 //-----------------------------------------------------------------------------------
    207 //
    208 //   TestArabicShapeThreads -- see if calls to u_shapeArabic in many threads works successfully
    209 //
    210 //   Set up N threads pointing at N chars. When they are started, they will make calls to doTailTest which tests
    211 //   u_shapeArabic, if the calls are successful it will the set * chars.
    212 //   At the end we make sure all threads managed to run u_shapeArabic successfully.
    213 //   This is a unit test for ticket 9473
    214 //
    215 //-----------------------------------------------------------------------------------
    216 
    217 class TestArabicShapeThreads : public SimpleThread
    218 {
    219 public:
    220     TestArabicShapeThreads() {};
    221     virtual void run() { doTailTest(); };
    222 private:
    223 	void doTailTest();
    224 };
    225 
    226 
    227 void TestArabicShapeThreads::doTailTest(void) {
    228     static const UChar src[] = { 0x0020, 0x0633, 0 };
    229     static const UChar dst_old[] = { 0xFEB1, 0x200B,0 };
    230     static const UChar dst_new[] = { 0xFEB1, 0xFE73,0 };
    231     UChar dst[3] = { 0x0000, 0x0000,0 };
    232     int32_t length;
    233     UErrorCode status;
    234 
    235     for (int32_t loopCount = 0; loopCount < 100; loopCount++) {
    236         status = U_ZERO_ERROR;
    237         length = u_shapeArabic(src, -1, dst, UPRV_LENGTHOF(dst),
    238                 U_SHAPE_LETTERS_SHAPE|U_SHAPE_SEEN_TWOCELL_NEAR, &status);
    239         if(U_FAILURE(status)) {
    240             IntlTest::gTest->errln("Fail: status %s\n", u_errorName(status));
    241             return;
    242         } else if(length!=2) {
    243             IntlTest::gTest->errln("Fail: len %d expected 3\n", length);
    244             return;
    245         } else if(u_strncmp(dst,dst_old,UPRV_LENGTHOF(dst))) {
    246             IntlTest::gTest->errln("Fail: got U+%04X U+%04X expected U+%04X U+%04X\n",
    247                     dst[0],dst[1],dst_old[0],dst_old[1]);
    248             return;
    249         }
    250 
    251 
    252         //"Trying new tail
    253         status = U_ZERO_ERROR;
    254         length = u_shapeArabic(src, -1, dst, UPRV_LENGTHOF(dst),
    255                 U_SHAPE_LETTERS_SHAPE|U_SHAPE_SEEN_TWOCELL_NEAR|U_SHAPE_TAIL_NEW_UNICODE, &status);
    256         if(U_FAILURE(status)) {
    257             IntlTest::gTest->errln("Fail: status %s\n", u_errorName(status));
    258             return;
    259         } else if(length!=2) {
    260             IntlTest::gTest->errln("Fail: len %d expected 3\n", length);
    261             return;
    262         } else if(u_strncmp(dst,dst_new,UPRV_LENGTHOF(dst))) {
    263             IntlTest::gTest->errln("Fail: got U+%04X U+%04X expected U+%04X U+%04X\n",
    264                     dst[0],dst[1],dst_new[0],dst_new[1]);
    265             return;
    266         }
    267     }
    268     return;
    269 }
    270 
    271 
    272 void MultithreadTest::TestArabicShapingThreads()
    273 {
    274     TestArabicShapeThreads threads[30];
    275 
    276     int32_t i;
    277 
    278     logln("-> do TestArabicShapingThreads <- Firing off threads.. ");
    279     for(i=0; i < UPRV_LENGTHOF(threads); i++) {
    280         if (threads[i].start() != 0) {
    281             errln("Error starting thread %d", i);
    282         }
    283     }
    284 
    285     for(i=0; i < UPRV_LENGTHOF(threads); i++) {
    286         threads[i].join();
    287     }
    288     logln("->TestArabicShapingThreads <- Got all threads! cya");
    289 }
    290 
    291 
    292 //-----------------------------------------------------------------------
    293 //
    294 //  TestMutex  - a simple (non-stress) test to verify that ICU mutexes
    295 //               and condition variables are functioning.  Does not test the use of
    296 //               mutexes within ICU services, but rather that the
    297 //               platform's mutex support is at least superficially there.
    298 //
    299 //----------------------------------------------------------------------
    300 static UMutex         gTestMutexA          = U_MUTEX_INITIALIZER;
    301 static UConditionVar  gThreadsCountChanged = U_CONDITION_INITIALIZER;
    302 
    303 static int     gThreadsStarted = 0;
    304 static int     gThreadsInMiddle = 0;
    305 static int     gThreadsDone = 0;
    306 
    307 static const int TESTMUTEX_THREAD_COUNT = 40;
    308 
    309 class TestMutexThread : public SimpleThread
    310 {
    311 public:
    312     virtual void run() {
    313         // This is the code that each of the spawned threads runs.
    314         // All threads move together throught the started - middle - done sequence together,
    315         // waiting for all other threads to reach each point before advancing.
    316         umtx_lock(&gTestMutexA);
    317         gThreadsStarted += 1;
    318         umtx_condBroadcast(&gThreadsCountChanged);
    319         while (gThreadsStarted < TESTMUTEX_THREAD_COUNT) {
    320             if (gThreadsInMiddle != 0) {
    321                 IntlTest::gTest->errln(
    322                     "%s:%d gThreadsInMiddle = %d. Expected 0.", __FILE__, __LINE__, gThreadsInMiddle);
    323                 return;
    324             }
    325             umtx_condWait(&gThreadsCountChanged, &gTestMutexA);
    326         }
    327 
    328         gThreadsInMiddle += 1;
    329         umtx_condBroadcast(&gThreadsCountChanged);
    330         while (gThreadsInMiddle < TESTMUTEX_THREAD_COUNT) {
    331             if (gThreadsDone != 0) {
    332                 IntlTest::gTest->errln(
    333                     "%s:%d gThreadsDone = %d. Expected 0.", __FILE__, __LINE__, gThreadsDone);
    334                 return;
    335             }
    336             umtx_condWait(&gThreadsCountChanged, &gTestMutexA);
    337         }
    338 
    339         gThreadsDone += 1;
    340         umtx_condBroadcast(&gThreadsCountChanged);
    341         while (gThreadsDone < TESTMUTEX_THREAD_COUNT) {
    342             umtx_condWait(&gThreadsCountChanged, &gTestMutexA);
    343         }
    344         umtx_unlock(&gTestMutexA);
    345     }
    346 };
    347 
    348 void MultithreadTest::TestMutex()
    349 {
    350     gThreadsStarted = 0;
    351     gThreadsInMiddle = 0;
    352     gThreadsDone = 0;
    353     int32_t i = 0;
    354     TestMutexThread  threads[TESTMUTEX_THREAD_COUNT];
    355     umtx_lock(&gTestMutexA);
    356     for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) {
    357         if (threads[i].start() != 0) {
    358             errln("%s:%d Error starting thread %d", __FILE__, __LINE__, i);
    359             return;
    360         }
    361     }
    362 
    363     // Because we are holding gTestMutexA, all of the threads should be blocked
    364     // at the start of their run() function.
    365     if (gThreadsStarted != 0) {
    366         errln("%s:%d gThreadsStarted=%d. Expected 0.", __FILE__, __LINE__, gThreadsStarted);
    367         return;
    368     }
    369 
    370     while (gThreadsInMiddle < TESTMUTEX_THREAD_COUNT) {
    371         if (gThreadsDone != 0) {
    372             errln("%s:%d gThreadsDone=%d. Expected 0.", __FILE__, __LINE__, gThreadsStarted);
    373             return;
    374         }
    375         umtx_condWait(&gThreadsCountChanged, &gTestMutexA);
    376     }
    377 
    378     while (gThreadsDone < TESTMUTEX_THREAD_COUNT) {
    379         umtx_condWait(&gThreadsCountChanged, &gTestMutexA);
    380     }
    381     umtx_unlock(&gTestMutexA);
    382 
    383     for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) {
    384         threads[i].join();
    385     }
    386 }
    387 
    388 
    389 //-------------------------------------------------------------------------------------------
    390 //
    391 //   TestMultithreadedIntl.  Test ICU Formatting in a multi-threaded environment
    392 //
    393 //-------------------------------------------------------------------------------------------
    394 
    395 
    396 // * Show exactly where the string's differences lie.
    397 UnicodeString showDifference(const UnicodeString& expected, const UnicodeString& result)
    398 {
    399     UnicodeString res;
    400     res = expected + "<Expected\n";
    401     if(expected.length() != result.length())
    402         res += " [ Different lengths ] \n";
    403     else
    404     {
    405         for(int32_t i=0;i<expected.length();i++)
    406         {
    407             if(expected[i] == result[i])
    408             {
    409                 res += " ";
    410             }
    411             else
    412             {
    413                 res += "|";
    414             }
    415         }
    416         res += "<Differences";
    417         res += "\n";
    418     }
    419     res += result + "<Result\n";
    420 
    421     return res;
    422 }
    423 
    424 
    425 //-------------------------------------------------------------------------------------------
    426 //
    427 //   FormatThreadTest - a thread that tests performing a number of numberformats.
    428 //
    429 //-------------------------------------------------------------------------------------------
    430 
    431 const int kFormatThreadIterations = 100;  // # of iterations per thread
    432 const int kFormatThreadThreads    = 10;  // # of threads to spawn
    433 
    434 #if !UCONFIG_NO_FORMATTING
    435 
    436 
    437 
    438 struct FormatThreadTestData
    439 {
    440     double number;
    441     UnicodeString string;
    442     FormatThreadTestData(double a, const UnicodeString& b) : number(a),string(b) {}
    443 } ;
    444 
    445 
    446 // "Someone from {2} is receiving a #{0} error - {1}. Their telephone call is costing {3 number,currency}."
    447 
    448 static void formatErrorMessage(UErrorCode &realStatus, const UnicodeString& pattern, const Locale& theLocale,
    449                      UErrorCode inStatus0, /* statusString 1 */ const Locale &inCountry2, double currency3, // these numbers are the message arguments.
    450                      UnicodeString &result)
    451 {
    452     if(U_FAILURE(realStatus))
    453         return; // you messed up
    454 
    455     UnicodeString errString1(u_errorName(inStatus0));
    456 
    457     UnicodeString countryName2;
    458     inCountry2.getDisplayCountry(theLocale,countryName2);
    459 
    460     Formattable myArgs[] = {
    461         Formattable((int32_t)inStatus0),   // inStatus0      {0}
    462         Formattable(errString1), // statusString1 {1}
    463         Formattable(countryName2),  // inCountry2 {2}
    464         Formattable(currency3)// currency3  {3,number,currency}
    465     };
    466 
    467     MessageFormat *fmt = new MessageFormat("MessageFormat's API is broken!!!!!!!!!!!",realStatus);
    468     fmt->setLocale(theLocale);
    469     fmt->applyPattern(pattern, realStatus);
    470 
    471     if (U_FAILURE(realStatus)) {
    472         delete fmt;
    473         return;
    474     }
    475 
    476     FieldPosition ignore = 0;
    477     fmt->format(myArgs,4,result,ignore,realStatus);
    478 
    479     delete fmt;
    480 }
    481 
    482 /**
    483   * Shared formatters &  data used by instances of ThreadSafeFormat.
    484   * Exactly one instance of this class is created, and it is then shared concurrently
    485   * by the multiple instances of ThreadSafeFormat.
    486   */
    487 class ThreadSafeFormatSharedData {
    488   public:
    489     ThreadSafeFormatSharedData(UErrorCode &status);
    490     ~ThreadSafeFormatSharedData();
    491     LocalPointer<NumberFormat>  fFormat;
    492     Formattable    fYDDThing;
    493     Formattable    fBBDThing;
    494     UnicodeString  fYDDStr;
    495     UnicodeString  fBBDStr;
    496 };
    497 
    498 const ThreadSafeFormatSharedData *gSharedData = NULL;
    499 
    500 ThreadSafeFormatSharedData::ThreadSafeFormatSharedData(UErrorCode &status) {
    501     fFormat.adoptInstead(NumberFormat::createCurrencyInstance(Locale::getUS(), status));
    502     static const UChar kYDD[] = { 0x59, 0x44, 0x44, 0x00 };
    503     static const UChar kBBD[] = { 0x42, 0x42, 0x44, 0x00 };
    504     fYDDThing.adoptObject(new CurrencyAmount(123.456, kYDD, status));
    505     fBBDThing.adoptObject(new CurrencyAmount(987.654, kBBD, status));
    506     if (U_FAILURE(status)) {
    507         return;
    508     }
    509     fFormat->format(fYDDThing, fYDDStr, NULL, status);
    510     fFormat->format(fBBDThing, fBBDStr, NULL, status);
    511     gSharedData = this;
    512 }
    513 
    514 ThreadSafeFormatSharedData::~ThreadSafeFormatSharedData() {
    515     gSharedData = NULL;
    516 }
    517 
    518 /**
    519  * Class for thread-safe testing of format.
    520  *   Instances of this class appear as members of class FormatThreadTest.
    521  *   Multiple instances of FormatThreadTest coexist.
    522  *   ThreadSafeFormat::doStuff() is called concurrently to test the thread safety of
    523  *   various shared format operations.
    524  */
    525 class ThreadSafeFormat {
    526 public:
    527   /* give a unique offset to each thread */
    528   ThreadSafeFormat(UErrorCode &status);
    529   UBool doStuff(int32_t offset, UnicodeString &appendErr, UErrorCode &status) const;
    530 private:
    531   LocalPointer<NumberFormat> fFormat; // formatter - en_US constructed currency
    532 };
    533 
    534 
    535 ThreadSafeFormat::ThreadSafeFormat(UErrorCode &status) {
    536   fFormat.adoptInstead(NumberFormat::createCurrencyInstance(Locale::getUS(), status));
    537 }
    538 
    539 static const UChar kUSD[] = { 0x55, 0x53, 0x44, 0x00 };
    540 
    541 UBool ThreadSafeFormat::doStuff(int32_t offset, UnicodeString &appendErr, UErrorCode &status) const {
    542   UBool okay = TRUE;
    543 
    544   if(u_strcmp(fFormat->getCurrency(), kUSD)) {
    545     appendErr.append("fFormat currency != ")
    546       .append(kUSD)
    547       .append(", =")
    548       .append(fFormat->getCurrency())
    549       .append("! ");
    550     okay = FALSE;
    551   }
    552 
    553   if(u_strcmp(gSharedData->fFormat->getCurrency(), kUSD)) {
    554     appendErr.append("gFormat currency != ")
    555       .append(kUSD)
    556       .append(", =")
    557       .append(gSharedData->fFormat->getCurrency())
    558       .append("! ");
    559     okay = FALSE;
    560   }
    561   UnicodeString str;
    562   const UnicodeString *o=NULL;
    563   Formattable f;
    564   const NumberFormat *nf = NULL; // only operate on it as const.
    565   switch(offset%4) {
    566   case 0:  f = gSharedData->fYDDThing;  o = &gSharedData->fYDDStr;  nf = gSharedData->fFormat.getAlias();  break;
    567   case 1:  f = gSharedData->fBBDThing;  o = &gSharedData->fBBDStr;  nf = gSharedData->fFormat.getAlias();  break;
    568   case 2:  f = gSharedData->fYDDThing;  o = &gSharedData->fYDDStr;  nf = fFormat.getAlias();  break;
    569   case 3:  f = gSharedData->fBBDThing;  o = &gSharedData->fBBDStr;  nf = fFormat.getAlias();  break;
    570   }
    571   nf->format(f, str, NULL, status);
    572 
    573   if(*o != str) {
    574     appendErr.append(showDifference(*o, str));
    575     okay = FALSE;
    576   }
    577   return okay;
    578 }
    579 
    580 UBool U_CALLCONV isAcceptable(void *, const char *, const char *, const UDataInfo *) {
    581     return TRUE;
    582 }
    583 
    584 //static UMTX debugMutex = NULL;
    585 //static UMTX gDebugMutex;
    586 
    587 
    588 class FormatThreadTest : public SimpleThread
    589 {
    590 public:
    591     int     fNum;
    592     int     fTraceInfo;
    593 
    594     LocalPointer<ThreadSafeFormat> fTSF;
    595 
    596     FormatThreadTest() // constructor is NOT multithread safe.
    597         : SimpleThread(),
    598         fNum(0),
    599         fTraceInfo(0),
    600         fTSF(NULL),
    601         fOffset(0)
    602         // the locale to use
    603     {
    604         UErrorCode status = U_ZERO_ERROR;      // TODO: rearrange code to allow checking of status.
    605         fTSF.adoptInstead(new ThreadSafeFormat(status));
    606         static int32_t fgOffset = 0;
    607         fgOffset += 3;
    608         fOffset = fgOffset;
    609     }
    610 
    611 
    612     virtual void run()
    613     {
    614         fTraceInfo                     = 1;
    615         LocalPointer<NumberFormat> percentFormatter;
    616         UErrorCode status = U_ZERO_ERROR;
    617 
    618 #if 0
    619         // debugging code,
    620         for (int i=0; i<4000; i++) {
    621             status = U_ZERO_ERROR;
    622             UDataMemory *data1 = udata_openChoice(0, "res", "en_US", isAcceptable, 0, &status);
    623             UDataMemory *data2 = udata_openChoice(0, "res", "fr", isAcceptable, 0, &status);
    624             udata_close(data1);
    625             udata_close(data2);
    626             if (U_FAILURE(status)) {
    627                 error("udata_openChoice failed.\n");
    628                 break;
    629             }
    630         }
    631         return;
    632 #endif
    633 
    634 #if 0
    635         // debugging code,
    636         int m;
    637         for (m=0; m<4000; m++) {
    638             status         = U_ZERO_ERROR;
    639             UResourceBundle *res   = NULL;
    640             const char *localeName = NULL;
    641 
    642             Locale  loc = Locale::getEnglish();
    643 
    644             localeName = loc.getName();
    645             // localeName = "en";
    646 
    647             // ResourceBundle bund = ResourceBundle(0, loc, status);
    648             //umtx_lock(&gDebugMutex);
    649             res = ures_open(NULL, localeName, &status);
    650             //umtx_unlock(&gDebugMutex);
    651 
    652             //umtx_lock(&gDebugMutex);
    653             ures_close(res);
    654             //umtx_unlock(&gDebugMutex);
    655 
    656             if (U_FAILURE(status)) {
    657                 error("Resource bundle construction failed.\n");
    658                 break;
    659             }
    660         }
    661         return;
    662 #endif
    663 
    664         // Keep this data here to avoid static initialization.
    665         FormatThreadTestData kNumberFormatTestData[] =
    666         {
    667             FormatThreadTestData((double)5.0, UnicodeString("5", "")),
    668                 FormatThreadTestData( 6.0, UnicodeString("6", "")),
    669                 FormatThreadTestData( 20.0, UnicodeString("20", "")),
    670                 FormatThreadTestData( 8.0, UnicodeString("8", "")),
    671                 FormatThreadTestData( 8.3, UnicodeString("8.3", "")),
    672                 FormatThreadTestData( 12345, UnicodeString("12,345", "")),
    673                 FormatThreadTestData( 81890.23, UnicodeString("81,890.23", "")),
    674         };
    675         int32_t kNumberFormatTestDataLength = UPRV_LENGTHOF(kNumberFormatTestData);
    676 
    677         // Keep this data here to avoid static initialization.
    678         FormatThreadTestData kPercentFormatTestData[] =
    679         {
    680             FormatThreadTestData((double)5.0, CharsToUnicodeString("500\\u00a0%")),
    681                 FormatThreadTestData( 1.0, CharsToUnicodeString("100\\u00a0%")),
    682                 FormatThreadTestData( 0.26, CharsToUnicodeString("26\\u00a0%")),
    683                 FormatThreadTestData(
    684                    16384.99, CharsToUnicodeString("1\\u00a0638\\u00a0499\\u00a0%")), // U+00a0 = NBSP
    685                 FormatThreadTestData(
    686                     81890.23, CharsToUnicodeString("8\\u00a0189\\u00a0023\\u00a0%")),
    687         };
    688         int32_t kPercentFormatTestDataLength = UPRV_LENGTHOF(kPercentFormatTestData);
    689         int32_t iteration;
    690 
    691         status = U_ZERO_ERROR;
    692         LocalPointer<NumberFormat> formatter(NumberFormat::createInstance(Locale::getEnglish(),status));
    693         if(U_FAILURE(status)) {
    694             IntlTest::gTest->dataerrln("%s:%d Error %s on NumberFormat::createInstance().",
    695                     __FILE__, __LINE__, u_errorName(status));
    696             goto cleanupAndReturn;
    697         }
    698 
    699         percentFormatter.adoptInstead(NumberFormat::createPercentInstance(Locale::getFrench(),status));
    700         if(U_FAILURE(status))             {
    701             IntlTest::gTest->errln("%s:%d Error %s on NumberFormat::createPercentInstance().",
    702                     __FILE__, __LINE__, u_errorName(status));
    703             goto cleanupAndReturn;
    704         }
    705 
    706         for(iteration = 0;!IntlTest::gTest->getErrors() && iteration<kFormatThreadIterations;iteration++)
    707         {
    708 
    709             int32_t whichLine = (iteration + fOffset)%kNumberFormatTestDataLength;
    710 
    711             UnicodeString  output;
    712 
    713             formatter->format(kNumberFormatTestData[whichLine].number, output);
    714 
    715             if(0 != output.compare(kNumberFormatTestData[whichLine].string)) {
    716                 IntlTest::gTest->errln("format().. expected " + kNumberFormatTestData[whichLine].string
    717                         + " got " + output);
    718                 goto cleanupAndReturn;
    719             }
    720 
    721             // Now check percent.
    722             output.remove();
    723             whichLine = (iteration + fOffset)%kPercentFormatTestDataLength;
    724 
    725             percentFormatter->format(kPercentFormatTestData[whichLine].number, output);
    726             if(0 != output.compare(kPercentFormatTestData[whichLine].string))
    727             {
    728                 IntlTest::gTest->errln("percent format().. \n" +
    729                         showDifference(kPercentFormatTestData[whichLine].string,output));
    730                 goto cleanupAndReturn;
    731             }
    732 
    733             // Test message error
    734             const int       kNumberOfMessageTests = 3;
    735             UErrorCode      statusToCheck;
    736             UnicodeString   patternToCheck;
    737             Locale          messageLocale;
    738             Locale          countryToCheck;
    739             double          currencyToCheck;
    740 
    741             UnicodeString   expected;
    742 
    743             // load the cases.
    744             switch((iteration+fOffset) % kNumberOfMessageTests)
    745             {
    746             default:
    747             case 0:
    748                 statusToCheck=                      U_FILE_ACCESS_ERROR;
    749                 patternToCheck=        "0:Someone from {2} is receiving a #{0}"
    750                                        " error - {1}. Their telephone call is costing "
    751                                        "{3,number,currency}."; // number,currency
    752                 messageLocale=                      Locale("en","US");
    753                 countryToCheck=                     Locale("","HR");
    754                 currencyToCheck=                    8192.77;
    755                 expected=  "0:Someone from Croatia is receiving a #4 error - "
    756                             "U_FILE_ACCESS_ERROR. Their telephone call is costing $8,192.77.";
    757                 break;
    758             case 1:
    759                 statusToCheck=                      U_INDEX_OUTOFBOUNDS_ERROR;
    760                 patternToCheck=                     "1:A customer in {2} is receiving a #{0} error - {1}. "
    761                                                     "Their telephone call is costing {3,number,currency}."; // number,currency
    762                 messageLocale=                      Locale("de","DE@currency=DEM");
    763                 countryToCheck=                     Locale("","BF");
    764                 currencyToCheck=                    2.32;
    765                 expected=                           CharsToUnicodeString(
    766                                                     "1:A customer in Burkina Faso is receiving a #8 error - U_INDEX_OUTOFBOUNDS_ERROR. "
    767                                                     "Their telephone call is costing 2,32\\u00A0DM.");
    768                 break;
    769             case 2:
    770                 statusToCheck=                      U_MEMORY_ALLOCATION_ERROR;
    771                 patternToCheck=   "2:user in {2} is receiving a #{0} error - {1}. "
    772                                   "They insist they just spent {3,number,currency} "
    773                                   "on memory."; // number,currency
    774                 messageLocale=                      Locale("de","AT@currency=ATS"); // Austrian German
    775                 countryToCheck=                     Locale("","US"); // hmm
    776                 currencyToCheck=                    40193.12;
    777                 expected=       CharsToUnicodeString(
    778                             "2:user in Vereinigte Staaten is receiving a #7 error"
    779                             " - U_MEMORY_ALLOCATION_ERROR. They insist they just spent"
    780                             " \\u00f6S\\u00A040\\u00A0193,12 on memory.");
    781                 break;
    782             }
    783 
    784             UnicodeString result;
    785             UErrorCode status = U_ZERO_ERROR;
    786             formatErrorMessage(status,patternToCheck,messageLocale,statusToCheck,
    787                                 countryToCheck,currencyToCheck,result);
    788             if(U_FAILURE(status))
    789             {
    790                 UnicodeString tmp(u_errorName(status));
    791                 IntlTest::gTest->errln("Failure on message format, pattern=" + patternToCheck +
    792                         ", error = " + tmp);
    793                 goto cleanupAndReturn;
    794             }
    795 
    796             if(result != expected)
    797             {
    798                 IntlTest::gTest->errln("PatternFormat: \n" + showDifference(expected,result));
    799                 goto cleanupAndReturn;
    800             }
    801             // test the Thread Safe Format
    802             UnicodeString appendErr;
    803             if(!fTSF->doStuff(fNum, appendErr, status)) {
    804               IntlTest::gTest->errln(appendErr);
    805               goto cleanupAndReturn;
    806             }
    807         }   /*  end of for loop */
    808 
    809 
    810 
    811 cleanupAndReturn:
    812         fTraceInfo = 2;
    813     }
    814 
    815 private:
    816     int32_t fOffset; // where we are testing from.
    817 };
    818 
    819 // ** The actual test function.
    820 
    821 void MultithreadTest::TestThreadedIntl()
    822 {
    823     UnicodeString theErr;
    824 
    825     UErrorCode threadSafeErr = U_ZERO_ERROR;
    826 
    827     ThreadSafeFormatSharedData sharedData(threadSafeErr);
    828     assertSuccess("initializing ThreadSafeFormat", threadSafeErr, TRUE);
    829 
    830     //
    831     //  Create and start the test threads
    832     //
    833     logln("Spawning: %d threads * %d iterations each.",
    834                 kFormatThreadThreads, kFormatThreadIterations);
    835     FormatThreadTest tests[kFormatThreadThreads];
    836     int32_t j;
    837     for(j = 0; j < UPRV_LENGTHOF(tests); j++) {
    838         tests[j].fNum = j;
    839         int32_t threadStatus = tests[j].start();
    840         if (threadStatus != 0) {
    841             errln("%s:%d System Error %d starting thread number %d.",
    842                     __FILE__, __LINE__, threadStatus, j);
    843             return;
    844         }
    845     }
    846 
    847 
    848     for (j=0; j<UPRV_LENGTHOF(tests); j++) {
    849         tests[j].join();
    850         logln("Thread # %d is complete..", j);
    851     }
    852 }
    853 #endif /* #if !UCONFIG_NO_FORMATTING */
    854 
    855 
    856 
    857 
    858 
    859 //-------------------------------------------------------------------------------------------
    860 //
    861 // Collation threading test
    862 //
    863 //-------------------------------------------------------------------------------------------
    864 #if !UCONFIG_NO_COLLATION
    865 
    866 #define kCollatorThreadThreads   10  // # of threads to spawn
    867 #define kCollatorThreadPatience kCollatorThreadThreads*30
    868 
    869 struct Line {
    870     UChar buff[25];
    871     int32_t buflen;
    872 } ;
    873 
    874 static UBool
    875 skipLineBecauseOfBug(const UChar *s, int32_t length) {
    876     // TODO: Fix ICU ticket #8052
    877     if(length >= 3 &&
    878             (s[0] == 0xfb2 || s[0] == 0xfb3) &&
    879             s[1] == 0x334 &&
    880             (s[2] == 0xf73 || s[2] == 0xf75 || s[2] == 0xf81)) {
    881         return TRUE;
    882     }
    883     return FALSE;
    884 }
    885 
    886 static UCollationResult
    887 normalizeResult(int32_t result) {
    888     return result<0 ? UCOL_LESS : result==0 ? UCOL_EQUAL : UCOL_GREATER;
    889 }
    890 
    891 class CollatorThreadTest : public SimpleThread
    892 {
    893 private:
    894     const Collator *coll;
    895     const Line *lines;
    896     int32_t noLines;
    897     UBool isAtLeastUCA62;
    898 public:
    899     CollatorThreadTest()  : SimpleThread(),
    900         coll(NULL),
    901         lines(NULL),
    902         noLines(0),
    903         isAtLeastUCA62(TRUE)
    904     {
    905     };
    906     void setCollator(Collator *c, Line *l, int32_t nl, UBool atLeastUCA62)
    907     {
    908         coll = c;
    909         lines = l;
    910         noLines = nl;
    911         isAtLeastUCA62 = atLeastUCA62;
    912     }
    913     virtual void run() {
    914         uint8_t sk1[1024], sk2[1024];
    915         uint8_t *oldSk = NULL, *newSk = sk1;
    916         int32_t oldLen = 0;
    917         int32_t prev = 0;
    918         int32_t i = 0;
    919 
    920         for(i = 0; i < noLines; i++) {
    921             if(lines[i].buflen == 0) { continue; }
    922 
    923             if(skipLineBecauseOfBug(lines[i].buff, lines[i].buflen)) { continue; }
    924 
    925             int32_t resLen = coll->getSortKey(lines[i].buff, lines[i].buflen, newSk, 1024);
    926 
    927             if(oldSk != NULL) {
    928                 int32_t skres = strcmp((char *)oldSk, (char *)newSk);
    929                 int32_t cmpres = coll->compare(lines[prev].buff, lines[prev].buflen, lines[i].buff, lines[i].buflen);
    930                 int32_t cmpres2 = coll->compare(lines[i].buff, lines[i].buflen, lines[prev].buff, lines[prev].buflen);
    931 
    932                 if(cmpres != -cmpres2) {
    933                     IntlTest::gTest->errln(UnicodeString("Compare result not symmetrical on line ") + (i + 1));
    934                     break;
    935                 }
    936 
    937                 if(cmpres != normalizeResult(skres)) {
    938                     IntlTest::gTest->errln(UnicodeString("Difference between coll->compare and sortkey compare on line ") + (i + 1));
    939                     break;
    940                 }
    941 
    942                 int32_t res = cmpres;
    943                 if(res == 0 && !isAtLeastUCA62) {
    944                     // Up to UCA 6.1, the collation test files use a custom tie-breaker,
    945                     // comparing the raw input strings.
    946                     res = u_strcmpCodePointOrder(lines[prev].buff, lines[i].buff);
    947                     // Starting with UCA 6.2, the collation test files use the standard UCA tie-breaker,
    948                     // comparing the NFD versions of the input strings,
    949                     // which we do via setting strength=identical.
    950                 }
    951                 if(res > 0) {
    952                     IntlTest::gTest->errln(UnicodeString("Line is not greater or equal than previous line, for line ") + (i + 1));
    953                     break;
    954                 }
    955             }
    956 
    957             oldSk = newSk;
    958             oldLen = resLen;
    959             (void)oldLen;   // Suppress set but not used warning.
    960             prev = i;
    961 
    962             newSk = (newSk == sk1)?sk2:sk1;
    963         }
    964     }
    965 };
    966 
    967 void MultithreadTest::TestCollators()
    968 {
    969 
    970     UErrorCode status = U_ZERO_ERROR;
    971     FILE *testFile = NULL;
    972     char testDataPath[1024];
    973     strcpy(testDataPath, IntlTest::getSourceTestData(status));
    974     if (U_FAILURE(status)) {
    975         errln("ERROR: could not open test data %s", u_errorName(status));
    976         return;
    977     }
    978     strcat(testDataPath, "CollationTest_");
    979 
    980     const char* type = "NON_IGNORABLE";
    981 
    982     const char *ext = ".txt";
    983     if(testFile) {
    984         fclose(testFile);
    985     }
    986     char buffer[1024];
    987     strcpy(buffer, testDataPath);
    988     strcat(buffer, type);
    989     size_t bufLen = strlen(buffer);
    990 
    991     // we try to open 3 files:
    992     // path/CollationTest_type.txt
    993     // path/CollationTest_type_SHORT.txt
    994     // path/CollationTest_type_STUB.txt
    995     // we are going to test with the first one that we manage to open.
    996 
    997     strcpy(buffer+bufLen, ext);
    998 
    999     testFile = fopen(buffer, "rb");
   1000 
   1001     if(testFile == 0) {
   1002         strcpy(buffer+bufLen, "_SHORT");
   1003         strcat(buffer, ext);
   1004         testFile = fopen(buffer, "rb");
   1005 
   1006         if(testFile == 0) {
   1007             strcpy(buffer+bufLen, "_STUB");
   1008             strcat(buffer, ext);
   1009             testFile = fopen(buffer, "rb");
   1010 
   1011             if (testFile == 0) {
   1012                 *(buffer+bufLen) = 0;
   1013                 dataerrln("could not open any of the conformance test files, tried opening base %s", buffer);
   1014                 return;
   1015             } else {
   1016                 infoln(
   1017                     "INFO: Working with the stub file.\n"
   1018                     "If you need the full conformance test, please\n"
   1019                     "download the appropriate data files from:\n"
   1020                     "http://source.icu-project.org/repos/icu/tools/trunk/unicodetools/com/ibm/text/data/");
   1021             }
   1022         }
   1023     }
   1024 
   1025     LocalArray<Line> lines(new Line[200000]);
   1026     memset(lines.getAlias(), 0, sizeof(Line)*200000);
   1027     int32_t lineNum = 0;
   1028 
   1029     UChar bufferU[1024];
   1030     uint32_t first = 0;
   1031 
   1032     while (fgets(buffer, 1024, testFile) != NULL) {
   1033         if(*buffer == 0 || buffer[0] == '#') {
   1034             // Store empty and comment lines so that errors are reported
   1035             // for the real test file lines.
   1036             lines[lineNum].buflen = 0;
   1037             lines[lineNum].buff[0] = 0;
   1038         } else {
   1039             int32_t buflen = u_parseString(buffer, bufferU, 1024, &first, &status);
   1040             lines[lineNum].buflen = buflen;
   1041             u_memcpy(lines[lineNum].buff, bufferU, buflen);
   1042             lines[lineNum].buff[buflen] = 0;
   1043         }
   1044         lineNum++;
   1045     }
   1046     fclose(testFile);
   1047     if(U_FAILURE(status)) {
   1048       dataerrln("Couldn't read the test file!");
   1049       return;
   1050     }
   1051 
   1052     UVersionInfo uniVersion;
   1053     static const UVersionInfo v62 = { 6, 2, 0, 0 };
   1054     u_getUnicodeVersion(uniVersion);
   1055     UBool isAtLeastUCA62 = uprv_memcmp(uniVersion, v62, 4) >= 0;
   1056 
   1057     LocalPointer<Collator> coll(Collator::createInstance(Locale::getRoot(), status));
   1058     if(U_FAILURE(status)) {
   1059         errcheckln(status, "Couldn't open UCA collator");
   1060         return;
   1061     }
   1062     coll->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status);
   1063     coll->setAttribute(UCOL_CASE_FIRST, UCOL_OFF, status);
   1064     coll->setAttribute(UCOL_CASE_LEVEL, UCOL_OFF, status);
   1065     coll->setAttribute(UCOL_STRENGTH, isAtLeastUCA62 ? UCOL_IDENTICAL : UCOL_TERTIARY, status);
   1066     coll->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_NON_IGNORABLE, status);
   1067 
   1068     int32_t spawnResult = 0;
   1069     LocalArray<CollatorThreadTest> tests(new CollatorThreadTest[kCollatorThreadThreads]);
   1070 
   1071     logln(UnicodeString("Spawning: ") + kCollatorThreadThreads + " threads * " + kFormatThreadIterations + " iterations each.");
   1072     int32_t j = 0;
   1073     for(j = 0; j < kCollatorThreadThreads; j++) {
   1074         //logln("Setting collator %i", j);
   1075         tests[j].setCollator(coll.getAlias(), lines.getAlias(), lineNum, isAtLeastUCA62);
   1076     }
   1077     for(j = 0; j < kCollatorThreadThreads; j++) {
   1078         log("%i ", j);
   1079         spawnResult = tests[j].start();
   1080         if(spawnResult != 0) {
   1081             errln("%s:%d THREAD INFO: thread %d failed to start with status %d", __FILE__, __LINE__, j, spawnResult);
   1082             return;
   1083         }
   1084     }
   1085     logln("Spawned all");
   1086 
   1087     for(int32_t i=0;i<kCollatorThreadThreads;i++) {
   1088         tests[i].join();
   1089         //logln(UnicodeString("Test #") + i + " is complete.. ");
   1090     }
   1091 }
   1092 
   1093 #endif /* #if !UCONFIG_NO_COLLATION */
   1094 
   1095 
   1096 
   1097 
   1098 //-------------------------------------------------------------------------------------------
   1099 //
   1100 //   StringThreadTest2
   1101 //
   1102 //-------------------------------------------------------------------------------------------
   1103 
   1104 const int kStringThreadIterations = 2500;// # of iterations per thread
   1105 const int kStringThreadThreads    = 10;  // # of threads to spawn
   1106 
   1107 
   1108 class StringThreadTest2 : public SimpleThread
   1109 {
   1110 public:
   1111     int                 fNum;
   1112     int                 fTraceInfo;
   1113     static const UnicodeString *gSharedString;
   1114 
   1115     StringThreadTest2() // constructor is NOT multithread safe.
   1116         : SimpleThread(),
   1117         fTraceInfo(0)
   1118     {
   1119     };
   1120 
   1121 
   1122     virtual void run()
   1123     {
   1124         fTraceInfo    = 1;
   1125         int loopCount = 0;
   1126 
   1127         for (loopCount = 0; loopCount < kStringThreadIterations; loopCount++) {
   1128             if (*gSharedString != "This is the original test string.") {
   1129                 IntlTest::gTest->errln("%s:%d Original string is corrupt.", __FILE__, __LINE__);
   1130                 break;
   1131             }
   1132             UnicodeString s1 = *gSharedString;
   1133             s1 += "cat this";
   1134             UnicodeString s2(s1);
   1135             UnicodeString s3 = *gSharedString;
   1136             s2 = s3;
   1137             s3.truncate(12);
   1138             s2.truncate(0);
   1139         }
   1140 
   1141         fTraceInfo = 2;
   1142     }
   1143 
   1144 };
   1145 
   1146 const UnicodeString *StringThreadTest2::gSharedString = NULL;
   1147 
   1148 // ** The actual test function.
   1149 
   1150 
   1151 void MultithreadTest::TestString()
   1152 {
   1153     int     j;
   1154     StringThreadTest2::gSharedString = new UnicodeString("This is the original test string.");
   1155     StringThreadTest2  tests[kStringThreadThreads];
   1156 
   1157     logln(UnicodeString("Spawning: ") + kStringThreadThreads + " threads * " + kStringThreadIterations + " iterations each.");
   1158     for(j = 0; j < kStringThreadThreads; j++) {
   1159         int32_t threadStatus = tests[j].start();
   1160         if (threadStatus != 0) {
   1161             errln("%s:%d System Error %d starting thread number %d.", __FILE__, __LINE__, threadStatus, j);
   1162         }
   1163     }
   1164 
   1165     // Force a failure, to verify test is functioning and can report errors.
   1166     // const_cast<UnicodeString *>(StringThreadTest2::gSharedString)->setCharAt(5, 'x');
   1167 
   1168     for(j=0; j<kStringThreadThreads; j++) {
   1169         tests[j].join();
   1170         logln(UnicodeString("Test #") + j + " is complete.. ");
   1171     }
   1172 
   1173     delete StringThreadTest2::gSharedString;
   1174     StringThreadTest2::gSharedString = NULL;
   1175 }
   1176 
   1177 
   1178 //
   1179 // Test for ticket #10673, race in cache code in AnyTransliterator.
   1180 // It's difficult to make the original unsafe code actually fail, but
   1181 // this test will fairly reliably take the code path for races in
   1182 // populating the cache.
   1183 //
   1184 
   1185 #if !UCONFIG_NO_TRANSLITERATION
   1186 Transliterator *gSharedTranslit = NULL;
   1187 class TxThread: public SimpleThread {
   1188   public:
   1189     TxThread() {};
   1190     ~TxThread();
   1191     void run();
   1192 };
   1193 
   1194 TxThread::~TxThread() {}
   1195 void TxThread::run() {
   1196     UnicodeString greekString("\\u03B4\\u03B9\\u03B1\\u03C6\\u03BF\\u03C1\\u03B5\\u03C4\\u03B9\\u03BA\\u03BF\\u03CD\\u03C2");
   1197     greekString = greekString.unescape();
   1198     gSharedTranslit->transliterate(greekString);
   1199     if (greekString[0] != 0x64)      // 'd'. The whole transliterated string is "diaphoretikous" (accented u).
   1200     {
   1201         IntlTest::gTest->errln("%s:%d Transliteration failed.", __FILE__, __LINE__);
   1202     }
   1203 }
   1204 #endif
   1205 
   1206 
   1207 void MultithreadTest::TestAnyTranslit() {
   1208 #if !UCONFIG_NO_TRANSLITERATION
   1209     UErrorCode status = U_ZERO_ERROR;
   1210     LocalPointer<Transliterator> tx(Transliterator::createInstance("Any-Latin", UTRANS_FORWARD, status));
   1211     if (U_FAILURE(status)) {
   1212         dataerrln("File %s, Line %d: Error, status = %s", __FILE__, __LINE__, u_errorName(status));
   1213         return;
   1214     }
   1215     gSharedTranslit = tx.getAlias();
   1216     TxThread  threads[4];
   1217     int32_t i;
   1218     for (i=0; i<UPRV_LENGTHOF(threads); i++) {
   1219         threads[i].start();
   1220     }
   1221 
   1222     for (i=0; i<UPRV_LENGTHOF(threads); i++) {
   1223         threads[i].join();
   1224     }
   1225     gSharedTranslit = NULL;
   1226 #endif  // !UCONFIG_NO_TRANSLITERATION
   1227 }
   1228 
   1229 
   1230 //
   1231 // Condition Variables Test
   1232 //   Create a swarm of threads.
   1233 //   Using a mutex and a condition variables each thread
   1234 //     Increments a global count of started threads.
   1235 //     Broadcasts that it has started.
   1236 //     Waits on the condition that all threads have started.
   1237 //     Increments a global count of finished threads.
   1238 //     Waits on the condition that all threads have finished.
   1239 //     Exits.
   1240 //
   1241 
   1242 class CondThread: public SimpleThread {
   1243   public:
   1244     CondThread() :fFinished(false)  {};
   1245     ~CondThread() {};
   1246     void run();
   1247     bool  fFinished;
   1248 };
   1249 
   1250 static UMutex gCTMutex = U_MUTEX_INITIALIZER;
   1251 static UConditionVar gCTConditionVar = U_CONDITION_INITIALIZER;
   1252 int gConditionTestOne = 1;   // Value one. Non-const, extern linkage to inhibit
   1253                              //   compiler assuming a known value.
   1254 int gStartedThreads;
   1255 int gFinishedThreads;
   1256 static const int NUMTHREADS = 10;
   1257 
   1258 
   1259 // Worker thread function.
   1260 void CondThread::run() {
   1261     umtx_lock(&gCTMutex);
   1262     gStartedThreads += gConditionTestOne;
   1263     umtx_condBroadcast(&gCTConditionVar);
   1264 
   1265     while (gStartedThreads < NUMTHREADS) {
   1266         if (gFinishedThreads != 0) {
   1267             IntlTest::gTest->errln("File %s, Line %d: Error, gStartedThreads = %d, gFinishedThreads = %d",
   1268                              __FILE__, __LINE__, gStartedThreads, gFinishedThreads);
   1269         }
   1270         umtx_condWait(&gCTConditionVar, &gCTMutex);
   1271     }
   1272 
   1273     gFinishedThreads += gConditionTestOne;
   1274     fFinished = true;
   1275     umtx_condBroadcast(&gCTConditionVar);
   1276 
   1277     while (gFinishedThreads < NUMTHREADS) {
   1278         umtx_condWait(&gCTConditionVar, &gCTMutex);
   1279     }
   1280     umtx_unlock(&gCTMutex);
   1281 }
   1282 
   1283 void MultithreadTest::TestConditionVariables() {
   1284     gStartedThreads = 0;
   1285     gFinishedThreads = 0;
   1286     int i;
   1287 
   1288     umtx_lock(&gCTMutex);
   1289     CondThread *threads[NUMTHREADS];
   1290     for (i=0; i<NUMTHREADS; ++i) {
   1291         threads[i] = new CondThread;
   1292         threads[i]->start();
   1293     }
   1294 
   1295     while (gStartedThreads < NUMTHREADS) {
   1296         umtx_condWait(&gCTConditionVar, &gCTMutex);
   1297     }
   1298 
   1299     while (gFinishedThreads < NUMTHREADS) {
   1300         umtx_condWait(&gCTConditionVar, &gCTMutex);
   1301     }
   1302 
   1303     umtx_unlock(&gCTMutex);
   1304 
   1305     for (i=0; i<NUMTHREADS; ++i) {
   1306         if (!threads[i]->fFinished) {
   1307             errln("File %s, Line %d: Error, threads[%d]->fFinished == false", __FILE__, __LINE__, i);
   1308         }
   1309     }
   1310 
   1311     for (i=0; i<NUMTHREADS; ++i) {
   1312         threads[i]->join();
   1313         delete threads[i];
   1314     }
   1315 }
   1316 
   1317 
   1318 //
   1319 // Unified Cache Test
   1320 //
   1321 
   1322 // Each thread fetches a pair of objects. There are 8 distinct pairs:
   1323 // ("en_US", "bs"), ("en_GB", "ca"), ("fr_FR", "ca_AD") etc.
   1324 // These pairs represent 8 distinct languages
   1325 
   1326 // Note that only one value per language gets created in the cache.
   1327 // In particular each cached value can have multiple keys.
   1328 static const char *gCacheLocales[] = {
   1329     "en_US", "en_GB", "fr_FR", "fr",
   1330     "de", "sr_ME", "sr_BA", "sr_CS"};
   1331 static const char *gCacheLocales2[] = {
   1332     "bs", "ca", "ca_AD", "ca_ES",
   1333     "en_US", "fi", "ff_CM", "ff_GN"};
   1334 
   1335 static int32_t gObjectsCreated = 0;  // protected by gCTMutex
   1336 static const int32_t CACHE_LOAD = 3;
   1337 
   1338 class UCTMultiThreadItem : public SharedObject {
   1339   public:
   1340     char *value;
   1341     UCTMultiThreadItem(const char *x) : value(NULL) {
   1342         value = uprv_strdup(x);
   1343     }
   1344     virtual ~UCTMultiThreadItem() {
   1345         uprv_free(value);
   1346     }
   1347 };
   1348 
   1349 U_NAMESPACE_BEGIN
   1350 
   1351 template<> U_EXPORT
   1352 const UCTMultiThreadItem *LocaleCacheKey<UCTMultiThreadItem>::createObject(
   1353         const void *context, UErrorCode &status) const {
   1354     const UnifiedCache *cacheContext = (const UnifiedCache *) context;
   1355 
   1356     if (uprv_strcmp(fLoc.getLanguage(), fLoc.getName()) != 0) {
   1357         const UCTMultiThreadItem *result = NULL;
   1358         if (cacheContext == NULL) {
   1359             UnifiedCache::getByLocale(fLoc.getLanguage(), result, status);
   1360             return result;
   1361         }
   1362         cacheContext->get(LocaleCacheKey<UCTMultiThreadItem>(fLoc.getLanguage()), result, status);
   1363         return result;
   1364     }
   1365 
   1366     umtx_lock(&gCTMutex);
   1367     bool firstObject = (gObjectsCreated == 0);
   1368     if (firstObject) {
   1369         // Force the first object creation that comes through to wait
   1370         // until other have completed. Verifies that cache doesn't
   1371         // deadlock when a creation is slow.
   1372 
   1373         // Note that gObjectsCreated needs to be incremeneted from 0 to 1
   1374         // early, to keep subsequent threads from entering this path.
   1375         gObjectsCreated = 1;
   1376         while (gObjectsCreated < 3) {
   1377             umtx_condWait(&gCTConditionVar, &gCTMutex);
   1378         }
   1379     }
   1380     umtx_unlock(&gCTMutex);
   1381 
   1382     const UCTMultiThreadItem *result =
   1383         new UCTMultiThreadItem(fLoc.getLanguage());
   1384     if (result == NULL) {
   1385         status = U_MEMORY_ALLOCATION_ERROR;
   1386     } else {
   1387         result->addRef();
   1388     }
   1389 
   1390     // Log that we created an object. The first object was already counted,
   1391     //    don't do it again.
   1392     umtx_lock(&gCTMutex);
   1393     if (!firstObject) {
   1394         gObjectsCreated += 1;
   1395     }
   1396     umtx_condBroadcast(&gCTConditionVar);
   1397     umtx_unlock(&gCTMutex);
   1398 
   1399     return result;
   1400 }
   1401 
   1402 U_NAMESPACE_END
   1403 
   1404 class UnifiedCacheThread: public SimpleThread {
   1405   public:
   1406     UnifiedCacheThread(
   1407             const UnifiedCache *cache,
   1408             const char *loc,
   1409             const char *loc2) : fCache(cache), fLoc(loc), fLoc2(loc2) {};
   1410     ~UnifiedCacheThread() {};
   1411     void run();
   1412     void exerciseByLocale(const Locale &);
   1413     const UnifiedCache *fCache;
   1414     Locale fLoc;
   1415     Locale fLoc2;
   1416 };
   1417 
   1418 void UnifiedCacheThread::exerciseByLocale(const Locale &locale) {
   1419     UErrorCode status = U_ZERO_ERROR;
   1420     const UCTMultiThreadItem *origItem = NULL;
   1421     fCache->get(
   1422             LocaleCacheKey<UCTMultiThreadItem>(locale), fCache, origItem, status);
   1423     U_ASSERT(U_SUCCESS(status));
   1424     if (uprv_strcmp(locale.getLanguage(), origItem->value)) {
   1425       IntlTest::gTest->errln(
   1426               "%s:%d Expected %s, got %s", __FILE__, __LINE__,
   1427               locale.getLanguage(),
   1428               origItem->value);
   1429     }
   1430 
   1431     // Fetch the same item again many times. We should always get the same
   1432     // pointer since this client is already holding onto it
   1433     for (int32_t i = 0; i < 1000; ++i) {
   1434         const UCTMultiThreadItem *item = NULL;
   1435         fCache->get(
   1436                 LocaleCacheKey<UCTMultiThreadItem>(locale), fCache, item, status);
   1437         if (item != origItem) {
   1438             IntlTest::gTest->errln(
   1439                     "%s:%d Expected to get the same pointer",
   1440                      __FILE__,
   1441                      __LINE__);
   1442         }
   1443         if (item != NULL) {
   1444             item->removeRef();
   1445         }
   1446     }
   1447     origItem->removeRef();
   1448 }
   1449 
   1450 void UnifiedCacheThread::run() {
   1451     // Run the exercise with 2 different locales so that we can exercise
   1452     // eviction more. If each thread exerices just one locale, then
   1453     // eviction can't start until the threads end.
   1454     exerciseByLocale(fLoc);
   1455     exerciseByLocale(fLoc2);
   1456 }
   1457 
   1458 void MultithreadTest::TestUnifiedCache() {
   1459 
   1460     // Start with our own local cache so that we have complete control
   1461     // and set the eviction policy to evict starting with 2 unused
   1462     // values
   1463     UErrorCode status = U_ZERO_ERROR;
   1464     UnifiedCache::getInstance(status);
   1465     UnifiedCache cache(status);
   1466     cache.setEvictionPolicy(2, 0, status);
   1467     U_ASSERT(U_SUCCESS(status));
   1468 
   1469     gFinishedThreads = 0;
   1470     gObjectsCreated = 0;
   1471 
   1472     UnifiedCacheThread *threads[CACHE_LOAD][UPRV_LENGTHOF(gCacheLocales)];
   1473     for (int32_t i=0; i<CACHE_LOAD; ++i) {
   1474         for (int32_t j=0; j<UPRV_LENGTHOF(gCacheLocales); ++j) {
   1475             // Each thread works with a pair of locales.
   1476             threads[i][j] = new UnifiedCacheThread(
   1477                     &cache, gCacheLocales[j], gCacheLocales2[j]);
   1478             threads[i][j]->start();
   1479         }
   1480     }
   1481 
   1482     for (int32_t i=0; i<CACHE_LOAD; ++i) {
   1483         for (int32_t j=0; j<UPRV_LENGTHOF(gCacheLocales); ++j) {
   1484             threads[i][j]->join();
   1485         }
   1486     }
   1487     // Because of cache eviction, we can't assert exactly how many
   1488     // distinct objects get created over the course of this run.
   1489     // However we know that at least 8 objects get created because that
   1490     // is how many distinct languages we have in our test.
   1491     if (gObjectsCreated < 8) {
   1492         errln("%s:%d Too few objects created.", __FILE__, __LINE__);
   1493     }
   1494     // We know that each thread cannot create more than 2 objects in
   1495     // the cache, and there are UPRV_LENGTHOF(gCacheLocales) pairs of
   1496     // objects fetched from the cache. If the threads run in series because
   1497     // of eviction, at worst case each thread creates two objects.
   1498     if (gObjectsCreated > 2 * CACHE_LOAD * UPRV_LENGTHOF(gCacheLocales)) {
   1499         errln("%s:%d Too many objects created, got %d, expected %d", __FILE__, __LINE__, gObjectsCreated, 2 * CACHE_LOAD * UPRV_LENGTHOF(gCacheLocales));
   1500 
   1501     }
   1502 
   1503     assertEquals("unused values", 2, cache.unusedCount());
   1504 
   1505     // clean up threads
   1506     for (int32_t i=0; i<CACHE_LOAD; ++i) {
   1507         for (int32_t j=0; j<UPRV_LENGTHOF(gCacheLocales); ++j) {
   1508             delete threads[i][j];
   1509         }
   1510     }
   1511 }
   1512 
   1513 #if !UCONFIG_NO_TRANSLITERATION
   1514 //
   1515 //  BreakTransliterator Threading Test
   1516 //     This is a test for bug #11603. Test verified to fail prior to fix.
   1517 //
   1518 
   1519 static const Transliterator *gSharedTransliterator;
   1520 static const UnicodeString *gTranslitInput;
   1521 static const UnicodeString *gTranslitExpected;
   1522 
   1523 class BreakTranslitThread: public SimpleThread {
   1524   public:
   1525     BreakTranslitThread() {};
   1526     ~BreakTranslitThread() {};
   1527     void run();
   1528 };
   1529 
   1530 void BreakTranslitThread::run() {
   1531     for (int i=0; i<10; i++) {
   1532         icu::UnicodeString s(*gTranslitInput);
   1533         gSharedTransliterator->transliterate(s);
   1534         if (*gTranslitExpected != s) {
   1535             IntlTest::gTest->errln("%s:%d Transliteration threading failure.", __FILE__, __LINE__);
   1536             break;
   1537         }
   1538     }
   1539 }
   1540 
   1541 void MultithreadTest::TestBreakTranslit() {
   1542     UErrorCode status = U_ZERO_ERROR;
   1543     UnicodeString input(
   1544         "\\u0E42\\u0E14\\u0E22\\u0E1E\\u0E37\\u0E49\\u0E19\\u0E10\\u0E32\\u0E19\\u0E41\\u0E25\\u0E49\\u0E27,");
   1545     input = input.unescape();
   1546     gTranslitInput = &input;
   1547 
   1548     gSharedTransliterator = Transliterator::createInstance(
   1549         UNICODE_STRING_SIMPLE("Any-Latin; Lower; NFD; [:Diacritic:]Remove; NFC; Latin-ASCII;"), UTRANS_FORWARD, status);
   1550     if (!gSharedTransliterator) {
   1551          return;
   1552      }
   1553     TSMTHREAD_ASSERT_SUCCESS(status);
   1554 
   1555     UnicodeString expected(*gTranslitInput);
   1556     gSharedTransliterator->transliterate(expected);
   1557     gTranslitExpected = &expected;
   1558 
   1559     BreakTranslitThread threads[4];
   1560     for (int i=0; i<UPRV_LENGTHOF(threads); ++i) {
   1561         threads[i].start();
   1562     }
   1563     for (int i=0; i<UPRV_LENGTHOF(threads); ++i) {
   1564         threads[i].join();
   1565     }
   1566 
   1567     delete gSharedTransliterator;
   1568     gTranslitInput = NULL;
   1569     gTranslitExpected = NULL;
   1570 }
   1571 
   1572 #endif /* !UCONFIG_NO_TRANSLITERATION */
   1573