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