• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /********************************************************************
2  * COPYRIGHT:
3  * Copyright (c) 1999-2012, 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 
31 
32 #if U_PLATFORM_USES_ONLY_WIN32_API
33     /* Prefer native Windows APIs even if POSIX is implemented (i.e., on Cygwin). */
34 #   undef POSIX
35 #elif U_PLATFORM_IMPLEMENTS_POSIX
36 #   define POSIX
37 #else
38 #   undef POSIX
39 #endif
40 
41 
42 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
43 /* Needed by z/OS to get usleep */
44 #if U_PLATFORM == U_PF_OS390
45 #define __DOT1 1
46 #define __UU
47 #ifndef _XPG4_2
48 #define _XPG4_2
49 #endif
50 #include <unistd.h>
51 #endif
52 #if defined(POSIX)
53 
54 #define HAVE_IMP
55 
56 #if (ICU_USE_THREADS == 1)
57 #include <pthread.h>
58 #endif
59 
60 #if defined(__hpux) && defined(HPUX_CMA)
61 # if defined(read)  // read being defined as cma_read causes trouble with iostream::read
62 #  undef read
63 # endif
64 #endif
65 
66 /* Define __EXTENSIONS__ for Solaris and old friends in strict mode. */
67 #ifndef __EXTENSIONS__
68 #define __EXTENSIONS__
69 #endif
70 
71 #if U_PLATFORM == U_PF_OS390
72 #include <sys/types.h>
73 #endif
74 
75 #if U_PLATFORM != U_PF_OS390
76 #include <signal.h>
77 #endif
78 
79 /* Define _XPG4_2 for Solaris and friends. */
80 #ifndef _XPG4_2
81 #define _XPG4_2
82 #endif
83 
84 /* Define __USE_XOPEN_EXTENDED for Linux and glibc. */
85 #ifndef __USE_XOPEN_EXTENDED
86 #define __USE_XOPEN_EXTENDED
87 #endif
88 
89 /* Define _INCLUDE_XOPEN_SOURCE_EXTENDED for HP/UX (11?). */
90 #ifndef _INCLUDE_XOPEN_SOURCE_EXTENDED
91 #define _INCLUDE_XOPEN_SOURCE_EXTENDED
92 #endif
93 
94 #include <unistd.h>
95 
96 #endif
97 /* HPUX */
98 #ifdef sleep
99 #undef sleep
100 #endif
101 
102 #define TSMTHREAD_FAIL(msg) errln("%s at file %s, line %d", msg, __FILE__, __LINE__)
103 #define TSMTHREAD_ASSERT(expr) {if (!(expr)) {TSMTHREAD_FAIL("Fail");}}
104 
MultithreadTest()105 MultithreadTest::MultithreadTest()
106 {
107 }
108 
~MultithreadTest()109 MultithreadTest::~MultithreadTest()
110 {
111 }
112 
113 
114 
115 #if (ICU_USE_THREADS==0)
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)116 void MultithreadTest::runIndexedTest( int32_t index, UBool exec,
117                 const char* &name, char* /*par*/ ) {
118   if (exec) logln("TestSuite MultithreadTest: ");
119 
120   if(index == 0)
121       name = "NO_THREADED_TESTS";
122   else
123       name = "";
124 
125   if(exec) { logln("MultithreadTest - test DISABLED.  ICU_USE_THREADS set to 0, check your configuration if this is a problem..");
126   }
127 }
128 #else
129 
130 #include <stdio.h>
131 #include <string.h>
132 #include <ctype.h>    // tolower, toupper
133 
134 #include "unicode/putil.h"
135 
136 // for mthreadtest
137 #include "unicode/numfmt.h"
138 #include "unicode/choicfmt.h"
139 #include "unicode/msgfmt.h"
140 #include "unicode/locid.h"
141 #include "unicode/coll.h"
142 #include "unicode/calendar.h"
143 #include "ucaconf.h"
144 
errorFunc()145 void SimpleThread::errorFunc() {
146     // *(char *)0 = 3;            // Force entry into a debugger via a crash;
147 }
148 
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)149 void MultithreadTest::runIndexedTest( int32_t index, UBool exec,
150                 const char* &name, char* /*par*/ ) {
151     if (exec)
152         logln("TestSuite MultithreadTest: ");
153     switch (index) {
154     case 0:
155         name = "TestThreads";
156         if (exec)
157             TestThreads();
158         break;
159 
160     case 1:
161         name = "TestMutex";
162         if (exec)
163             TestMutex();
164         break;
165 
166     case 2:
167         name = "TestThreadedIntl";
168 #if !UCONFIG_NO_FORMATTING
169         if (exec) {
170             TestThreadedIntl();
171         }
172 #endif
173         break;
174 
175     case 3:
176       name = "TestCollators";
177 #if !UCONFIG_NO_COLLATION
178       if (exec) {
179             TestCollators();
180       }
181 #endif /* #if !UCONFIG_NO_COLLATION */
182       break;
183 
184     case 4:
185         name = "TestString";
186         if (exec) {
187             TestString();
188         }
189         break;
190 
191 	case 5:
192         name = "TestArabicShapingThreads";
193         if (exec) {
194             TestArabicShapingThreads();
195         }
196         break;
197 
198 
199     default:
200         name = "";
201         break; //needed to end loop
202     }
203 }
204 
205 
206 //-----------------------------------------------------------------------------------
207 //
208 //   TestThreads -- see if threads really work at all.
209 //
210 //   Set up N threads pointing at N chars. When they are started, they will
211 //   each sleep 1 second and then set their chars. At the end we make sure they
212 //   are all set.
213 //
214 //-----------------------------------------------------------------------------------
215 #define THREADTEST_NRTHREADS 8
216 #define ARABICSHAPE_THREADTEST 30
217 
218 class TestThreadsThread : public SimpleThread
219 {
220 public:
TestThreadsThread(char * whatToChange)221     TestThreadsThread(char* whatToChange) { fWhatToChange = whatToChange; }
run()222     virtual void run() { SimpleThread::sleep(1000);
223                          Mutex m;
224                          *fWhatToChange = '*';
225     }
226 private:
227     char *fWhatToChange;
228 };
229 //-----------------------------------------------------------------------------------
230 //
231 //   TestArabicShapeThreads -- see if calls to u_shapeArabic in many threads works successfully
232 //
233 //   Set up N threads pointing at N chars. When they are started, they will make calls to doTailTest which tests
234 //   u_shapeArabic, if the calls are successful it will the set * chars.
235 //   At the end we make sure all threads managed to run u_shapeArabic successfully.
236 //   This is a unit test for ticket 9473
237 //
238 //-----------------------------------------------------------------------------------
239 class TestArabicShapeThreads : public SimpleThread
240 {
241 public:
TestArabicShapeThreads(char * whatToChange)242     TestArabicShapeThreads(char* whatToChange) { fWhatToChange = whatToChange;}
run()243     virtual void run() {
244 	    if(doTailTest()==TRUE)
245 			*fWhatToChange = '*';
246     }
247 private:
248     char *fWhatToChange;
249 
doTailTest(void)250 	UBool doTailTest(void) {
251   static const UChar src[] = { 0x0020, 0x0633, 0 };
252   static const UChar dst_old[] = { 0xFEB1, 0x200B,0 };
253   static const UChar dst_new[] = { 0xFEB1, 0xFE73,0 };
254   UChar dst[3] = { 0x0000, 0x0000,0 };
255   int32_t length;
256   UErrorCode status;
257   IntlTest inteltst =  IntlTest();
258 
259   status = U_ZERO_ERROR;
260   length = u_shapeArabic(src, -1, dst, LENGTHOF(dst),
261                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_SEEN_TWOCELL_NEAR, &status);
262   if(U_FAILURE(status)) {
263 	   inteltst.errln("Fail: status %s\n", u_errorName(status));
264 	return FALSE;
265   } else if(length!=2) {
266     inteltst.errln("Fail: len %d expected 3\n", length);
267 	return FALSE;
268   } else if(u_strncmp(dst,dst_old,LENGTHOF(dst))) {
269     inteltst.errln("Fail: got U+%04X U+%04X expected U+%04X U+%04X\n",
270             dst[0],dst[1],dst_old[0],dst_old[1]);
271 	return FALSE;
272   }
273 
274 
275   //"Trying new tail
276   status = U_ZERO_ERROR;
277   length = u_shapeArabic(src, -1, dst, LENGTHOF(dst),
278                          U_SHAPE_LETTERS_SHAPE|U_SHAPE_SEEN_TWOCELL_NEAR|U_SHAPE_TAIL_NEW_UNICODE, &status);
279   if(U_FAILURE(status)) {
280     inteltst.errln("Fail: status %s\n", u_errorName(status));
281 	return FALSE;
282   } else if(length!=2) {
283     inteltst.errln("Fail: len %d expected 3\n", length);
284 	return FALSE;
285   } else if(u_strncmp(dst,dst_new,LENGTHOF(dst))) {
286     inteltst.errln("Fail: got U+%04X U+%04X expected U+%04X U+%04X\n",
287             dst[0],dst[1],dst_new[0],dst_new[1]);
288 	return FALSE;
289   }
290 
291 
292   return TRUE;
293 
294 }
295 
296 
297 };
298 
TestThreads()299 void MultithreadTest::TestThreads()
300 {
301     char threadTestChars[THREADTEST_NRTHREADS + 1];
302     SimpleThread *threads[THREADTEST_NRTHREADS];
303     int32_t numThreadsStarted = 0;
304 
305     int32_t i;
306     for(i=0;i<THREADTEST_NRTHREADS;i++)
307     {
308         threadTestChars[i] = ' ';
309         threads[i] = new TestThreadsThread(&threadTestChars[i]);
310     }
311     threadTestChars[THREADTEST_NRTHREADS] = '\0';
312 
313     logln("->" + UnicodeString(threadTestChars) + "<- Firing off threads.. ");
314     for(i=0;i<THREADTEST_NRTHREADS;i++)
315     {
316         if (threads[i]->start() != 0) {
317             errln("Error starting thread %d", i);
318         }
319         else {
320             numThreadsStarted++;
321         }
322         SimpleThread::sleep(100);
323         logln(" Subthread started.");
324     }
325 
326     logln("Waiting for threads to be set..");
327     if (numThreadsStarted == 0) {
328         errln("No threads could be started for testing!");
329         return;
330     }
331 
332     int32_t patience = 40; // seconds to wait
333 
334     while(patience--)
335     {
336         int32_t count = 0;
337         umtx_lock(NULL);
338         for(i=0;i<THREADTEST_NRTHREADS;i++)
339         {
340             if(threadTestChars[i] == '*')
341             {
342                 count++;
343             }
344         }
345         umtx_unlock(NULL);
346 
347         if(count == THREADTEST_NRTHREADS)
348         {
349             logln("->" + UnicodeString(threadTestChars) + "<- Got all threads! cya");
350             for(i=0;i<THREADTEST_NRTHREADS;i++)
351             {
352                 delete threads[i];
353             }
354             return;
355         }
356 
357         logln("->" + UnicodeString(threadTestChars) + "<- Waiting..");
358         SimpleThread::sleep(500);
359     }
360 
361     errln("->" + UnicodeString(threadTestChars) + "<- PATIENCE EXCEEDED!! Still missing some.");
362     for(i=0;i<THREADTEST_NRTHREADS;i++)
363     {
364         delete threads[i];
365     }
366 }
367 
368 
TestArabicShapingThreads()369 void MultithreadTest::TestArabicShapingThreads()
370 {
371     char threadTestChars[ARABICSHAPE_THREADTEST + 1];
372     SimpleThread *threads[ARABICSHAPE_THREADTEST];
373     int32_t numThreadsStarted = 0;
374 
375     int32_t i;
376 
377     for(i=0;i<ARABICSHAPE_THREADTEST;i++)
378     {
379         threadTestChars[i] = ' ';
380         threads[i] = new TestArabicShapeThreads(&threadTestChars[i]);
381     }
382     threadTestChars[ARABICSHAPE_THREADTEST] = '\0';
383 
384     logln("-> do TestArabicShapingThreads <- Firing off threads.. ");
385     for(i=0;i<ARABICSHAPE_THREADTEST;i++)
386     {
387         if (threads[i]->start() != 0) {
388             errln("Error starting thread %d", i);
389         }
390         else {
391             numThreadsStarted++;
392         }
393         //SimpleThread::sleep(100);
394         logln(" Subthread started.");
395     }
396 
397     logln("Waiting for threads to be set..");
398     if (numThreadsStarted == 0) {
399         errln("No threads could be started for testing!");
400         return;
401     }
402 
403     int32_t patience = 100; // seconds to wait
404 
405     while(patience--)
406     {
407         int32_t count = 0;
408         umtx_lock(NULL);
409         for(i=0;i<ARABICSHAPE_THREADTEST;i++)
410         {
411             if(threadTestChars[i] == '*')
412             {
413                 count++;
414             }
415         }
416         umtx_unlock(NULL);
417 
418         if(count == ARABICSHAPE_THREADTEST)
419         {
420             logln("->TestArabicShapingThreads <- Got all threads! cya");
421             for(i=0;i<ARABICSHAPE_THREADTEST;i++)
422             {
423                 delete threads[i];
424             }
425             return;
426         }
427 
428         logln("-> TestArabicShapingThreads <- Waiting..");
429         SimpleThread::sleep(500);
430     }
431 
432     errln("-> TestArabicShapingThreads <- PATIENCE EXCEEDED!! Still missing some.");
433     for(i=0;i<ARABICSHAPE_THREADTEST;i++)
434     {
435         delete threads[i];
436     }
437 
438 }
439 
440 
441 //-----------------------------------------------------------------------
442 //
443 //  TestMutex  - a simple (non-stress) test to verify that ICU mutexes
444 //               are actually mutexing.  Does not test the use of
445 //               mutexes within ICU services, but rather that the
446 //               platform's mutex support is at least superficially there.
447 //
448 //----------------------------------------------------------------------
449 static UMutex    gTestMutexA = U_MUTEX_INITIALIZER;
450 static UMutex    gTestMutexB = U_MUTEX_INITIALIZER;
451 
452 static int     gThreadsStarted = 0;
453 static int     gThreadsInMiddle = 0;
454 static int     gThreadsDone = 0;
455 
456 static const int TESTMUTEX_THREAD_COUNT = 4;
457 
safeIncr(int & var,int amt)458 static int safeIncr(int &var, int amt) {
459     // Thread safe (using global mutex) increment of a variable.
460     // Return the updated value.
461     // Can also be used as a safe load of a variable by incrementing it by 0.
462     Mutex m;
463     var += amt;
464     return var;
465 }
466 
467 class TestMutexThread : public SimpleThread
468 {
469 public:
run()470     virtual void run()
471     {
472         // This is the code that each of the spawned threads runs.
473         // All of the spawned threads bunch up together at each of the two mutexes
474         // because the main holds the mutexes until they do.
475         //
476         safeIncr(gThreadsStarted, 1);
477         umtx_lock(&gTestMutexA);
478         umtx_unlock(&gTestMutexA);
479         safeIncr(gThreadsInMiddle, 1);
480         umtx_lock(&gTestMutexB);
481         umtx_unlock(&gTestMutexB);
482         safeIncr(gThreadsDone, 1);
483     }
484 };
485 
TestMutex()486 void MultithreadTest::TestMutex()
487 {
488     // Start up the test threads.  They should all pile up waiting on
489     // gTestMutexA, which we (the main thread) hold until the test threads
490     //   all get there.
491     gThreadsStarted = 0;
492     gThreadsInMiddle = 0;
493     gThreadsDone = 0;
494     umtx_lock(&gTestMutexA);
495     TestMutexThread  *threads[TESTMUTEX_THREAD_COUNT];
496     int i;
497     int32_t numThreadsStarted = 0;
498     for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) {
499         threads[i] = new TestMutexThread;
500         if (threads[i]->start() != 0) {
501             errln("Error starting thread %d", i);
502         }
503         else {
504             numThreadsStarted++;
505         }
506     }
507     if (numThreadsStarted == 0) {
508         errln("No threads could be started for testing!");
509         return;
510     }
511 
512     int patience = 0;
513     while (safeIncr(gThreadsStarted, 0) != TESTMUTEX_THREAD_COUNT) {
514         if (patience++ > 24) {
515             TSMTHREAD_FAIL("Patience Exceeded");
516             return;
517         }
518         SimpleThread::sleep(500);
519     }
520     // None of the test threads should have advanced past the first mutex.
521     TSMTHREAD_ASSERT(gThreadsInMiddle==0);
522     TSMTHREAD_ASSERT(gThreadsDone==0);
523 
524     //  All of the test threads have made it to the first mutex.
525     //  We (the main thread) now let them advance to the second mutex,
526     //   where they should all pile up again.
527     umtx_lock(&gTestMutexB);
528     umtx_unlock(&gTestMutexA);
529 
530     patience = 0;
531     while (safeIncr(gThreadsInMiddle, 0) != TESTMUTEX_THREAD_COUNT) {
532         if (patience++ > 24) {
533             TSMTHREAD_FAIL("Patience Exceeded");
534             return;
535         }
536         SimpleThread::sleep(500);
537     }
538     TSMTHREAD_ASSERT(gThreadsDone==0);
539 
540     //  All test threads made it to the second mutex.
541     //   Now let them proceed from there.  They will all terminate.
542     umtx_unlock(&gTestMutexB);
543     patience = 0;
544     while (safeIncr(gThreadsDone, 0) != TESTMUTEX_THREAD_COUNT) {
545         if (patience++ > 24) {
546             TSMTHREAD_FAIL("Patience Exceeded");
547             return;
548         }
549         SimpleThread::sleep(500);
550     }
551 
552     // All threads made it by both mutexes.
553 
554     for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) {
555         delete threads[i];
556     }
557 
558 }
559 
560 
561 //-------------------------------------------------------------------------------------------
562 //
563 // class ThreadWithStatus - a thread that we can check the status and error condition of
564 //
565 //-------------------------------------------------------------------------------------------
566 class ThreadWithStatus : public SimpleThread
567 {
568 public:
getError()569     UBool  getError() { return (fErrors > 0); }
getError(UnicodeString & fillinError)570     UBool  getError(UnicodeString& fillinError) { fillinError = fErrorString; return (fErrors > 0); }
~ThreadWithStatus()571     virtual ~ThreadWithStatus(){}
572 protected:
ThreadWithStatus()573     ThreadWithStatus() :  fErrors(0) {}
error(const UnicodeString & error)574     void error(const UnicodeString &error) {
575         fErrors++; fErrorString = error;
576         SimpleThread::errorFunc();
577     }
error()578     void error() { error("An error occured."); }
579 private:
580     int32_t fErrors;
581     UnicodeString fErrorString;
582 };
583 
584 
585 
586 //-------------------------------------------------------------------------------------------
587 //
588 //   TestMultithreadedIntl.  Test ICU Formatting n a multi-threaded environment
589 //
590 //-------------------------------------------------------------------------------------------
591 
592 
593 // * Show exactly where the string's differences lie.
showDifference(const UnicodeString & expected,const UnicodeString & result)594 UnicodeString showDifference(const UnicodeString& expected, const UnicodeString& result)
595 {
596     UnicodeString res;
597     res = expected + "<Expected\n";
598     if(expected.length() != result.length())
599         res += " [ Different lengths ] \n";
600     else
601     {
602         for(int32_t i=0;i<expected.length();i++)
603         {
604             if(expected[i] == result[i])
605             {
606                 res += " ";
607             }
608             else
609             {
610                 res += "|";
611             }
612         }
613         res += "<Differences";
614         res += "\n";
615     }
616     res += result + "<Result\n";
617 
618     return res;
619 }
620 
621 
622 
623 
624 //-------------------------------------------------------------------------------------------
625 //
626 //   FormatThreadTest - a thread that tests performing a number of numberformats.
627 //
628 //-------------------------------------------------------------------------------------------
629 
630 const int kFormatThreadIterations = 20;  // # of iterations per thread
631 const int kFormatThreadThreads    = 10;  // # of threads to spawn
632 const int kFormatThreadPatience   = 60;  // time in seconds to wait for all threads
633 
634 #if !UCONFIG_NO_FORMATTING
635 
636 
637 
638 struct FormatThreadTestData
639 {
640     double number;
641     UnicodeString string;
FormatThreadTestDataFormatThreadTestData642     FormatThreadTestData(double a, const UnicodeString& b) : number(a),string(b) {}
643 } ;
644 
645 
646 // "Someone from {2} is receiving a #{0} error - {1}. Their telephone call is costing {3 number,currency}."
647 
formatErrorMessage(UErrorCode & realStatus,const UnicodeString & pattern,const Locale & theLocale,UErrorCode inStatus0,const Locale & inCountry2,double currency3,UnicodeString & result)648 void formatErrorMessage(UErrorCode &realStatus, const UnicodeString& pattern, const Locale& theLocale,
649                      UErrorCode inStatus0, /* statusString 1 */ const Locale &inCountry2, double currency3, // these numbers are the message arguments.
650                      UnicodeString &result)
651 {
652     if(U_FAILURE(realStatus))
653         return; // you messed up
654 
655     UnicodeString errString1(u_errorName(inStatus0));
656 
657     UnicodeString countryName2;
658     inCountry2.getDisplayCountry(theLocale,countryName2);
659 
660     Formattable myArgs[] = {
661         Formattable((int32_t)inStatus0),   // inStatus0      {0}
662         Formattable(errString1), // statusString1 {1}
663         Formattable(countryName2),  // inCountry2 {2}
664         Formattable(currency3)// currency3  {3,number,currency}
665     };
666 
667     MessageFormat *fmt = new MessageFormat("MessageFormat's API is broken!!!!!!!!!!!",realStatus);
668     fmt->setLocale(theLocale);
669     fmt->applyPattern(pattern, realStatus);
670 
671     if (U_FAILURE(realStatus)) {
672         delete fmt;
673         return;
674     }
675 
676     FieldPosition ignore = 0;
677     fmt->format(myArgs,4,result,ignore,realStatus);
678 
679     delete fmt;
680 }
681 
682 
isAcceptable(void *,const char *,const char *,const UDataInfo *)683 UBool U_CALLCONV isAcceptable(void *, const char *, const char *, const UDataInfo *) {
684     return TRUE;
685 }
686 
687 //static UMTX debugMutex = NULL;
688 //static UMTX gDebugMutex;
689 
690 
691 class FormatThreadTest : public ThreadWithStatus
692 {
693 public:
694     int     fNum;
695     int     fTraceInfo;
696 
FormatThreadTest()697     FormatThreadTest() // constructor is NOT multithread safe.
698         : ThreadWithStatus(),
699         fNum(0),
700         fTraceInfo(0),
701         fOffset(0)
702         // the locale to use
703     {
704         static int32_t fgOffset = 0;
705         fgOffset += 3;
706         fOffset = fgOffset;
707     }
708 
709 
run()710     virtual void run()
711     {
712         fTraceInfo                     = 1;
713         LocalPointer<NumberFormat> percentFormatter;
714         UErrorCode status = U_ZERO_ERROR;
715 
716 #if 0
717         // debugging code,
718         for (int i=0; i<4000; i++) {
719             status = U_ZERO_ERROR;
720             UDataMemory *data1 = udata_openChoice(0, "res", "en_US", isAcceptable, 0, &status);
721             UDataMemory *data2 = udata_openChoice(0, "res", "fr", isAcceptable, 0, &status);
722             udata_close(data1);
723             udata_close(data2);
724             if (U_FAILURE(status)) {
725                 error("udata_openChoice failed.\n");
726                 break;
727             }
728         }
729         return;
730 #endif
731 
732 #if 0
733         // debugging code,
734         int m;
735         for (m=0; m<4000; m++) {
736             status         = U_ZERO_ERROR;
737             UResourceBundle *res   = NULL;
738             const char *localeName = NULL;
739 
740             Locale  loc = Locale::getEnglish();
741 
742             localeName = loc.getName();
743             // localeName = "en";
744 
745             // ResourceBundle bund = ResourceBundle(0, loc, status);
746             //umtx_lock(&gDebugMutex);
747             res = ures_open(NULL, localeName, &status);
748             //umtx_unlock(&gDebugMutex);
749 
750             //umtx_lock(&gDebugMutex);
751             ures_close(res);
752             //umtx_unlock(&gDebugMutex);
753 
754             if (U_FAILURE(status)) {
755                 error("Resource bundle construction failed.\n");
756                 break;
757             }
758         }
759         return;
760 #endif
761 
762         // Keep this data here to avoid static initialization.
763         FormatThreadTestData kNumberFormatTestData[] =
764         {
765             FormatThreadTestData((double)5.0, UnicodeString("5", "")),
766                 FormatThreadTestData( 6.0, UnicodeString("6", "")),
767                 FormatThreadTestData( 20.0, UnicodeString("20", "")),
768                 FormatThreadTestData( 8.0, UnicodeString("8", "")),
769                 FormatThreadTestData( 8.3, UnicodeString("8.3", "")),
770                 FormatThreadTestData( 12345, UnicodeString("12,345", "")),
771                 FormatThreadTestData( 81890.23, UnicodeString("81,890.23", "")),
772         };
773         int32_t kNumberFormatTestDataLength = (int32_t)(sizeof(kNumberFormatTestData) /
774                                                         sizeof(kNumberFormatTestData[0]));
775 
776         // Keep this data here to avoid static initialization.
777         FormatThreadTestData kPercentFormatTestData[] =
778         {
779             FormatThreadTestData((double)5.0, CharsToUnicodeString("500\\u00a0%")),
780                 FormatThreadTestData( 1.0, CharsToUnicodeString("100\\u00a0%")),
781                 FormatThreadTestData( 0.26, CharsToUnicodeString("26\\u00a0%")),
782                 FormatThreadTestData(
783                    16384.99, CharsToUnicodeString("1\\u00a0638\\u00a0499\\u00a0%")), // U+00a0 = NBSP
784                 FormatThreadTestData(
785                     81890.23, CharsToUnicodeString("8\\u00a0189\\u00a0023\\u00a0%")),
786         };
787         int32_t kPercentFormatTestDataLength =
788                 (int32_t)(sizeof(kPercentFormatTestData) / sizeof(kPercentFormatTestData[0]));
789         int32_t iteration;
790 
791         status = U_ZERO_ERROR;
792         LocalPointer<NumberFormat> formatter(NumberFormat::createInstance(Locale::getEnglish(),status));
793         if(U_FAILURE(status)) {
794             error("Error on NumberFormat::createInstance().");
795             goto cleanupAndReturn;
796         }
797 
798         percentFormatter.adoptInstead(NumberFormat::createPercentInstance(Locale::getFrench(),status));
799         if(U_FAILURE(status))             {
800             error("Error on NumberFormat::createPercentInstance().");
801             goto cleanupAndReturn;
802         }
803 
804         for(iteration = 0;!getError() && iteration<kFormatThreadIterations;iteration++)
805         {
806 
807             int32_t whichLine = (iteration + fOffset)%kNumberFormatTestDataLength;
808 
809             UnicodeString  output;
810 
811             formatter->format(kNumberFormatTestData[whichLine].number, output);
812 
813             if(0 != output.compare(kNumberFormatTestData[whichLine].string)) {
814                 error("format().. expected " + kNumberFormatTestData[whichLine].string
815                         + " got " + output);
816                 goto cleanupAndReturn;
817             }
818 
819             // Now check percent.
820             output.remove();
821             whichLine = (iteration + fOffset)%kPercentFormatTestDataLength;
822 
823             percentFormatter->format(kPercentFormatTestData[whichLine].number, output);
824             if(0 != output.compare(kPercentFormatTestData[whichLine].string))
825             {
826                 error("percent format().. \n" +
827                         showDifference(kPercentFormatTestData[whichLine].string,output));
828                 goto cleanupAndReturn;
829             }
830 
831             // Test message error
832             const int       kNumberOfMessageTests = 3;
833             UErrorCode      statusToCheck;
834             UnicodeString   patternToCheck;
835             Locale          messageLocale;
836             Locale          countryToCheck;
837             double          currencyToCheck;
838 
839             UnicodeString   expected;
840 
841             // load the cases.
842             switch((iteration+fOffset) % kNumberOfMessageTests)
843             {
844             default:
845             case 0:
846                 statusToCheck=                      U_FILE_ACCESS_ERROR;
847                 patternToCheck=        "0:Someone from {2} is receiving a #{0}"
848                                        " error - {1}. Their telephone call is costing "
849                                        "{3,number,currency}."; // number,currency
850                 messageLocale=                      Locale("en","US");
851                 countryToCheck=                     Locale("","HR");
852                 currencyToCheck=                    8192.77;
853                 expected=  "0:Someone from Croatia is receiving a #4 error - "
854                             "U_FILE_ACCESS_ERROR. Their telephone call is costing $8,192.77.";
855                 break;
856             case 1:
857                 statusToCheck=                      U_INDEX_OUTOFBOUNDS_ERROR;
858                 patternToCheck=                     "1:A customer in {2} is receiving a #{0} error - {1}. Their telephone call is costing {3,number,currency}."; // number,currency
859                 messageLocale=                      Locale("de","DE@currency=DEM");
860                 countryToCheck=                     Locale("","BF");
861                 currencyToCheck=                    2.32;
862                 expected=                           CharsToUnicodeString(
863                                                     "1:A customer in Burkina Faso is receiving a #8 error - U_INDEX_OUTOFBOUNDS_ERROR. Their telephone call is costing 2,32\\u00A0DEM.");
864                 break;
865             case 2:
866                 statusToCheck=                      U_MEMORY_ALLOCATION_ERROR;
867                 patternToCheck=   "2:user in {2} is receiving a #{0} error - {1}. "
868                                   "They insist they just spent {3,number,currency} "
869                                   "on memory."; // number,currency
870                 messageLocale=                      Locale("de","AT@currency=ATS"); // Austrian German
871                 countryToCheck=                     Locale("","US"); // hmm
872                 currencyToCheck=                    40193.12;
873                 expected=       CharsToUnicodeString(
874                             "2:user in Vereinigte Staaten is receiving a #7 error"
875                             " - U_MEMORY_ALLOCATION_ERROR. They insist they just spent"
876                             " \\u00f6S\\u00A040.193,12 on memory.");
877                 break;
878             }
879 
880             UnicodeString result;
881             UErrorCode status = U_ZERO_ERROR;
882             formatErrorMessage(status,patternToCheck,messageLocale,statusToCheck,
883                                 countryToCheck,currencyToCheck,result);
884             if(U_FAILURE(status))
885             {
886                 UnicodeString tmp(u_errorName(status));
887                 error("Failure on message format, pattern=" + patternToCheck +
888                         ", error = " + tmp);
889                 goto cleanupAndReturn;
890             }
891 
892             if(result != expected)
893             {
894                 error("PatternFormat: \n" + showDifference(expected,result));
895                 goto cleanupAndReturn;
896             }
897         }   /*  end of for loop */
898 
899 cleanupAndReturn:
900         //  while (fNum == 4) {SimpleThread::sleep(10000);}   // Force a failure by preventing thread from finishing
901         fTraceInfo = 2;
902     }
903 
904 private:
905     int32_t fOffset; // where we are testing from.
906 };
907 
908 // ** The actual test function.
909 
TestThreadedIntl()910 void MultithreadTest::TestThreadedIntl()
911 {
912     int i;
913     UnicodeString theErr;
914     UBool   haveDisplayedInfo[kFormatThreadThreads];
915     static const int32_t PATIENCE_SECONDS = 45;
916 
917     //
918     //  Create and start the test threads
919     //
920     logln("Spawning: %d threads * %d iterations each.",
921                 kFormatThreadThreads, kFormatThreadIterations);
922     LocalArray<FormatThreadTest> tests(new FormatThreadTest[kFormatThreadThreads]);
923     for(int32_t j = 0; j < kFormatThreadThreads; j++) {
924         tests[j].fNum = j;
925         int32_t threadStatus = tests[j].start();
926         if (threadStatus != 0) {
927             errln("System Error %d starting thread number %d.", threadStatus, j);
928             SimpleThread::errorFunc();
929             return;
930         }
931         haveDisplayedInfo[j] = FALSE;
932     }
933 
934 
935     // Spin, waiting for the test threads to finish.
936     UBool   stillRunning;
937     UDate startTime, endTime;
938     startTime = Calendar::getNow();
939     do {
940         /*  Spin until the test threads  complete. */
941         stillRunning = FALSE;
942         endTime = Calendar::getNow();
943         if (((int32_t)(endTime - startTime)/U_MILLIS_PER_SECOND) > PATIENCE_SECONDS) {
944             errln("Patience exceeded. Test is taking too long.");
945             return;
946         }
947         /*
948          The following sleep must be here because the *BSD operating systems
949          have a brain dead thread scheduler. They starve the child threads from
950          CPU time.
951         */
952         SimpleThread::sleep(1); // yield
953         for(i=0;i<kFormatThreadThreads;i++) {
954             if (tests[i].isRunning()) {
955                 stillRunning = TRUE;
956             } else if (haveDisplayedInfo[i] == FALSE) {
957                 logln("Thread # %d is complete..", i);
958                 if(tests[i].getError(theErr)) {
959                     dataerrln(UnicodeString("#") + i + ": " + theErr);
960                     SimpleThread::errorFunc();
961                 }
962                 haveDisplayedInfo[i] = TRUE;
963             }
964         }
965     } while (stillRunning);
966 
967     //
968     //  All threads have finished.
969     //
970 }
971 #endif /* #if !UCONFIG_NO_FORMATTING */
972 
973 
974 
975 
976 
977 //-------------------------------------------------------------------------------------------
978 //
979 // Collation threading test
980 //
981 //-------------------------------------------------------------------------------------------
982 #if !UCONFIG_NO_COLLATION
983 
984 #define kCollatorThreadThreads   10  // # of threads to spawn
985 #define kCollatorThreadPatience kCollatorThreadThreads*30
986 
987 struct Line {
988     UChar buff[25];
989     int32_t buflen;
990 } ;
991 
992 static UBool
skipLineBecauseOfBug(const UChar * s,int32_t length)993 skipLineBecauseOfBug(const UChar *s, int32_t length) {
994     // TODO: Fix ICU ticket #8052
995     if(length >= 3 &&
996             (s[0] == 0xfb2 || s[0] == 0xfb3) &&
997             s[1] == 0x334 &&
998             (s[2] == 0xf73 || s[2] == 0xf75 || s[2] == 0xf81)) {
999         return TRUE;
1000     }
1001     return FALSE;
1002 }
1003 
1004 static UCollationResult
normalizeResult(int32_t result)1005 normalizeResult(int32_t result) {
1006     return result<0 ? UCOL_LESS : result==0 ? UCOL_EQUAL : UCOL_GREATER;
1007 }
1008 
1009 class CollatorThreadTest : public ThreadWithStatus
1010 {
1011 private:
1012     const Collator *coll;
1013     const Line *lines;
1014     int32_t noLines;
1015     UBool isAtLeastUCA62;
1016 public:
CollatorThreadTest()1017     CollatorThreadTest()  : ThreadWithStatus(),
1018         coll(NULL),
1019         lines(NULL),
1020         noLines(0),
1021         isAtLeastUCA62(TRUE)
1022     {
1023     };
setCollator(Collator * c,Line * l,int32_t nl,UBool atLeastUCA62)1024     void setCollator(Collator *c, Line *l, int32_t nl, UBool atLeastUCA62)
1025     {
1026         coll = c;
1027         lines = l;
1028         noLines = nl;
1029         isAtLeastUCA62 = atLeastUCA62;
1030     }
run()1031     virtual void run() {
1032         uint8_t sk1[1024], sk2[1024];
1033         uint8_t *oldSk = NULL, *newSk = sk1;
1034         int32_t oldLen = 0;
1035         int32_t prev = 0;
1036         int32_t i = 0;
1037 
1038         for(i = 0; i < noLines; i++) {
1039             if(lines[i].buflen == 0) { continue; }
1040 
1041             if(skipLineBecauseOfBug(lines[i].buff, lines[i].buflen)) { continue; }
1042 
1043             int32_t resLen = coll->getSortKey(lines[i].buff, lines[i].buflen, newSk, 1024);
1044 
1045             if(oldSk != NULL) {
1046                 int32_t skres = strcmp((char *)oldSk, (char *)newSk);
1047                 int32_t cmpres = coll->compare(lines[prev].buff, lines[prev].buflen, lines[i].buff, lines[i].buflen);
1048                 int32_t cmpres2 = coll->compare(lines[i].buff, lines[i].buflen, lines[prev].buff, lines[prev].buflen);
1049 
1050                 if(cmpres != -cmpres2) {
1051                     error(UnicodeString("Compare result not symmetrical on line ") + (i + 1));
1052                     break;
1053                 }
1054 
1055                 if(cmpres != normalizeResult(skres)) {
1056                     error(UnicodeString("Difference between coll->compare and sortkey compare on line ") + (i + 1));
1057                     break;
1058                 }
1059 
1060                 int32_t res = cmpres;
1061                 if(res == 0 && !isAtLeastUCA62) {
1062                     // Up to UCA 6.1, the collation test files use a custom tie-breaker,
1063                     // comparing the raw input strings.
1064                     res = u_strcmpCodePointOrder(lines[prev].buff, lines[i].buff);
1065                     // Starting with UCA 6.2, the collation test files use the standard UCA tie-breaker,
1066                     // comparing the NFD versions of the input strings,
1067                     // which we do via setting strength=identical.
1068                 }
1069                 if(res > 0) {
1070                     error(UnicodeString("Line is not greater or equal than previous line, for line ") + (i + 1));
1071                     break;
1072                 }
1073             }
1074 
1075             oldSk = newSk;
1076             oldLen = resLen;
1077             prev = i;
1078 
1079             newSk = (newSk == sk1)?sk2:sk1;
1080         }
1081     }
1082 };
1083 
TestCollators()1084 void MultithreadTest::TestCollators()
1085 {
1086 
1087     UErrorCode status = U_ZERO_ERROR;
1088     FILE *testFile = NULL;
1089     char testDataPath[1024];
1090     strcpy(testDataPath, IntlTest::getSourceTestData(status));
1091     if (U_FAILURE(status)) {
1092         errln("ERROR: could not open test data %s", u_errorName(status));
1093         return;
1094     }
1095     strcat(testDataPath, "CollationTest_");
1096 
1097     const char* type = "NON_IGNORABLE";
1098 
1099     const char *ext = ".txt";
1100     if(testFile) {
1101         fclose(testFile);
1102     }
1103     char buffer[1024];
1104     strcpy(buffer, testDataPath);
1105     strcat(buffer, type);
1106     size_t bufLen = strlen(buffer);
1107 
1108     // we try to open 3 files:
1109     // path/CollationTest_type.txt
1110     // path/CollationTest_type_SHORT.txt
1111     // path/CollationTest_type_STUB.txt
1112     // we are going to test with the first one that we manage to open.
1113 
1114     strcpy(buffer+bufLen, ext);
1115 
1116     testFile = fopen(buffer, "rb");
1117 
1118     if(testFile == 0) {
1119         strcpy(buffer+bufLen, "_SHORT");
1120         strcat(buffer, ext);
1121         testFile = fopen(buffer, "rb");
1122 
1123         if(testFile == 0) {
1124             strcpy(buffer+bufLen, "_STUB");
1125             strcat(buffer, ext);
1126             testFile = fopen(buffer, "rb");
1127 
1128             if (testFile == 0) {
1129                 *(buffer+bufLen) = 0;
1130                 dataerrln("could not open any of the conformance test files, tried opening base %s", buffer);
1131                 return;
1132             } else {
1133                 infoln(
1134                     "INFO: Working with the stub file.\n"
1135                     "If you need the full conformance test, please\n"
1136                     "download the appropriate data files from:\n"
1137                     "http://source.icu-project.org/repos/icu/tools/trunk/unicodetools/com/ibm/text/data/");
1138             }
1139         }
1140     }
1141 
1142     LocalArray<Line> lines(new Line[200000]);
1143     memset(lines.getAlias(), 0, sizeof(Line)*200000);
1144     int32_t lineNum = 0;
1145 
1146     UChar bufferU[1024];
1147     uint32_t first = 0;
1148 
1149     while (fgets(buffer, 1024, testFile) != NULL) {
1150         if(*buffer == 0 || buffer[0] == '#') {
1151             // Store empty and comment lines so that errors are reported
1152             // for the real test file lines.
1153             lines[lineNum].buflen = 0;
1154             lines[lineNum].buff[0] = 0;
1155         } else {
1156             int32_t buflen = u_parseString(buffer, bufferU, 1024, &first, &status);
1157             lines[lineNum].buflen = buflen;
1158             u_memcpy(lines[lineNum].buff, bufferU, buflen);
1159             lines[lineNum].buff[buflen] = 0;
1160         }
1161         lineNum++;
1162     }
1163     fclose(testFile);
1164     if(U_FAILURE(status)) {
1165       dataerrln("Couldn't read the test file!");
1166       return;
1167     }
1168 
1169     UVersionInfo uniVersion;
1170     static const UVersionInfo v62 = { 6, 2, 0, 0 };
1171     u_getUnicodeVersion(uniVersion);
1172     UBool isAtLeastUCA62 = uprv_memcmp(uniVersion, v62, 4) >= 0;
1173 
1174     LocalPointer<Collator> coll(Collator::createInstance(Locale::getRoot(), status));
1175     if(U_FAILURE(status)) {
1176         errcheckln(status, "Couldn't open UCA collator");
1177         return;
1178     }
1179     coll->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status);
1180     coll->setAttribute(UCOL_CASE_FIRST, UCOL_OFF, status);
1181     coll->setAttribute(UCOL_CASE_LEVEL, UCOL_OFF, status);
1182     coll->setAttribute(UCOL_STRENGTH, isAtLeastUCA62 ? UCOL_IDENTICAL : UCOL_TERTIARY, status);
1183     coll->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_NON_IGNORABLE, status);
1184 
1185     int32_t noSpawned = 0;
1186     int32_t spawnResult = 0;
1187     LocalArray<CollatorThreadTest> tests(new CollatorThreadTest[kCollatorThreadThreads]);
1188 
1189     logln(UnicodeString("Spawning: ") + kCollatorThreadThreads + " threads * " + kFormatThreadIterations + " iterations each.");
1190     int32_t j = 0;
1191     for(j = 0; j < kCollatorThreadThreads; j++) {
1192         //logln("Setting collator %i", j);
1193         tests[j].setCollator(coll.getAlias(), lines.getAlias(), lineNum, isAtLeastUCA62);
1194     }
1195     for(j = 0; j < kCollatorThreadThreads; j++) {
1196         log("%i ", j);
1197         spawnResult = tests[j].start();
1198         if(spawnResult != 0) {
1199             infoln("THREAD INFO: Couldn't spawn more than %i threads", noSpawned);
1200             break;
1201         }
1202         noSpawned++;
1203     }
1204     logln("Spawned all");
1205     if (noSpawned == 0) {
1206         errln("No threads could be spawned.");
1207         return;
1208     }
1209 
1210     for(int32_t patience = kCollatorThreadPatience;patience > 0; patience --)
1211     {
1212         logln("Waiting...");
1213 
1214         int32_t i;
1215         int32_t terrs = 0;
1216         int32_t completed =0;
1217 
1218         for(i=0;i<kCollatorThreadThreads;i++)
1219         {
1220             if (tests[i].isRunning() == FALSE)
1221             {
1222                 completed++;
1223 
1224                 //logln(UnicodeString("Test #") + i + " is complete.. ");
1225 
1226                 UnicodeString theErr;
1227                 if(tests[i].getError(theErr))
1228                 {
1229                     terrs++;
1230                     errln(UnicodeString("#") + i + ": " + theErr);
1231                 }
1232                 // print out the error, too, if any.
1233             }
1234         }
1235         logln("Completed %i tests", completed);
1236 
1237         if(completed == noSpawned)
1238         {
1239             logln("Done! All %i tests are finished", noSpawned);
1240 
1241             if(terrs)
1242             {
1243                 errln("There were errors.");
1244                 SimpleThread::errorFunc();
1245             }
1246             return;
1247         }
1248 
1249         SimpleThread::sleep(900);
1250     }
1251     errln("patience exceeded. ");
1252     SimpleThread::errorFunc();
1253 }
1254 
1255 #endif /* #if !UCONFIG_NO_COLLATION */
1256 
1257 
1258 
1259 
1260 //-------------------------------------------------------------------------------------------
1261 //
1262 //   StringThreadTest2
1263 //
1264 //-------------------------------------------------------------------------------------------
1265 
1266 const int kStringThreadIterations = 2500;// # of iterations per thread
1267 const int kStringThreadThreads    = 10;  // # of threads to spawn
1268 const int kStringThreadPatience   = 120; // time in seconds to wait for all threads
1269 
1270 
1271 class StringThreadTest2 : public ThreadWithStatus
1272 {
1273 public:
1274     int                 fNum;
1275     int                 fTraceInfo;
1276     const UnicodeString *fSharedString;
1277 
StringThreadTest2(const UnicodeString * sharedString,int num)1278     StringThreadTest2(const UnicodeString *sharedString, int num) // constructor is NOT multithread safe.
1279         : ThreadWithStatus(),
1280         fNum(num),
1281         fTraceInfo(0),
1282         fSharedString(sharedString)
1283     {
1284     };
1285 
1286 
run()1287     virtual void run()
1288     {
1289         fTraceInfo    = 1;
1290         int loopCount = 0;
1291 
1292         for (loopCount = 0; loopCount < kStringThreadIterations; loopCount++) {
1293             if (*fSharedString != "This is the original test string.") {
1294                 error("Original string is corrupt.");
1295                 break;
1296             }
1297             UnicodeString s1 = *fSharedString;
1298             s1 += "cat this";
1299             UnicodeString s2(s1);
1300             UnicodeString s3 = *fSharedString;
1301             s2 = s3;
1302             s3.truncate(12);
1303             s2.truncate(0);
1304         }
1305 
1306         //  while (fNum == 4) {SimpleThread::sleep(10000);}   // Force a failure by preventing thread from finishing
1307         fTraceInfo = 2;
1308     }
1309 
1310 };
1311 
1312 // ** The actual test function.
1313 
TestString()1314 void MultithreadTest::TestString()
1315 {
1316     int     patience;
1317     int     terrs = 0;
1318     int     j;
1319 
1320     UnicodeString *testString = new UnicodeString("This is the original test string.");
1321 
1322     // Not using LocalArray<StringThreadTest2> tests[kStringThreadThreads];
1323     // because we don't always want to delete them.
1324     // See the comments below the cleanupAndReturn label.
1325     StringThreadTest2  *tests[kStringThreadThreads];
1326     for(j = 0; j < kStringThreadThreads; j++) {
1327         tests[j] = new StringThreadTest2(testString, j);
1328     }
1329 
1330     logln(UnicodeString("Spawning: ") + kStringThreadThreads + " threads * " + kStringThreadIterations + " iterations each.");
1331     for(j = 0; j < kStringThreadThreads; j++) {
1332         int32_t threadStatus = tests[j]->start();
1333         if (threadStatus != 0) {
1334             errln("System Error %d starting thread number %d.", threadStatus, j);
1335             SimpleThread::errorFunc();
1336             goto cleanupAndReturn;
1337         }
1338     }
1339 
1340     for(patience = kStringThreadPatience;patience > 0; patience --)
1341     {
1342         logln("Waiting...");
1343 
1344         int32_t i;
1345         terrs = 0;
1346         int32_t completed =0;
1347 
1348         for(i=0;i<kStringThreadThreads;i++) {
1349             if (tests[i]->isRunning() == FALSE)
1350             {
1351                 completed++;
1352 
1353                 logln(UnicodeString("Test #") + i + " is complete.. ");
1354 
1355                 UnicodeString theErr;
1356                 if(tests[i]->getError(theErr))
1357                 {
1358                     terrs++;
1359                     errln(UnicodeString("#") + i + ": " + theErr);
1360                 }
1361                 // print out the error, too, if any.
1362             }
1363         }
1364 
1365         if(completed == kStringThreadThreads)
1366         {
1367             logln("Done!");
1368             if(terrs) {
1369                 errln("There were errors.");
1370             }
1371             break;
1372         }
1373 
1374         SimpleThread::sleep(900);
1375     }
1376 
1377     if (patience <= 0) {
1378         errln("patience exceeded. ");
1379         // while (TRUE) {SimpleThread::sleep(10000);}   // TODO:   for debugging.  Sleep forever on failure.
1380         terrs++;
1381     }
1382 
1383     if (terrs > 0) {
1384         SimpleThread::errorFunc();
1385     }
1386 
1387 cleanupAndReturn:
1388     if (terrs == 0) {
1389         /*
1390         Don't clean up if there are errors. This prevents crashes if the
1391         threads are still running and using this data. This will only happen
1392         if there is an error with the test, ICU, or the machine is too slow.
1393         It's better to leak than crash.
1394         */
1395         for(j = 0; j < kStringThreadThreads; j++) {
1396             delete tests[j];
1397         }
1398         delete testString;
1399     }
1400 }
1401 
1402 #endif // ICU_USE_THREADS
1403