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