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