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