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