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