1 /********************************************************************
3 * Copyright (c) 1999-2012, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ********************************************************************/
8 # ifndef _INCLUDE_POSIX_SOURCE
9 # define _INCLUDE_POSIX_SOURCE
13 #include "simplethread.h"
15 #include "unicode/utypes.h"
16 #include "unicode/ustring.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"
29 #include "unicode/ushape.h"
32 #if U_PLATFORM_USES_ONLY_WIN32_API
33 /* Prefer native Windows APIs even if POSIX is implemented (i.e., on Cygwin). */
35 #elif U_PLATFORM_IMPLEMENTS_POSIX
42 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
43 /* Needed by z/OS to get usleep */
44 #if U_PLATFORM == U_PF_OS390
56 #if (ICU_USE_THREADS == 1)
60 #if defined(__hpux) && defined(HPUX_CMA)
61 # if defined(read) // read being defined as cma_read causes trouble with iostream::read
66 /* Define __EXTENSIONS__ for Solaris and old friends in strict mode. */
67 #ifndef __EXTENSIONS__
68 #define __EXTENSIONS__
71 #if U_PLATFORM == U_PF_OS390
72 #include <sys/types.h>
75 #if U_PLATFORM != U_PF_OS390
79 /* Define _XPG4_2 for Solaris and friends. */
84 /* Define __USE_XOPEN_EXTENDED for Linux and glibc. */
85 #ifndef __USE_XOPEN_EXTENDED
86 #define __USE_XOPEN_EXTENDED
89 /* Define _INCLUDE_XOPEN_SOURCE_EXTENDED for HP/UX (11?). */
90 #ifndef _INCLUDE_XOPEN_SOURCE_EXTENDED
91 #define _INCLUDE_XOPEN_SOURCE_EXTENDED
102 #define TSMTHREAD_FAIL(msg) errln("%s at file %s, line %d", msg, __FILE__, __LINE__)
103 #define TSMTHREAD_ASSERT(expr) {if (!(expr)) {TSMTHREAD_FAIL("Fail");}}
105 MultithreadTest::MultithreadTest()
109 MultithreadTest::~MultithreadTest()
115 #if (ICU_USE_THREADS==0)
116 void MultithreadTest::runIndexedTest( int32_t index
, UBool exec
,
117 const char* &name
, char* /*par*/ ) {
118 if (exec
) logln("TestSuite MultithreadTest: ");
121 name
= "NO_THREADED_TESTS";
125 if(exec
) { logln("MultithreadTest - test DISABLED. ICU_USE_THREADS set to 0, check your configuration if this is a problem..");
132 #include <ctype.h> // tolower, toupper
134 #include "unicode/putil.h"
137 #include "unicode/numfmt.h"
138 #include "unicode/choicfmt.h"
139 #include "unicode/msgfmt.h"
140 #include "unicode/locid.h"
141 #include "unicode/coll.h"
142 #include "unicode/calendar.h"
145 void SimpleThread::errorFunc() {
146 // *(char *)0 = 3; // Force entry into a debugger via a crash;
149 void MultithreadTest::runIndexedTest( int32_t index
, UBool exec
,
150 const char* &name
, char* /*par*/ ) {
152 logln("TestSuite MultithreadTest: ");
155 name
= "TestThreads";
167 name
= "TestThreadedIntl";
168 #if !UCONFIG_NO_FORMATTING
176 name
= "TestCollators";
177 #if !UCONFIG_NO_COLLATION
181 #endif /* #if !UCONFIG_NO_COLLATION */
192 name
= "TestArabicShapingThreads";
194 TestArabicShapingThreads();
201 break; //needed to end loop
206 //-----------------------------------------------------------------------------------
208 // TestThreads -- see if threads really work at all.
210 // Set up N threads pointing at N chars. When they are started, they will
211 // each sleep 1 second and then set their chars. At the end we make sure they
214 //-----------------------------------------------------------------------------------
215 #define THREADTEST_NRTHREADS 8
216 #define ARABICSHAPE_THREADTEST 30
218 class TestThreadsThread
: public SimpleThread
221 TestThreadsThread(char* whatToChange
) { fWhatToChange
= whatToChange
; }
222 virtual void run() { SimpleThread::sleep(1000);
224 *fWhatToChange
= '*';
229 //-----------------------------------------------------------------------------------
231 // TestArabicShapeThreads -- see if calls to u_shapeArabic in many threads works successfully
233 // Set up N threads pointing at N chars. When they are started, they will make calls to doTailTest which tests
234 // u_shapeArabic, if the calls are successful it will the set * chars.
235 // At the end we make sure all threads managed to run u_shapeArabic successfully.
236 // This is a unit test for ticket 9473
238 //-----------------------------------------------------------------------------------
239 class TestArabicShapeThreads
: public SimpleThread
242 TestArabicShapeThreads(char* whatToChange
) { fWhatToChange
= whatToChange
;}
244 if(doTailTest()==TRUE
)
245 *fWhatToChange
= '*';
250 UBool
doTailTest(void) {
251 static const UChar src
[] = { 0x0020, 0x0633, 0 };
252 static const UChar dst_old
[] = { 0xFEB1, 0x200B,0 };
253 static const UChar dst_new
[] = { 0xFEB1, 0xFE73,0 };
254 UChar dst
[3] = { 0x0000, 0x0000,0 };
257 IntlTest inteltst
= IntlTest();
259 status
= U_ZERO_ERROR
;
260 length
= u_shapeArabic(src
, -1, dst
, LENGTHOF(dst
),
261 U_SHAPE_LETTERS_SHAPE
|U_SHAPE_SEEN_TWOCELL_NEAR
, &status
);
262 if(U_FAILURE(status
)) {
263 inteltst
.errln("Fail: status %s\n", u_errorName(status
));
265 } else if(length
!=2) {
266 inteltst
.errln("Fail: len %d expected 3\n", length
);
268 } else if(u_strncmp(dst
,dst_old
,LENGTHOF(dst
))) {
269 inteltst
.errln("Fail: got U+%04X U+%04X expected U+%04X U+%04X\n",
270 dst
[0],dst
[1],dst_old
[0],dst_old
[1]);
276 status
= U_ZERO_ERROR
;
277 length
= u_shapeArabic(src
, -1, dst
, LENGTHOF(dst
),
278 U_SHAPE_LETTERS_SHAPE
|U_SHAPE_SEEN_TWOCELL_NEAR
|U_SHAPE_TAIL_NEW_UNICODE
, &status
);
279 if(U_FAILURE(status
)) {
280 inteltst
.errln("Fail: status %s\n", u_errorName(status
));
282 } else if(length
!=2) {
283 inteltst
.errln("Fail: len %d expected 3\n", length
);
285 } else if(u_strncmp(dst
,dst_new
,LENGTHOF(dst
))) {
286 inteltst
.errln("Fail: got U+%04X U+%04X expected U+%04X U+%04X\n",
287 dst
[0],dst
[1],dst_new
[0],dst_new
[1]);
299 void MultithreadTest::TestThreads()
301 char threadTestChars
[THREADTEST_NRTHREADS
+ 1];
302 SimpleThread
*threads
[THREADTEST_NRTHREADS
];
303 int32_t numThreadsStarted
= 0;
306 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
308 threadTestChars
[i
] = ' ';
309 threads
[i
] = new TestThreadsThread(&threadTestChars
[i
]);
311 threadTestChars
[THREADTEST_NRTHREADS
] = '\0';
313 logln("->" + UnicodeString(threadTestChars
) + "<- Firing off threads.. ");
314 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
316 if (threads
[i
]->start() != 0) {
317 errln("Error starting thread %d", i
);
322 SimpleThread::sleep(100);
323 logln(" Subthread started.");
326 logln("Waiting for threads to be set..");
327 if (numThreadsStarted
== 0) {
328 errln("No threads could be started for testing!");
332 int32_t patience
= 40; // seconds to wait
338 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
340 if(threadTestChars
[i
] == '*')
347 if(count
== THREADTEST_NRTHREADS
)
349 logln("->" + UnicodeString(threadTestChars
) + "<- Got all threads! cya");
350 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
357 logln("->" + UnicodeString(threadTestChars
) + "<- Waiting..");
358 SimpleThread::sleep(500);
361 errln("->" + UnicodeString(threadTestChars
) + "<- PATIENCE EXCEEDED!! Still missing some.");
362 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
369 void MultithreadTest::TestArabicShapingThreads()
371 char threadTestChars
[ARABICSHAPE_THREADTEST
+ 1];
372 SimpleThread
*threads
[ARABICSHAPE_THREADTEST
];
373 int32_t numThreadsStarted
= 0;
377 for(i
=0;i
<ARABICSHAPE_THREADTEST
;i
++)
379 threadTestChars
[i
] = ' ';
380 threads
[i
] = new TestArabicShapeThreads(&threadTestChars
[i
]);
382 threadTestChars
[ARABICSHAPE_THREADTEST
] = '\0';
384 logln("-> do TestArabicShapingThreads <- Firing off threads.. ");
385 for(i
=0;i
<ARABICSHAPE_THREADTEST
;i
++)
387 if (threads
[i
]->start() != 0) {
388 errln("Error starting thread %d", i
);
393 //SimpleThread::sleep(100);
394 logln(" Subthread started.");
397 logln("Waiting for threads to be set..");
398 if (numThreadsStarted
== 0) {
399 errln("No threads could be started for testing!");
403 int32_t patience
= 100; // seconds to wait
409 for(i
=0;i
<ARABICSHAPE_THREADTEST
;i
++)
411 if(threadTestChars
[i
] == '*')
418 if(count
== ARABICSHAPE_THREADTEST
)
420 logln("->TestArabicShapingThreads <- Got all threads! cya");
421 for(i
=0;i
<ARABICSHAPE_THREADTEST
;i
++)
428 logln("-> TestArabicShapingThreads <- Waiting..");
429 SimpleThread::sleep(500);
432 errln("-> TestArabicShapingThreads <- PATIENCE EXCEEDED!! Still missing some.");
433 for(i
=0;i
<ARABICSHAPE_THREADTEST
;i
++)
441 //-----------------------------------------------------------------------
443 // TestMutex - a simple (non-stress) test to verify that ICU mutexes
444 // are actually mutexing. Does not test the use of
445 // mutexes within ICU services, but rather that the
446 // platform's mutex support is at least superficially there.
448 //----------------------------------------------------------------------
449 static UMutex gTestMutexA
= U_MUTEX_INITIALIZER
;
450 static UMutex gTestMutexB
= U_MUTEX_INITIALIZER
;
452 static int gThreadsStarted
= 0;
453 static int gThreadsInMiddle
= 0;
454 static int gThreadsDone
= 0;
456 static const int TESTMUTEX_THREAD_COUNT
= 4;
458 static int safeIncr(int &var
, int amt
) {
459 // Thread safe (using global mutex) increment of a variable.
460 // Return the updated value.
461 // Can also be used as a safe load of a variable by incrementing it by 0.
467 class TestMutexThread
: public SimpleThread
472 // This is the code that each of the spawned threads runs.
473 // All of the spawned threads bunch up together at each of the two mutexes
474 // because the main holds the mutexes until they do.
476 safeIncr(gThreadsStarted
, 1);
477 umtx_lock(&gTestMutexA
);
478 umtx_unlock(&gTestMutexA
);
479 safeIncr(gThreadsInMiddle
, 1);
480 umtx_lock(&gTestMutexB
);
481 umtx_unlock(&gTestMutexB
);
482 safeIncr(gThreadsDone
, 1);
486 void MultithreadTest::TestMutex()
488 // Start up the test threads. They should all pile up waiting on
489 // gTestMutexA, which we (the main thread) hold until the test threads
492 gThreadsInMiddle
= 0;
494 umtx_lock(&gTestMutexA
);
495 TestMutexThread
*threads
[TESTMUTEX_THREAD_COUNT
];
497 int32_t numThreadsStarted
= 0;
498 for (i
=0; i
<TESTMUTEX_THREAD_COUNT
; i
++) {
499 threads
[i
] = new TestMutexThread
;
500 if (threads
[i
]->start() != 0) {
501 errln("Error starting thread %d", i
);
507 if (numThreadsStarted
== 0) {
508 errln("No threads could be started for testing!");
513 while (safeIncr(gThreadsStarted
, 0) != TESTMUTEX_THREAD_COUNT
) {
514 if (patience
++ > 24) {
515 TSMTHREAD_FAIL("Patience Exceeded");
518 SimpleThread::sleep(500);
520 // None of the test threads should have advanced past the first mutex.
521 TSMTHREAD_ASSERT(gThreadsInMiddle
==0);
522 TSMTHREAD_ASSERT(gThreadsDone
==0);
524 // All of the test threads have made it to the first mutex.
525 // We (the main thread) now let them advance to the second mutex,
526 // where they should all pile up again.
527 umtx_lock(&gTestMutexB
);
528 umtx_unlock(&gTestMutexA
);
531 while (safeIncr(gThreadsInMiddle
, 0) != TESTMUTEX_THREAD_COUNT
) {
532 if (patience
++ > 24) {
533 TSMTHREAD_FAIL("Patience Exceeded");
536 SimpleThread::sleep(500);
538 TSMTHREAD_ASSERT(gThreadsDone
==0);
540 // All test threads made it to the second mutex.
541 // Now let them proceed from there. They will all terminate.
542 umtx_unlock(&gTestMutexB
);
544 while (safeIncr(gThreadsDone
, 0) != TESTMUTEX_THREAD_COUNT
) {
545 if (patience
++ > 24) {
546 TSMTHREAD_FAIL("Patience Exceeded");
549 SimpleThread::sleep(500);
552 // All threads made it by both mutexes.
554 for (i
=0; i
<TESTMUTEX_THREAD_COUNT
; i
++) {
561 //-------------------------------------------------------------------------------------------
563 // class ThreadWithStatus - a thread that we can check the status and error condition of
565 //-------------------------------------------------------------------------------------------
566 class ThreadWithStatus
: public SimpleThread
569 UBool
getError() { return (fErrors
> 0); }
570 UBool
getError(UnicodeString
& fillinError
) { fillinError
= fErrorString
; return (fErrors
> 0); }
571 virtual ~ThreadWithStatus(){}
573 ThreadWithStatus() : fErrors(0) {}
574 void error(const UnicodeString
&error
) {
575 fErrors
++; fErrorString
= error
;
576 SimpleThread::errorFunc();
578 void error() { error("An error occured."); }
581 UnicodeString fErrorString
;
586 //-------------------------------------------------------------------------------------------
588 // TestMultithreadedIntl. Test ICU Formatting n a multi-threaded environment
590 //-------------------------------------------------------------------------------------------
593 // * Show exactly where the string's differences lie.
594 UnicodeString
showDifference(const UnicodeString
& expected
, const UnicodeString
& result
)
597 res
= expected
+ "<Expected\n";
598 if(expected
.length() != result
.length())
599 res
+= " [ Different lengths ] \n";
602 for(int32_t i
=0;i
<expected
.length();i
++)
604 if(expected
[i
] == result
[i
])
613 res
+= "<Differences";
616 res
+= result
+ "<Result\n";
624 //-------------------------------------------------------------------------------------------
626 // FormatThreadTest - a thread that tests performing a number of numberformats.
628 //-------------------------------------------------------------------------------------------
630 const int kFormatThreadIterations
= 20; // # of iterations per thread
631 const int kFormatThreadThreads
= 10; // # of threads to spawn
632 const int kFormatThreadPatience
= 60; // time in seconds to wait for all threads
634 #if !UCONFIG_NO_FORMATTING
638 struct FormatThreadTestData
641 UnicodeString string
;
642 FormatThreadTestData(double a
, const UnicodeString
& b
) : number(a
),string(b
) {}
646 // "Someone from {2} is receiving a #{0} error - {1}. Their telephone call is costing {3 number,currency}."
648 void formatErrorMessage(UErrorCode
&realStatus
, const UnicodeString
& pattern
, const Locale
& theLocale
,
649 UErrorCode inStatus0
, /* statusString 1 */ const Locale
&inCountry2
, double currency3
, // these numbers are the message arguments.
650 UnicodeString
&result
)
652 if(U_FAILURE(realStatus
))
653 return; // you messed up
655 UnicodeString
errString1(u_errorName(inStatus0
));
657 UnicodeString countryName2
;
658 inCountry2
.getDisplayCountry(theLocale
,countryName2
);
660 Formattable myArgs
[] = {
661 Formattable((int32_t)inStatus0
), // inStatus0 {0}
662 Formattable(errString1
), // statusString1 {1}
663 Formattable(countryName2
), // inCountry2 {2}
664 Formattable(currency3
)// currency3 {3,number,currency}
667 MessageFormat
*fmt
= new MessageFormat("MessageFormat's API is broken!!!!!!!!!!!",realStatus
);
668 fmt
->setLocale(theLocale
);
669 fmt
->applyPattern(pattern
, realStatus
);
671 if (U_FAILURE(realStatus
)) {
676 FieldPosition ignore
= 0;
677 fmt
->format(myArgs
,4,result
,ignore
,realStatus
);
683 UBool U_CALLCONV
isAcceptable(void *, const char *, const char *, const UDataInfo
*) {
687 //static UMTX debugMutex = NULL;
688 //static UMTX gDebugMutex;
691 class FormatThreadTest
: public ThreadWithStatus
697 FormatThreadTest() // constructor is NOT multithread safe.
698 : ThreadWithStatus(),
704 static int32_t fgOffset
= 0;
713 LocalPointer
<NumberFormat
> percentFormatter
;
714 UErrorCode status
= U_ZERO_ERROR
;
718 for (int i
=0; i
<4000; i
++) {
719 status
= U_ZERO_ERROR
;
720 UDataMemory
*data1
= udata_openChoice(0, "res", "en_US", isAcceptable
, 0, &status
);
721 UDataMemory
*data2
= udata_openChoice(0, "res", "fr", isAcceptable
, 0, &status
);
724 if (U_FAILURE(status
)) {
725 error("udata_openChoice failed.\n");
735 for (m
=0; m
<4000; m
++) {
736 status
= U_ZERO_ERROR
;
737 UResourceBundle
*res
= NULL
;
738 const char *localeName
= NULL
;
740 Locale loc
= Locale::getEnglish();
742 localeName
= loc
.getName();
743 // localeName = "en";
745 // ResourceBundle bund = ResourceBundle(0, loc, status);
746 //umtx_lock(&gDebugMutex);
747 res
= ures_open(NULL
, localeName
, &status
);
748 //umtx_unlock(&gDebugMutex);
750 //umtx_lock(&gDebugMutex);
752 //umtx_unlock(&gDebugMutex);
754 if (U_FAILURE(status
)) {
755 error("Resource bundle construction failed.\n");
762 // Keep this data here to avoid static initialization.
763 FormatThreadTestData kNumberFormatTestData
[] =
765 FormatThreadTestData((double)5.0, UnicodeString("5", "")),
766 FormatThreadTestData( 6.0, UnicodeString("6", "")),
767 FormatThreadTestData( 20.0, UnicodeString("20", "")),
768 FormatThreadTestData( 8.0, UnicodeString("8", "")),
769 FormatThreadTestData( 8.3, UnicodeString("8.3", "")),
770 FormatThreadTestData( 12345, UnicodeString("12,345", "")),
771 FormatThreadTestData( 81890.23, UnicodeString("81,890.23", "")),
773 int32_t kNumberFormatTestDataLength
= (int32_t)(sizeof(kNumberFormatTestData
) /
774 sizeof(kNumberFormatTestData
[0]));
776 // Keep this data here to avoid static initialization.
777 FormatThreadTestData kPercentFormatTestData
[] =
779 FormatThreadTestData((double)5.0, CharsToUnicodeString("500\\u00a0%")),
780 FormatThreadTestData( 1.0, CharsToUnicodeString("100\\u00a0%")),
781 FormatThreadTestData( 0.26, CharsToUnicodeString("26\\u00a0%")),
782 FormatThreadTestData(
783 16384.99, CharsToUnicodeString("1\\u00a0638\\u00a0499\\u00a0%")), // U+00a0 = NBSP
784 FormatThreadTestData(
785 81890.23, CharsToUnicodeString("8\\u00a0189\\u00a0023\\u00a0%")),
787 int32_t kPercentFormatTestDataLength
=
788 (int32_t)(sizeof(kPercentFormatTestData
) / sizeof(kPercentFormatTestData
[0]));
791 status
= U_ZERO_ERROR
;
792 LocalPointer
<NumberFormat
> formatter(NumberFormat::createInstance(Locale::getEnglish(),status
));
793 if(U_FAILURE(status
)) {
794 error("Error on NumberFormat::createInstance().");
795 goto cleanupAndReturn
;
798 percentFormatter
.adoptInstead(NumberFormat::createPercentInstance(Locale::getFrench(),status
));
799 if(U_FAILURE(status
)) {
800 error("Error on NumberFormat::createPercentInstance().");
801 goto cleanupAndReturn
;
804 for(iteration
= 0;!getError() && iteration
<kFormatThreadIterations
;iteration
++)
807 int32_t whichLine
= (iteration
+ fOffset
)%kNumberFormatTestDataLength
;
809 UnicodeString output
;
811 formatter
->format(kNumberFormatTestData
[whichLine
].number
, output
);
813 if(0 != output
.compare(kNumberFormatTestData
[whichLine
].string
)) {
814 error("format().. expected " + kNumberFormatTestData
[whichLine
].string
816 goto cleanupAndReturn
;
819 // Now check percent.
821 whichLine
= (iteration
+ fOffset
)%kPercentFormatTestDataLength
;
823 percentFormatter
->format(kPercentFormatTestData
[whichLine
].number
, output
);
824 if(0 != output
.compare(kPercentFormatTestData
[whichLine
].string
))
826 error("percent format().. \n" +
827 showDifference(kPercentFormatTestData
[whichLine
].string
,output
));
828 goto cleanupAndReturn
;
831 // Test message error
832 const int kNumberOfMessageTests
= 3;
833 UErrorCode statusToCheck
;
834 UnicodeString patternToCheck
;
835 Locale messageLocale
;
836 Locale countryToCheck
;
837 double currencyToCheck
;
839 UnicodeString expected
;
842 switch((iteration
+fOffset
) % kNumberOfMessageTests
)
846 statusToCheck
= U_FILE_ACCESS_ERROR
;
847 patternToCheck
= "0:Someone from {2} is receiving a #{0}"
848 " error - {1}. Their telephone call is costing "
849 "{3,number,currency}."; // number,currency
850 messageLocale
= Locale("en","US");
851 countryToCheck
= Locale("","HR");
852 currencyToCheck
= 8192.77;
853 expected
= "0:Someone from Croatia is receiving a #4 error - "
854 "U_FILE_ACCESS_ERROR. Their telephone call is costing $8,192.77.";
857 statusToCheck
= U_INDEX_OUTOFBOUNDS_ERROR
;
858 patternToCheck
= "1:A customer in {2} is receiving a #{0} error - {1}. Their telephone call is costing {3,number,currency}."; // number,currency
859 messageLocale
= Locale("de","DE@currency=DEM");
860 countryToCheck
= Locale("","BF");
861 currencyToCheck
= 2.32;
862 expected
= CharsToUnicodeString(
863 "1:A customer in Burkina Faso is receiving a #8 error - U_INDEX_OUTOFBOUNDS_ERROR. Their telephone call is costing 2,32\\u00A0DEM.");
866 statusToCheck
= U_MEMORY_ALLOCATION_ERROR
;
867 patternToCheck
= "2:user in {2} is receiving a #{0} error - {1}. "
868 "They insist they just spent {3,number,currency} "
869 "on memory."; // number,currency
870 messageLocale
= Locale("de","AT@currency=ATS"); // Austrian German
871 countryToCheck
= Locale("","US"); // hmm
872 currencyToCheck
= 40193.12;
873 expected
= CharsToUnicodeString(
874 "2:user in Vereinigte Staaten is receiving a #7 error"
875 " - U_MEMORY_ALLOCATION_ERROR. They insist they just spent"
876 " \\u00f6S\\u00A040.193,12 on memory.");
880 UnicodeString result
;
881 UErrorCode status
= U_ZERO_ERROR
;
882 formatErrorMessage(status
,patternToCheck
,messageLocale
,statusToCheck
,
883 countryToCheck
,currencyToCheck
,result
);
884 if(U_FAILURE(status
))
886 UnicodeString
tmp(u_errorName(status
));
887 error("Failure on message format, pattern=" + patternToCheck
+
889 goto cleanupAndReturn
;
892 if(result
!= expected
)
894 error("PatternFormat: \n" + showDifference(expected
,result
));
895 goto cleanupAndReturn
;
897 } /* end of for loop */
900 // while (fNum == 4) {SimpleThread::sleep(10000);} // Force a failure by preventing thread from finishing
905 int32_t fOffset
; // where we are testing from.
908 // ** The actual test function.
910 void MultithreadTest::TestThreadedIntl()
913 UnicodeString theErr
;
914 UBool haveDisplayedInfo
[kFormatThreadThreads
];
915 static const int32_t PATIENCE_SECONDS
= 45;
918 // Create and start the test threads
920 logln("Spawning: %d threads * %d iterations each.",
921 kFormatThreadThreads
, kFormatThreadIterations
);
922 LocalArray
<FormatThreadTest
> tests(new FormatThreadTest
[kFormatThreadThreads
]);
923 for(int32_t j
= 0; j
< kFormatThreadThreads
; j
++) {
925 int32_t threadStatus
= tests
[j
].start();
926 if (threadStatus
!= 0) {
927 errln("System Error %d starting thread number %d.", threadStatus
, j
);
928 SimpleThread::errorFunc();
931 haveDisplayedInfo
[j
] = FALSE
;
935 // Spin, waiting for the test threads to finish.
937 UDate startTime
, endTime
;
938 startTime
= Calendar::getNow();
940 /* Spin until the test threads complete. */
941 stillRunning
= FALSE
;
942 endTime
= Calendar::getNow();
943 if (((int32_t)(endTime
- startTime
)/U_MILLIS_PER_SECOND
) > PATIENCE_SECONDS
) {
944 errln("Patience exceeded. Test is taking too long.");
948 The following sleep must be here because the *BSD operating systems
949 have a brain dead thread scheduler. They starve the child threads from
952 SimpleThread::sleep(1); // yield
953 for(i
=0;i
<kFormatThreadThreads
;i
++) {
954 if (tests
[i
].isRunning()) {
956 } else if (haveDisplayedInfo
[i
] == FALSE
) {
957 logln("Thread # %d is complete..", i
);
958 if(tests
[i
].getError(theErr
)) {
959 dataerrln(UnicodeString("#") + i
+ ": " + theErr
);
960 SimpleThread::errorFunc();
962 haveDisplayedInfo
[i
] = TRUE
;
965 } while (stillRunning
);
968 // All threads have finished.
971 #endif /* #if !UCONFIG_NO_FORMATTING */
977 //-------------------------------------------------------------------------------------------
979 // Collation threading test
981 //-------------------------------------------------------------------------------------------
982 #if !UCONFIG_NO_COLLATION
984 #define kCollatorThreadThreads 10 // # of threads to spawn
985 #define kCollatorThreadPatience kCollatorThreadThreads*30
993 skipLineBecauseOfBug(const UChar
*s
, int32_t length
) {
994 // TODO: Fix ICU ticket #8052
996 (s
[0] == 0xfb2 || s
[0] == 0xfb3) &&
998 (s
[2] == 0xf73 || s
[2] == 0xf75 || s
[2] == 0xf81)) {
1004 static UCollationResult
1005 normalizeResult(int32_t result
) {
1006 return result
<0 ? UCOL_LESS
: result
==0 ? UCOL_EQUAL
: UCOL_GREATER
;
1009 class CollatorThreadTest
: public ThreadWithStatus
1012 const Collator
*coll
;
1015 UBool isAtLeastUCA62
;
1017 CollatorThreadTest() : ThreadWithStatus(),
1021 isAtLeastUCA62(TRUE
)
1024 void setCollator(Collator
*c
, Line
*l
, int32_t nl
, UBool atLeastUCA62
)
1029 isAtLeastUCA62
= atLeastUCA62
;
1031 virtual void run() {
1032 uint8_t sk1
[1024], sk2
[1024];
1033 uint8_t *oldSk
= NULL
, *newSk
= sk1
;
1038 for(i
= 0; i
< noLines
; i
++) {
1039 if(lines
[i
].buflen
== 0) { continue; }
1041 if(skipLineBecauseOfBug(lines
[i
].buff
, lines
[i
].buflen
)) { continue; }
1043 int32_t resLen
= coll
->getSortKey(lines
[i
].buff
, lines
[i
].buflen
, newSk
, 1024);
1046 int32_t skres
= strcmp((char *)oldSk
, (char *)newSk
);
1047 int32_t cmpres
= coll
->compare(lines
[prev
].buff
, lines
[prev
].buflen
, lines
[i
].buff
, lines
[i
].buflen
);
1048 int32_t cmpres2
= coll
->compare(lines
[i
].buff
, lines
[i
].buflen
, lines
[prev
].buff
, lines
[prev
].buflen
);
1050 if(cmpres
!= -cmpres2
) {
1051 error(UnicodeString("Compare result not symmetrical on line ") + (i
+ 1));
1055 if(cmpres
!= normalizeResult(skres
)) {
1056 error(UnicodeString("Difference between coll->compare and sortkey compare on line ") + (i
+ 1));
1060 int32_t res
= cmpres
;
1061 if(res
== 0 && !isAtLeastUCA62
) {
1062 // Up to UCA 6.1, the collation test files use a custom tie-breaker,
1063 // comparing the raw input strings.
1064 res
= u_strcmpCodePointOrder(lines
[prev
].buff
, lines
[i
].buff
);
1065 // Starting with UCA 6.2, the collation test files use the standard UCA tie-breaker,
1066 // comparing the NFD versions of the input strings,
1067 // which we do via setting strength=identical.
1070 error(UnicodeString("Line is not greater or equal than previous line, for line ") + (i
+ 1));
1079 newSk
= (newSk
== sk1
)?sk2
:sk1
;
1084 void MultithreadTest::TestCollators()
1087 UErrorCode status
= U_ZERO_ERROR
;
1088 FILE *testFile
= NULL
;
1089 char testDataPath
[1024];
1090 strcpy(testDataPath
, IntlTest::getSourceTestData(status
));
1091 if (U_FAILURE(status
)) {
1092 errln("ERROR: could not open test data %s", u_errorName(status
));
1095 strcat(testDataPath
, "CollationTest_");
1097 const char* type
= "NON_IGNORABLE";
1099 const char *ext
= ".txt";
1104 strcpy(buffer
, testDataPath
);
1105 strcat(buffer
, type
);
1106 size_t bufLen
= strlen(buffer
);
1108 // we try to open 3 files:
1109 // path/CollationTest_type.txt
1110 // path/CollationTest_type_SHORT.txt
1111 // path/CollationTest_type_STUB.txt
1112 // we are going to test with the first one that we manage to open.
1114 strcpy(buffer
+bufLen
, ext
);
1116 testFile
= fopen(buffer
, "rb");
1119 strcpy(buffer
+bufLen
, "_SHORT");
1120 strcat(buffer
, ext
);
1121 testFile
= fopen(buffer
, "rb");
1124 strcpy(buffer
+bufLen
, "_STUB");
1125 strcat(buffer
, ext
);
1126 testFile
= fopen(buffer
, "rb");
1128 if (testFile
== 0) {
1129 *(buffer
+bufLen
) = 0;
1130 dataerrln("could not open any of the conformance test files, tried opening base %s", buffer
);
1134 "INFO: Working with the stub file.\n"
1135 "If you need the full conformance test, please\n"
1136 "download the appropriate data files from:\n"
1137 "http://source.icu-project.org/repos/icu/tools/trunk/unicodetools/com/ibm/text/data/");
1142 LocalArray
<Line
> lines(new Line
[200000]);
1143 memset(lines
.getAlias(), 0, sizeof(Line
)*200000);
1144 int32_t lineNum
= 0;
1146 UChar bufferU
[1024];
1149 while (fgets(buffer
, 1024, testFile
) != NULL
) {
1150 if(*buffer
== 0 || buffer
[0] == '#') {
1151 // Store empty and comment lines so that errors are reported
1152 // for the real test file lines.
1153 lines
[lineNum
].buflen
= 0;
1154 lines
[lineNum
].buff
[0] = 0;
1156 int32_t buflen
= u_parseString(buffer
, bufferU
, 1024, &first
, &status
);
1157 lines
[lineNum
].buflen
= buflen
;
1158 u_memcpy(lines
[lineNum
].buff
, bufferU
, buflen
);
1159 lines
[lineNum
].buff
[buflen
] = 0;
1164 if(U_FAILURE(status
)) {
1165 dataerrln("Couldn't read the test file!");
1169 UVersionInfo uniVersion
;
1170 static const UVersionInfo v62
= { 6, 2, 0, 0 };
1171 u_getUnicodeVersion(uniVersion
);
1172 UBool isAtLeastUCA62
= uprv_memcmp(uniVersion
, v62
, 4) >= 0;
1174 LocalPointer
<Collator
> coll(Collator::createInstance(Locale::getRoot(), status
));
1175 if(U_FAILURE(status
)) {
1176 errcheckln(status
, "Couldn't open UCA collator");
1179 coll
->setAttribute(UCOL_NORMALIZATION_MODE
, UCOL_ON
, status
);
1180 coll
->setAttribute(UCOL_CASE_FIRST
, UCOL_OFF
, status
);
1181 coll
->setAttribute(UCOL_CASE_LEVEL
, UCOL_OFF
, status
);
1182 coll
->setAttribute(UCOL_STRENGTH
, isAtLeastUCA62
? UCOL_IDENTICAL
: UCOL_TERTIARY
, status
);
1183 coll
->setAttribute(UCOL_ALTERNATE_HANDLING
, UCOL_NON_IGNORABLE
, status
);
1185 int32_t noSpawned
= 0;
1186 int32_t spawnResult
= 0;
1187 LocalArray
<CollatorThreadTest
> tests(new CollatorThreadTest
[kCollatorThreadThreads
]);
1189 logln(UnicodeString("Spawning: ") + kCollatorThreadThreads
+ " threads * " + kFormatThreadIterations
+ " iterations each.");
1191 for(j
= 0; j
< kCollatorThreadThreads
; j
++) {
1192 //logln("Setting collator %i", j);
1193 tests
[j
].setCollator(coll
.getAlias(), lines
.getAlias(), lineNum
, isAtLeastUCA62
);
1195 for(j
= 0; j
< kCollatorThreadThreads
; j
++) {
1197 spawnResult
= tests
[j
].start();
1198 if(spawnResult
!= 0) {
1199 infoln("THREAD INFO: Couldn't spawn more than %i threads", noSpawned
);
1204 logln("Spawned all");
1205 if (noSpawned
== 0) {
1206 errln("No threads could be spawned.");
1210 for(int32_t patience
= kCollatorThreadPatience
;patience
> 0; patience
--)
1212 logln("Waiting...");
1216 int32_t completed
=0;
1218 for(i
=0;i
<kCollatorThreadThreads
;i
++)
1220 if (tests
[i
].isRunning() == FALSE
)
1224 //logln(UnicodeString("Test #") + i + " is complete.. ");
1226 UnicodeString theErr
;
1227 if(tests
[i
].getError(theErr
))
1230 errln(UnicodeString("#") + i
+ ": " + theErr
);
1232 // print out the error, too, if any.
1235 logln("Completed %i tests", completed
);
1237 if(completed
== noSpawned
)
1239 logln("Done! All %i tests are finished", noSpawned
);
1243 errln("There were errors.");
1244 SimpleThread::errorFunc();
1249 SimpleThread::sleep(900);
1251 errln("patience exceeded. ");
1252 SimpleThread::errorFunc();
1255 #endif /* #if !UCONFIG_NO_COLLATION */
1260 //-------------------------------------------------------------------------------------------
1262 // StringThreadTest2
1264 //-------------------------------------------------------------------------------------------
1266 const int kStringThreadIterations
= 2500;// # of iterations per thread
1267 const int kStringThreadThreads
= 10; // # of threads to spawn
1268 const int kStringThreadPatience
= 120; // time in seconds to wait for all threads
1271 class StringThreadTest2
: public ThreadWithStatus
1276 const UnicodeString
*fSharedString
;
1278 StringThreadTest2(const UnicodeString
*sharedString
, int num
) // constructor is NOT multithread safe.
1279 : ThreadWithStatus(),
1282 fSharedString(sharedString
)
1292 for (loopCount
= 0; loopCount
< kStringThreadIterations
; loopCount
++) {
1293 if (*fSharedString
!= "This is the original test string.") {
1294 error("Original string is corrupt.");
1297 UnicodeString s1
= *fSharedString
;
1299 UnicodeString
s2(s1
);
1300 UnicodeString s3
= *fSharedString
;
1306 // while (fNum == 4) {SimpleThread::sleep(10000);} // Force a failure by preventing thread from finishing
1312 // ** The actual test function.
1314 void MultithreadTest::TestString()
1320 UnicodeString
*testString
= new UnicodeString("This is the original test string.");
1322 // Not using LocalArray<StringThreadTest2> tests[kStringThreadThreads];
1323 // because we don't always want to delete them.
1324 // See the comments below the cleanupAndReturn label.
1325 StringThreadTest2
*tests
[kStringThreadThreads
];
1326 for(j
= 0; j
< kStringThreadThreads
; j
++) {
1327 tests
[j
] = new StringThreadTest2(testString
, j
);
1330 logln(UnicodeString("Spawning: ") + kStringThreadThreads
+ " threads * " + kStringThreadIterations
+ " iterations each.");
1331 for(j
= 0; j
< kStringThreadThreads
; j
++) {
1332 int32_t threadStatus
= tests
[j
]->start();
1333 if (threadStatus
!= 0) {
1334 errln("System Error %d starting thread number %d.", threadStatus
, j
);
1335 SimpleThread::errorFunc();
1336 goto cleanupAndReturn
;
1340 for(patience
= kStringThreadPatience
;patience
> 0; patience
--)
1342 logln("Waiting...");
1346 int32_t completed
=0;
1348 for(i
=0;i
<kStringThreadThreads
;i
++) {
1349 if (tests
[i
]->isRunning() == FALSE
)
1353 logln(UnicodeString("Test #") + i
+ " is complete.. ");
1355 UnicodeString theErr
;
1356 if(tests
[i
]->getError(theErr
))
1359 errln(UnicodeString("#") + i
+ ": " + theErr
);
1361 // print out the error, too, if any.
1365 if(completed
== kStringThreadThreads
)
1369 errln("There were errors.");
1374 SimpleThread::sleep(900);
1377 if (patience
<= 0) {
1378 errln("patience exceeded. ");
1379 // while (TRUE) {SimpleThread::sleep(10000);} // TODO: for debugging. Sleep forever on failure.
1384 SimpleThread::errorFunc();
1390 Don't clean up if there are errors. This prevents crashes if the
1391 threads are still running and using this data. This will only happen
1392 if there is an error with the test, ICU, or the machine is too slow.
1393 It's better to leak than crash.
1395 for(j
= 0; j
< kStringThreadThreads
; j
++) {
1402 #endif // ICU_USE_THREADS