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