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