1 /********************************************************************
3 * Copyright (c) 1999-2011, 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"
28 #if U_PLATFORM_USES_ONLY_WIN32_API
29 /* Prefer native Windows APIs even if POSIX is implemented (i.e., on Cygwin). */
31 #elif U_PLATFORM_IMPLEMENTS_POSIX
37 /* Needed by z/OS to get usleep */
38 #if U_PLATFORM == U_PF_OS390
50 #if (ICU_USE_THREADS == 1)
54 #if defined(__hpux) && defined(HPUX_CMA)
55 # if defined(read) // read being defined as cma_read causes trouble with iostream::read
60 /* Define __EXTENSIONS__ for Solaris and old friends in strict mode. */
61 #ifndef __EXTENSIONS__
62 #define __EXTENSIONS__
65 #if U_PLATFORM == U_PF_OS390
66 #include <sys/types.h>
69 #if U_PLATFORM != U_PF_OS390
73 /* Define _XPG4_2 for Solaris and friends. */
78 /* Define __USE_XOPEN_EXTENDED for Linux and glibc. */
79 #ifndef __USE_XOPEN_EXTENDED
80 #define __USE_XOPEN_EXTENDED
83 /* Define _INCLUDE_XOPEN_SOURCE_EXTENDED for HP/UX (11?). */
84 #ifndef _INCLUDE_XOPEN_SOURCE_EXTENDED
85 #define _INCLUDE_XOPEN_SOURCE_EXTENDED
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");}}
103 MultithreadTest::MultithreadTest()
107 MultithreadTest::~MultithreadTest()
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: ");
119 name
= "NO_THREADED_TESTS";
123 if(exec
) { logln("MultithreadTest - test DISABLED. ICU_USE_THREADS set to 0, check your configuration if this is a problem..");
130 #include <ctype.h> // tolower, toupper
132 #include "unicode/putil.h"
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"
143 void SimpleThread::errorFunc() {
144 // *(char *)0 = 3; // Force entry into a debugger via a crash;
147 void MultithreadTest::runIndexedTest( int32_t index
, UBool exec
,
148 const char* &name
, char* /*par*/ ) {
150 logln("TestSuite MultithreadTest: ");
153 name
= "TestThreads";
165 name
= "TestThreadedIntl";
166 #if !UCONFIG_NO_FORMATTING
174 name
= "TestCollators";
175 #if !UCONFIG_NO_COLLATION
179 #endif /* #if !UCONFIG_NO_COLLATION */
191 break; //needed to end loop
196 //-----------------------------------------------------------------------------------
198 // TestThreads -- see if threads really work at all.
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
204 //-----------------------------------------------------------------------------------
205 #define THREADTEST_NRTHREADS 8
207 class TestThreadsThread
: public SimpleThread
210 TestThreadsThread(char* whatToChange
) { fWhatToChange
= whatToChange
; }
211 virtual void run() { SimpleThread::sleep(1000);
213 *fWhatToChange
= '*';
219 void MultithreadTest::TestThreads()
221 char threadTestChars
[THREADTEST_NRTHREADS
+ 1];
222 SimpleThread
*threads
[THREADTEST_NRTHREADS
];
223 int32_t numThreadsStarted
= 0;
226 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
228 threadTestChars
[i
] = ' ';
229 threads
[i
] = new TestThreadsThread(&threadTestChars
[i
]);
231 threadTestChars
[THREADTEST_NRTHREADS
] = '\0';
233 logln("->" + UnicodeString(threadTestChars
) + "<- Firing off threads.. ");
234 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
236 if (threads
[i
]->start() != 0) {
237 errln("Error starting thread %d", i
);
242 SimpleThread::sleep(100);
243 logln(" Subthread started.");
246 logln("Waiting for threads to be set..");
247 if (numThreadsStarted
== 0) {
248 errln("No threads could be started for testing!");
252 int32_t patience
= 40; // seconds to wait
258 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
260 if(threadTestChars
[i
] == '*')
267 if(count
== THREADTEST_NRTHREADS
)
269 logln("->" + UnicodeString(threadTestChars
) + "<- Got all threads! cya");
270 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
277 logln("->" + UnicodeString(threadTestChars
) + "<- Waiting..");
278 SimpleThread::sleep(500);
281 errln("->" + UnicodeString(threadTestChars
) + "<- PATIENCE EXCEEDED!! Still missing some.");
282 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
289 //-----------------------------------------------------------------------
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.
296 //----------------------------------------------------------------------
297 static UMTX gTestMutexA
= NULL
;
298 static UMTX gTestMutexB
= NULL
;
300 static int gThreadsStarted
= 0;
301 static int gThreadsInMiddle
= 0;
302 static int gThreadsDone
= 0;
304 static const int TESTMUTEX_THREAD_COUNT
= 4;
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.
315 class TestMutexThread
: public SimpleThread
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.
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);
334 void MultithreadTest::TestMutex()
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
340 gThreadsInMiddle
= 0;
342 umtx_lock(&gTestMutexA
);
343 TestMutexThread
*threads
[TESTMUTEX_THREAD_COUNT
];
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
);
355 if (numThreadsStarted
== 0) {
356 errln("No threads could be started for testing!");
361 while (safeIncr(gThreadsStarted
, 0) != TESTMUTEX_THREAD_COUNT
) {
362 if (patience
++ > 24) {
363 TSMTHREAD_FAIL("Patience Exceeded");
366 SimpleThread::sleep(500);
368 // None of the test threads should have advanced past the first mutex.
369 TSMTHREAD_ASSERT(gThreadsInMiddle
==0);
370 TSMTHREAD_ASSERT(gThreadsDone
==0);
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
);
379 while (safeIncr(gThreadsInMiddle
, 0) != TESTMUTEX_THREAD_COUNT
) {
380 if (patience
++ > 24) {
381 TSMTHREAD_FAIL("Patience Exceeded");
384 SimpleThread::sleep(500);
386 TSMTHREAD_ASSERT(gThreadsDone
==0);
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
);
392 while (safeIncr(gThreadsDone
, 0) != TESTMUTEX_THREAD_COUNT
) {
393 if (patience
++ > 24) {
394 TSMTHREAD_FAIL("Patience Exceeded");
397 SimpleThread::sleep(500);
400 // All threads made it by both mutexes.
401 // Destroy the test mutexes.
402 umtx_destroy(&gTestMutexA
);
403 umtx_destroy(&gTestMutexB
);
407 for (i
=0; i
<TESTMUTEX_THREAD_COUNT
; i
++) {
414 //-------------------------------------------------------------------------------------------
416 // class ThreadWithStatus - a thread that we can check the status and error condition of
418 //-------------------------------------------------------------------------------------------
419 class ThreadWithStatus
: public SimpleThread
422 UBool
getError() { return (fErrors
> 0); }
423 UBool
getError(UnicodeString
& fillinError
) { fillinError
= fErrorString
; return (fErrors
> 0); }
424 virtual ~ThreadWithStatus(){}
426 ThreadWithStatus() : fErrors(0) {}
427 void error(const UnicodeString
&error
) {
428 fErrors
++; fErrorString
= error
;
429 SimpleThread::errorFunc();
431 void error() { error("An error occured."); }
434 UnicodeString fErrorString
;
439 //-------------------------------------------------------------------------------------------
441 // TestMultithreadedIntl. Test ICU Formatting n a multi-threaded environment
443 //-------------------------------------------------------------------------------------------
446 // * Show exactly where the string's differences lie.
447 UnicodeString
showDifference(const UnicodeString
& expected
, const UnicodeString
& result
)
450 res
= expected
+ "<Expected\n";
451 if(expected
.length() != result
.length())
452 res
+= " [ Different lengths ] \n";
455 for(int32_t i
=0;i
<expected
.length();i
++)
457 if(expected
[i
] == result
[i
])
466 res
+= "<Differences";
469 res
+= result
+ "<Result\n";
477 //-------------------------------------------------------------------------------------------
479 // FormatThreadTest - a thread that tests performing a number of numberformats.
481 //-------------------------------------------------------------------------------------------
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
487 #if !UCONFIG_NO_FORMATTING
491 struct FormatThreadTestData
494 UnicodeString string
;
495 FormatThreadTestData(double a
, const UnicodeString
& b
) : number(a
),string(b
) {}
499 // "Someone from {2} is receiving a #{0} error - {1}. Their telephone call is costing {3 number,currency}."
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
)
505 if(U_FAILURE(realStatus
))
506 return; // you messed up
508 UnicodeString
errString1(u_errorName(inStatus0
));
510 UnicodeString countryName2
;
511 inCountry2
.getDisplayCountry(theLocale
,countryName2
);
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}
520 MessageFormat
*fmt
= new MessageFormat("MessageFormat's API is broken!!!!!!!!!!!",realStatus
);
521 fmt
->setLocale(theLocale
);
522 fmt
->applyPattern(pattern
, realStatus
);
524 if (U_FAILURE(realStatus
)) {
529 FieldPosition ignore
= 0;
530 fmt
->format(myArgs
,4,result
,ignore
,realStatus
);
536 UBool U_CALLCONV
isAcceptable(void *, const char *, const char *, const UDataInfo
*) {
540 //static UMTX debugMutex = NULL;
541 //static UMTX gDebugMutex;
544 class FormatThreadTest
: public ThreadWithStatus
550 FormatThreadTest() // constructor is NOT multithread safe.
551 : ThreadWithStatus(),
557 static int32_t fgOffset
= 0;
566 LocalPointer
<NumberFormat
> percentFormatter
;
567 UErrorCode status
= U_ZERO_ERROR
;
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
);
577 if (U_FAILURE(status
)) {
578 error("udata_openChoice failed.\n");
588 for (m
=0; m
<4000; m
++) {
589 status
= U_ZERO_ERROR
;
590 UResourceBundle
*res
= NULL
;
591 const char *localeName
= NULL
;
593 Locale loc
= Locale::getEnglish();
595 localeName
= loc
.getName();
596 // localeName = "en";
598 // ResourceBundle bund = ResourceBundle(0, loc, status);
599 //umtx_lock(&gDebugMutex);
600 res
= ures_open(NULL
, localeName
, &status
);
601 //umtx_unlock(&gDebugMutex);
603 //umtx_lock(&gDebugMutex);
605 //umtx_unlock(&gDebugMutex);
607 if (U_FAILURE(status
)) {
608 error("Resource bundle construction failed.\n");
615 // Keep this data here to avoid static initialization.
616 FormatThreadTestData kNumberFormatTestData
[] =
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", "")),
626 int32_t kNumberFormatTestDataLength
= (int32_t)(sizeof(kNumberFormatTestData
) /
627 sizeof(kNumberFormatTestData
[0]));
629 // Keep this data here to avoid static initialization.
630 FormatThreadTestData kPercentFormatTestData
[] =
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%")),
640 int32_t kPercentFormatTestDataLength
=
641 (int32_t)(sizeof(kPercentFormatTestData
) / sizeof(kPercentFormatTestData
[0]));
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
;
651 percentFormatter
.adoptInstead(NumberFormat::createPercentInstance(Locale::getFrench(),status
));
652 if(U_FAILURE(status
)) {
653 error("Error on NumberFormat::createPercentInstance().");
654 goto cleanupAndReturn
;
657 for(iteration
= 0;!getError() && iteration
<kFormatThreadIterations
;iteration
++)
660 int32_t whichLine
= (iteration
+ fOffset
)%kNumberFormatTestDataLength
;
662 UnicodeString output
;
664 formatter
->format(kNumberFormatTestData
[whichLine
].number
, output
);
666 if(0 != output
.compare(kNumberFormatTestData
[whichLine
].string
)) {
667 error("format().. expected " + kNumberFormatTestData
[whichLine
].string
669 goto cleanupAndReturn
;
672 // Now check percent.
674 whichLine
= (iteration
+ fOffset
)%kPercentFormatTestDataLength
;
676 percentFormatter
->format(kPercentFormatTestData
[whichLine
].number
, output
);
677 if(0 != output
.compare(kPercentFormatTestData
[whichLine
].string
))
679 error("percent format().. \n" +
680 showDifference(kPercentFormatTestData
[whichLine
].string
,output
));
681 goto cleanupAndReturn
;
684 // Test message error
685 const int kNumberOfMessageTests
= 3;
686 UErrorCode statusToCheck
;
687 UnicodeString patternToCheck
;
688 Locale messageLocale
;
689 Locale countryToCheck
;
690 double currencyToCheck
;
692 UnicodeString expected
;
695 switch((iteration
+fOffset
) % kNumberOfMessageTests
)
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.";
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.");
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.");
733 UnicodeString result
;
734 UErrorCode status
= U_ZERO_ERROR
;
735 formatErrorMessage(status
,patternToCheck
,messageLocale
,statusToCheck
,
736 countryToCheck
,currencyToCheck
,result
);
737 if(U_FAILURE(status
))
739 UnicodeString
tmp(u_errorName(status
));
740 error("Failure on message format, pattern=" + patternToCheck
+
742 goto cleanupAndReturn
;
745 if(result
!= expected
)
747 error("PatternFormat: \n" + showDifference(expected
,result
));
748 goto cleanupAndReturn
;
750 } /* end of for loop */
753 // while (fNum == 4) {SimpleThread::sleep(10000);} // Force a failure by preventing thread from finishing
758 int32_t fOffset
; // where we are testing from.
761 // ** The actual test function.
763 void MultithreadTest::TestThreadedIntl()
766 UnicodeString theErr
;
767 UBool haveDisplayedInfo
[kFormatThreadThreads
];
768 static const int32_t PATIENCE_SECONDS
= 45;
771 // Create and start the test threads
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
++) {
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();
784 haveDisplayedInfo
[j
] = FALSE
;
788 // Spin, waiting for the test threads to finish.
790 UDate startTime
, endTime
;
791 startTime
= Calendar::getNow();
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.");
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
805 SimpleThread::sleep(1); // yield
806 for(i
=0;i
<kFormatThreadThreads
;i
++) {
807 if (tests
[i
].isRunning()) {
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();
815 haveDisplayedInfo
[i
] = TRUE
;
818 } while (stillRunning
);
821 // All threads have finished.
824 #endif /* #if !UCONFIG_NO_FORMATTING */
830 //-------------------------------------------------------------------------------------------
832 // Collation threading test
834 //-------------------------------------------------------------------------------------------
835 #if !UCONFIG_NO_COLLATION
837 #define kCollatorThreadThreads 10 // # of threads to spawn
838 #define kCollatorThreadPatience kCollatorThreadThreads*30
845 class CollatorThreadTest
: public ThreadWithStatus
848 const UCollator
*coll
;
852 CollatorThreadTest() : ThreadWithStatus(),
858 void setCollator(UCollator
*c
, Line
*l
, int32_t nl
)
868 uint8_t sk1
[1024], sk2
[1024];
869 uint8_t *oldSk
= NULL
, *newSk
= sk1
;
870 int32_t resLen
= 0, oldLen
= 0;
873 for(i
= 0; i
< noLines
; i
++) {
874 resLen
= ucol_getSortKey(coll
, lines
[i
].buff
, lines
[i
].buflen
, newSk
, 1024);
876 int32_t res
= 0, cmpres
= 0, cmpres2
= 0;
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
);
885 if(cmpres
!= -cmpres2
) {
886 error("Compare result not symmetrical on line "+ line
);
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
));
896 error(UnicodeString("Line %i is not greater or equal than previous line ")+ UnicodeString(i
));
898 } else if(res
== 0) { /* equal */
899 res
= u_strcmpCodePointOrder(lines
[i
-1].buff
, lines
[i
].buff
);
901 error(UnicodeString("Probable error in test file on line %i (comparing identical strings)")+ UnicodeString(i
));
905 * UCA 6.0 test files can have lines that compare == if they are
906 * different strings but canonically equivalent.
908 error(UnicodeString("Sortkeys are identical, but code point compare gives >0 on line ")+ UnicodeString(i));
918 newSk
= (newSk
== sk1
)?sk2
:sk1
;
923 void MultithreadTest::TestCollators()
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
));
934 strcat(testDataPath
, "CollationTest_");
936 const char* type
= "NON_IGNORABLE";
938 const char *ext
= ".txt";
943 strcpy(buffer
, testDataPath
);
944 strcat(buffer
, type
);
945 size_t bufLen
= strlen(buffer
);
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.
953 strcpy(buffer
+bufLen
, ext
);
955 testFile
= fopen(buffer
, "rb");
958 strcpy(buffer
+bufLen
, "_SHORT");
960 testFile
= fopen(buffer
, "rb");
963 strcpy(buffer
+bufLen
, "_STUB");
965 testFile
= fopen(buffer
, "rb");
968 *(buffer
+bufLen
) = 0;
969 dataerrln("could not open any of the conformance test files, tried opening base %s", buffer
);
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/");
981 Line
*lines
= new Line
[200000];
982 memset(lines
, 0, sizeof(Line
)*200000);
990 while (fgets(buffer
, 1024, testFile
) != NULL
) {
992 if(*buffer
== 0 || strlen(buffer
) < 3 || buffer
[0] == '#') {
995 offset
= u_parseString(buffer
, bufferU
, 1024, &first
, &status
);
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
);
1004 if(U_FAILURE(status
)) {
1005 dataerrln("Couldn't read the test file!");
1009 UCollator
*coll
= ucol_open("root", &status
);
1010 if(U_FAILURE(status
)) {
1011 errcheckln(status
, "Couldn't open UCA collator");
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
);
1020 int32_t noSpawned
= 0;
1021 int32_t spawnResult
= 0;
1022 LocalArray
<CollatorThreadTest
> tests(new CollatorThreadTest
[kCollatorThreadThreads
]);
1024 logln(UnicodeString("Spawning: ") + kCollatorThreadThreads
+ " threads * " + kFormatThreadIterations
+ " iterations each.");
1026 for(j
= 0; j
< kCollatorThreadThreads
; j
++) {
1027 //logln("Setting collator %i", j);
1028 tests
[j
].setCollator(coll
, lines
, lineNum
);
1030 for(j
= 0; j
< kCollatorThreadThreads
; j
++) {
1032 spawnResult
= tests
[j
].start();
1033 if(spawnResult
!= 0) {
1034 infoln("THREAD INFO: Couldn't spawn more than %i threads", noSpawned
);
1039 logln("Spawned all");
1040 if (noSpawned
== 0) {
1041 errln("No threads could be spawned.");
1045 for(int32_t patience
= kCollatorThreadPatience
;patience
> 0; patience
--)
1047 logln("Waiting...");
1051 int32_t completed
=0;
1053 for(i
=0;i
<kCollatorThreadThreads
;i
++)
1055 if (tests
[i
].isRunning() == FALSE
)
1059 //logln(UnicodeString("Test #") + i + " is complete.. ");
1061 UnicodeString theErr
;
1062 if(tests
[i
].getError(theErr
))
1065 errln(UnicodeString("#") + i
+ ": " + theErr
);
1067 // print out the error, too, if any.
1070 logln("Completed %i tests", completed
);
1072 if(completed
== noSpawned
)
1074 logln("Done! All %i tests are finished", noSpawned
);
1078 errln("There were errors.");
1079 SimpleThread::errorFunc();
1082 //for(i = 0; i < lineNum; i++) {
1083 //delete[] lines[i].buff;
1090 SimpleThread::sleep(900);
1092 errln("patience exceeded. ");
1093 SimpleThread::errorFunc();
1097 #endif /* #if !UCONFIG_NO_COLLATION */
1102 //-------------------------------------------------------------------------------------------
1104 // StringThreadTest2
1106 //-------------------------------------------------------------------------------------------
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
1113 class StringThreadTest2
: public ThreadWithStatus
1118 const UnicodeString
*fSharedString
;
1120 StringThreadTest2(const UnicodeString
*sharedString
, int num
) // constructor is NOT multithread safe.
1121 : ThreadWithStatus(),
1124 fSharedString(sharedString
)
1134 for (loopCount
= 0; loopCount
< kStringThreadIterations
; loopCount
++) {
1135 if (*fSharedString
!= "This is the original test string.") {
1136 error("Original string is corrupt.");
1139 UnicodeString s1
= *fSharedString
;
1141 UnicodeString
s2(s1
);
1142 UnicodeString s3
= *fSharedString
;
1148 // while (fNum == 4) {SimpleThread::sleep(10000);} // Force a failure by preventing thread from finishing
1154 // ** The actual test function.
1156 void MultithreadTest::TestString()
1162 UnicodeString
*testString
= new UnicodeString("This is the original test string.");
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
);
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
;
1182 for(patience
= kStringThreadPatience
;patience
> 0; patience
--)
1184 logln("Waiting...");
1188 int32_t completed
=0;
1190 for(i
=0;i
<kStringThreadThreads
;i
++) {
1191 if (tests
[i
]->isRunning() == FALSE
)
1195 logln(UnicodeString("Test #") + i
+ " is complete.. ");
1197 UnicodeString theErr
;
1198 if(tests
[i
]->getError(theErr
))
1201 errln(UnicodeString("#") + i
+ ": " + theErr
);
1203 // print out the error, too, if any.
1207 if(completed
== kStringThreadThreads
)
1211 errln("There were errors.");
1216 SimpleThread::sleep(900);
1219 if (patience
<= 0) {
1220 errln("patience exceeded. ");
1221 // while (TRUE) {SimpleThread::sleep(10000);} // TODO: for debugging. Sleep forever on failure.
1226 SimpleThread::errorFunc();
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.
1237 for(j
= 0; j
< kStringThreadThreads
; j
++) {
1244 #endif // ICU_USE_THREADS