1 /********************************************************************
3 * Copyright (c) 1999-2010, 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"
27 #if !defined(U_WINDOWS) && !defined(XP_MAC) && !defined(U_RHAPSODY)
31 /* Needed by z/OS to get usleep */
35 #define _XOPEN_SOURCE_EXTENDED 1
40 /*#include "platform_xopen_source_extended.h"*/
42 #if defined(POSIX) || defined(U_SOLARIS) || defined(U_AIX) || defined(U_HPUX)
46 #if (ICU_USE_THREADS == 1)
50 #if defined(__hpux) && defined(HPUX_CMA)
51 # if defined(read) // read being defined as cma_read causes trouble with iostream::read
56 /* Define __EXTENSIONS__ for Solaris and old friends in strict mode. */
57 #ifndef __EXTENSIONS__
58 #define __EXTENSIONS__
62 #include <sys/types.h>
69 /* Define _XPG4_2 for Solaris and friends. */
74 /* Define __USE_XOPEN_EXTENDED for Linux and glibc. */
75 #ifndef __USE_XOPEN_EXTENDED
76 #define __USE_XOPEN_EXTENDED
79 /* Define _INCLUDE_XOPEN_SOURCE_EXTENDED for HP/UX (11?). */
80 #ifndef _INCLUDE_XOPEN_SOURCE_EXTENDED
81 #define _INCLUDE_XOPEN_SOURCE_EXTENDED
96 #define TSMTHREAD_FAIL(msg) errln("%s at file %s, line %d", msg, __FILE__, __LINE__)
97 #define TSMTHREAD_ASSERT(expr) {if (!(expr)) {TSMTHREAD_FAIL("Fail");}}
99 MultithreadTest::MultithreadTest()
103 MultithreadTest::~MultithreadTest()
109 #if (ICU_USE_THREADS==0)
110 void MultithreadTest::runIndexedTest( int32_t index
, UBool exec
,
111 const char* &name
, char* /*par*/ ) {
112 if (exec
) logln("TestSuite MultithreadTest: ");
115 name
= "NO_THREADED_TESTS";
119 if(exec
) { logln("MultithreadTest - test DISABLED. ICU_USE_THREADS set to 0, check your configuration if this is a problem..");
126 #include <ctype.h> // tolower, toupper
128 #include "unicode/putil.h"
131 #include "unicode/numfmt.h"
132 #include "unicode/choicfmt.h"
133 #include "unicode/msgfmt.h"
134 #include "unicode/locid.h"
135 #include "unicode/ucol.h"
136 #include "unicode/calendar.h"
139 void SimpleThread::errorFunc() {
140 // *(char *)0 = 3; // Force entry into a debugger via a crash;
143 void MultithreadTest::runIndexedTest( int32_t index
, UBool exec
,
144 const char* &name
, char* /*par*/ ) {
146 logln("TestSuite MultithreadTest: ");
149 name
= "TestThreads";
161 name
= "TestThreadedIntl";
162 #if !UCONFIG_NO_FORMATTING
170 name
= "TestCollators";
171 #if !UCONFIG_NO_COLLATION
175 #endif /* #if !UCONFIG_NO_COLLATION */
187 break; //needed to end loop
192 //-----------------------------------------------------------------------------------
194 // TestThreads -- see if threads really work at all.
196 // Set up N threads pointing at N chars. When they are started, they will
197 // each sleep 1 second and then set their chars. At the end we make sure they
200 //-----------------------------------------------------------------------------------
201 #define THREADTEST_NRTHREADS 8
203 class TestThreadsThread
: public SimpleThread
206 TestThreadsThread(char* whatToChange
) { fWhatToChange
= whatToChange
; }
207 virtual void run() { SimpleThread::sleep(1000);
209 *fWhatToChange
= '*';
215 void MultithreadTest::TestThreads()
217 char threadTestChars
[THREADTEST_NRTHREADS
+ 1];
218 SimpleThread
*threads
[THREADTEST_NRTHREADS
];
219 int32_t numThreadsStarted
= 0;
222 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
224 threadTestChars
[i
] = ' ';
225 threads
[i
] = new TestThreadsThread(&threadTestChars
[i
]);
227 threadTestChars
[THREADTEST_NRTHREADS
] = '\0';
229 logln("->" + UnicodeString(threadTestChars
) + "<- Firing off threads.. ");
230 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
232 if (threads
[i
]->start() != 0) {
233 errln("Error starting thread %d", i
);
238 SimpleThread::sleep(100);
239 logln(" Subthread started.");
242 logln("Waiting for threads to be set..");
243 if (numThreadsStarted
== 0) {
244 errln("No threads could be started for testing!");
248 int32_t patience
= 40; // seconds to wait
254 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
256 if(threadTestChars
[i
] == '*')
263 if(count
== THREADTEST_NRTHREADS
)
265 logln("->" + UnicodeString(threadTestChars
) + "<- Got all threads! cya");
266 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
273 logln("->" + UnicodeString(threadTestChars
) + "<- Waiting..");
274 SimpleThread::sleep(500);
277 errln("->" + UnicodeString(threadTestChars
) + "<- PATIENCE EXCEEDED!! Still missing some.");
278 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
285 //-----------------------------------------------------------------------
287 // TestMutex - a simple (non-stress) test to verify that ICU mutexes
288 // are actually mutexing. Does not test the use of
289 // mutexes within ICU services, but rather that the
290 // platform's mutex support is at least superficially there.
292 //----------------------------------------------------------------------
293 static UMTX gTestMutexA
= NULL
;
294 static UMTX gTestMutexB
= NULL
;
296 static int gThreadsStarted
= 0;
297 static int gThreadsInMiddle
= 0;
298 static int gThreadsDone
= 0;
300 static const int TESTMUTEX_THREAD_COUNT
= 4;
302 static int safeIncr(int &var
, int amt
) {
303 // Thread safe (using global mutex) increment of a variable.
304 // Return the updated value.
305 // Can also be used as a safe load of a variable by incrementing it by 0.
311 class TestMutexThread
: public SimpleThread
316 // This is the code that each of the spawned threads runs.
317 // All of the spawned threads bunch up together at each of the two mutexes
318 // because the main holds the mutexes until they do.
320 safeIncr(gThreadsStarted
, 1);
321 umtx_lock(&gTestMutexA
);
322 umtx_unlock(&gTestMutexA
);
323 safeIncr(gThreadsInMiddle
, 1);
324 umtx_lock(&gTestMutexB
);
325 umtx_unlock(&gTestMutexB
);
326 safeIncr(gThreadsDone
, 1);
330 void MultithreadTest::TestMutex()
332 // Start up the test threads. They should all pile up waiting on
333 // gTestMutexA, which we (the main thread) hold until the test threads
336 gThreadsInMiddle
= 0;
338 umtx_lock(&gTestMutexA
);
339 TestMutexThread
*threads
[TESTMUTEX_THREAD_COUNT
];
341 int32_t numThreadsStarted
= 0;
342 for (i
=0; i
<TESTMUTEX_THREAD_COUNT
; i
++) {
343 threads
[i
] = new TestMutexThread
;
344 if (threads
[i
]->start() != 0) {
345 errln("Error starting thread %d", i
);
351 if (numThreadsStarted
== 0) {
352 errln("No threads could be started for testing!");
357 while (safeIncr(gThreadsStarted
, 0) != TESTMUTEX_THREAD_COUNT
) {
358 if (patience
++ > 24) {
359 TSMTHREAD_FAIL("Patience Exceeded");
362 SimpleThread::sleep(500);
364 // None of the test threads should have advanced past the first mutex.
365 TSMTHREAD_ASSERT(gThreadsInMiddle
==0);
366 TSMTHREAD_ASSERT(gThreadsDone
==0);
368 // All of the test threads have made it to the first mutex.
369 // We (the main thread) now let them advance to the second mutex,
370 // where they should all pile up again.
371 umtx_lock(&gTestMutexB
);
372 umtx_unlock(&gTestMutexA
);
375 while (safeIncr(gThreadsInMiddle
, 0) != TESTMUTEX_THREAD_COUNT
) {
376 if (patience
++ > 24) {
377 TSMTHREAD_FAIL("Patience Exceeded");
380 SimpleThread::sleep(500);
382 TSMTHREAD_ASSERT(gThreadsDone
==0);
384 // All test threads made it to the second mutex.
385 // Now let them proceed from there. They will all terminate.
386 umtx_unlock(&gTestMutexB
);
388 while (safeIncr(gThreadsDone
, 0) != TESTMUTEX_THREAD_COUNT
) {
389 if (patience
++ > 24) {
390 TSMTHREAD_FAIL("Patience Exceeded");
393 SimpleThread::sleep(500);
396 // All threads made it by both mutexes.
397 // Destroy the test mutexes.
398 umtx_destroy(&gTestMutexA
);
399 umtx_destroy(&gTestMutexB
);
403 for (i
=0; i
<TESTMUTEX_THREAD_COUNT
; i
++) {
410 //-------------------------------------------------------------------------------------------
412 // class ThreadWithStatus - a thread that we can check the status and error condition of
414 //-------------------------------------------------------------------------------------------
415 class ThreadWithStatus
: public SimpleThread
418 UBool
getError() { return (fErrors
> 0); }
419 UBool
getError(UnicodeString
& fillinError
) { fillinError
= fErrorString
; return (fErrors
> 0); }
420 virtual ~ThreadWithStatus(){}
422 ThreadWithStatus() : fErrors(0) {}
423 void error(const UnicodeString
&error
) {
424 fErrors
++; fErrorString
= error
;
425 SimpleThread::errorFunc();
427 void error() { error("An error occured."); }
430 UnicodeString fErrorString
;
435 //-------------------------------------------------------------------------------------------
437 // TestMultithreadedIntl. Test ICU Formatting n a multi-threaded environment
439 //-------------------------------------------------------------------------------------------
442 // * Show exactly where the string's differences lie.
443 UnicodeString
showDifference(const UnicodeString
& expected
, const UnicodeString
& result
)
446 res
= expected
+ "<Expected\n";
447 if(expected
.length() != result
.length())
448 res
+= " [ Different lengths ] \n";
451 for(int32_t i
=0;i
<expected
.length();i
++)
453 if(expected
[i
] == result
[i
])
462 res
+= "<Differences";
465 res
+= result
+ "<Result\n";
473 //-------------------------------------------------------------------------------------------
475 // FormatThreadTest - a thread that tests performing a number of numberformats.
477 //-------------------------------------------------------------------------------------------
479 const int kFormatThreadIterations
= 20; // # of iterations per thread
480 const int kFormatThreadThreads
= 10; // # of threads to spawn
481 const int kFormatThreadPatience
= 60; // time in seconds to wait for all threads
483 #if !UCONFIG_NO_FORMATTING
487 struct FormatThreadTestData
490 UnicodeString string
;
491 FormatThreadTestData(double a
, const UnicodeString
& b
) : number(a
),string(b
) {}
495 // "Someone from {2} is receiving a #{0} error - {1}. Their telephone call is costing {3 number,currency}."
497 void formatErrorMessage(UErrorCode
&realStatus
, const UnicodeString
& pattern
, const Locale
& theLocale
,
498 UErrorCode inStatus0
, /* statusString 1 */ const Locale
&inCountry2
, double currency3
, // these numbers are the message arguments.
499 UnicodeString
&result
)
501 if(U_FAILURE(realStatus
))
502 return; // you messed up
504 UnicodeString
errString1(u_errorName(inStatus0
));
506 UnicodeString countryName2
;
507 inCountry2
.getDisplayCountry(theLocale
,countryName2
);
509 Formattable myArgs
[] = {
510 Formattable((int32_t)inStatus0
), // inStatus0 {0}
511 Formattable(errString1
), // statusString1 {1}
512 Formattable(countryName2
), // inCountry2 {2}
513 Formattable(currency3
)// currency3 {3,number,currency}
516 MessageFormat
*fmt
= new MessageFormat("MessageFormat's API is broken!!!!!!!!!!!",realStatus
);
517 fmt
->setLocale(theLocale
);
518 fmt
->applyPattern(pattern
, realStatus
);
520 if (U_FAILURE(realStatus
)) {
525 FieldPosition ignore
= 0;
526 fmt
->format(myArgs
,4,result
,ignore
,realStatus
);
532 UBool U_CALLCONV
isAcceptable(void *, const char *, const char *, const UDataInfo
*) {
536 //static UMTX debugMutex = NULL;
537 //static UMTX gDebugMutex;
540 class FormatThreadTest
: public ThreadWithStatus
546 FormatThreadTest() // constructor is NOT multithread safe.
547 : ThreadWithStatus(),
553 static int32_t fgOffset
= 0;
562 LocalPointer
<NumberFormat
> percentFormatter
;
563 UErrorCode status
= U_ZERO_ERROR
;
567 for (int i
=0; i
<4000; i
++) {
568 status
= U_ZERO_ERROR
;
569 UDataMemory
*data1
= udata_openChoice(0, "res", "en_US", isAcceptable
, 0, &status
);
570 UDataMemory
*data2
= udata_openChoice(0, "res", "fr", isAcceptable
, 0, &status
);
573 if (U_FAILURE(status
)) {
574 error("udata_openChoice failed.\n");
584 for (m
=0; m
<4000; m
++) {
585 status
= U_ZERO_ERROR
;
586 UResourceBundle
*res
= NULL
;
587 const char *localeName
= NULL
;
589 Locale loc
= Locale::getEnglish();
591 localeName
= loc
.getName();
592 // localeName = "en";
594 // ResourceBundle bund = ResourceBundle(0, loc, status);
595 //umtx_lock(&gDebugMutex);
596 res
= ures_open(NULL
, localeName
, &status
);
597 //umtx_unlock(&gDebugMutex);
599 //umtx_lock(&gDebugMutex);
601 //umtx_unlock(&gDebugMutex);
603 if (U_FAILURE(status
)) {
604 error("Resource bundle construction failed.\n");
611 // Keep this data here to avoid static initialization.
612 FormatThreadTestData kNumberFormatTestData
[] =
614 FormatThreadTestData((double)5.0, UnicodeString("5", "")),
615 FormatThreadTestData( 6.0, UnicodeString("6", "")),
616 FormatThreadTestData( 20.0, UnicodeString("20", "")),
617 FormatThreadTestData( 8.0, UnicodeString("8", "")),
618 FormatThreadTestData( 8.3, UnicodeString("8.3", "")),
619 FormatThreadTestData( 12345, UnicodeString("12,345", "")),
620 FormatThreadTestData( 81890.23, UnicodeString("81,890.23", "")),
622 int32_t kNumberFormatTestDataLength
= (int32_t)(sizeof(kNumberFormatTestData
) /
623 sizeof(kNumberFormatTestData
[0]));
625 // Keep this data here to avoid static initialization.
626 FormatThreadTestData kPercentFormatTestData
[] =
628 FormatThreadTestData((double)5.0, CharsToUnicodeString("500\\u00a0%")),
629 FormatThreadTestData( 1.0, CharsToUnicodeString("100\\u00a0%")),
630 FormatThreadTestData( 0.26, CharsToUnicodeString("26\\u00a0%")),
631 FormatThreadTestData(
632 16384.99, CharsToUnicodeString("1\\u00a0638\\u00a0499\\u00a0%")), // U+00a0 = NBSP
633 FormatThreadTestData(
634 81890.23, CharsToUnicodeString("8\\u00a0189\\u00a0023\\u00a0%")),
636 int32_t kPercentFormatTestDataLength
=
637 (int32_t)(sizeof(kPercentFormatTestData
) / sizeof(kPercentFormatTestData
[0]));
640 status
= U_ZERO_ERROR
;
641 LocalPointer
<NumberFormat
> formatter(NumberFormat::createInstance(Locale::getEnglish(),status
));
642 if(U_FAILURE(status
)) {
643 error("Error on NumberFormat::createInstance().");
644 goto cleanupAndReturn
;
647 percentFormatter
.adoptInstead(NumberFormat::createPercentInstance(Locale::getFrench(),status
));
648 if(U_FAILURE(status
)) {
649 error("Error on NumberFormat::createPercentInstance().");
650 goto cleanupAndReturn
;
653 for(iteration
= 0;!getError() && iteration
<kFormatThreadIterations
;iteration
++)
656 int32_t whichLine
= (iteration
+ fOffset
)%kNumberFormatTestDataLength
;
658 UnicodeString output
;
660 formatter
->format(kNumberFormatTestData
[whichLine
].number
, output
);
662 if(0 != output
.compare(kNumberFormatTestData
[whichLine
].string
)) {
663 error("format().. expected " + kNumberFormatTestData
[whichLine
].string
665 goto cleanupAndReturn
;
668 // Now check percent.
670 whichLine
= (iteration
+ fOffset
)%kPercentFormatTestDataLength
;
672 percentFormatter
->format(kPercentFormatTestData
[whichLine
].number
, output
);
673 if(0 != output
.compare(kPercentFormatTestData
[whichLine
].string
))
675 error("percent format().. \n" +
676 showDifference(kPercentFormatTestData
[whichLine
].string
,output
));
677 goto cleanupAndReturn
;
680 // Test message error
681 const int kNumberOfMessageTests
= 3;
682 UErrorCode statusToCheck
;
683 UnicodeString patternToCheck
;
684 Locale messageLocale
;
685 Locale countryToCheck
;
686 double currencyToCheck
;
688 UnicodeString expected
;
691 switch((iteration
+fOffset
) % kNumberOfMessageTests
)
695 statusToCheck
= U_FILE_ACCESS_ERROR
;
696 patternToCheck
= "0:Someone from {2} is receiving a #{0}"
697 " error - {1}. Their telephone call is costing "
698 "{3,number,currency}."; // number,currency
699 messageLocale
= Locale("en","US");
700 countryToCheck
= Locale("","HR");
701 currencyToCheck
= 8192.77;
702 expected
= "0:Someone from Croatia is receiving a #4 error - "
703 "U_FILE_ACCESS_ERROR. Their telephone call is costing $8,192.77.";
706 statusToCheck
= U_INDEX_OUTOFBOUNDS_ERROR
;
707 patternToCheck
= "1:A customer in {2} is receiving a #{0} error - {1}. Their telephone call is costing {3,number,currency}."; // number,currency
708 messageLocale
= Locale("de","DE@currency=DEM");
709 countryToCheck
= Locale("","BF");
710 currencyToCheck
= 2.32;
711 expected
= CharsToUnicodeString(
712 "1:A customer in Burkina Faso is receiving a #8 error - U_INDEX_OUTOFBOUNDS_ERROR. Their telephone call is costing 2,32\\u00A0DM.");
715 statusToCheck
= U_MEMORY_ALLOCATION_ERROR
;
716 patternToCheck
= "2:user in {2} is receiving a #{0} error - {1}. "
717 "They insist they just spent {3,number,currency} "
718 "on memory."; // number,currency
719 messageLocale
= Locale("de","AT@currency=ATS"); // Austrian German
720 countryToCheck
= Locale("","US"); // hmm
721 currencyToCheck
= 40193.12;
722 expected
= CharsToUnicodeString(
723 "2:user in Vereinigte Staaten is receiving a #7 error"
724 " - U_MEMORY_ALLOCATION_ERROR. They insist they just spent"
725 " \\u00f6S\\u00A040.193,12 on memory.");
729 UnicodeString result
;
730 UErrorCode status
= U_ZERO_ERROR
;
731 formatErrorMessage(status
,patternToCheck
,messageLocale
,statusToCheck
,
732 countryToCheck
,currencyToCheck
,result
);
733 if(U_FAILURE(status
))
735 UnicodeString
tmp(u_errorName(status
));
736 error("Failure on message format, pattern=" + patternToCheck
+
738 goto cleanupAndReturn
;
741 if(result
!= expected
)
743 error("PatternFormat: \n" + showDifference(expected
,result
));
744 goto cleanupAndReturn
;
746 } /* end of for loop */
749 // while (fNum == 4) {SimpleThread::sleep(10000);} // Force a failure by preventing thread from finishing
754 int32_t fOffset
; // where we are testing from.
757 // ** The actual test function.
759 void MultithreadTest::TestThreadedIntl()
762 UnicodeString theErr
;
763 UBool haveDisplayedInfo
[kFormatThreadThreads
];
764 static const int32_t PATIENCE_SECONDS
= 45;
767 // Create and start the test threads
769 logln("Spawning: %d threads * %d iterations each.",
770 kFormatThreadThreads
, kFormatThreadIterations
);
771 LocalArray
<FormatThreadTest
> tests(new FormatThreadTest
[kFormatThreadThreads
]);
772 for(int32_t j
= 0; j
< kFormatThreadThreads
; j
++) {
774 int32_t threadStatus
= tests
[j
].start();
775 if (threadStatus
!= 0) {
776 errln("System Error %d starting thread number %d.", threadStatus
, j
);
777 SimpleThread::errorFunc();
780 haveDisplayedInfo
[j
] = FALSE
;
784 // Spin, waiting for the test threads to finish.
786 UDate startTime
, endTime
;
787 startTime
= Calendar::getNow();
789 /* Spin until the test threads complete. */
790 stillRunning
= FALSE
;
791 endTime
= Calendar::getNow();
792 if (((int32_t)(endTime
- startTime
)/U_MILLIS_PER_SECOND
) > PATIENCE_SECONDS
) {
793 errln("Patience exceeded. Test is taking too long.");
797 The following sleep must be here because the *BSD operating systems
798 have a brain dead thread scheduler. They starve the child threads from
801 SimpleThread::sleep(1); // yield
802 for(i
=0;i
<kFormatThreadThreads
;i
++) {
803 if (tests
[i
].isRunning()) {
805 } else if (haveDisplayedInfo
[i
] == FALSE
) {
806 logln("Thread # %d is complete..", i
);
807 if(tests
[i
].getError(theErr
)) {
808 dataerrln(UnicodeString("#") + i
+ ": " + theErr
);
809 SimpleThread::errorFunc();
811 haveDisplayedInfo
[i
] = TRUE
;
814 } while (stillRunning
);
817 // All threads have finished.
820 #endif /* #if !UCONFIG_NO_FORMATTING */
826 //-------------------------------------------------------------------------------------------
828 // Collation threading test
830 //-------------------------------------------------------------------------------------------
831 #if !UCONFIG_NO_COLLATION
833 #define kCollatorThreadThreads 10 // # of threads to spawn
834 #define kCollatorThreadPatience kCollatorThreadThreads*30
841 class CollatorThreadTest
: public ThreadWithStatus
844 const UCollator
*coll
;
848 CollatorThreadTest() : ThreadWithStatus(),
854 void setCollator(UCollator
*c
, Line
*l
, int32_t nl
)
864 uint8_t sk1
[1024], sk2
[1024];
865 uint8_t *oldSk
= NULL
, *newSk
= sk1
;
866 int32_t resLen
= 0, oldLen
= 0;
869 for(i
= 0; i
< noLines
; i
++) {
870 resLen
= ucol_getSortKey(coll
, lines
[i
].buff
, lines
[i
].buflen
, newSk
, 1024);
872 int32_t res
= 0, cmpres
= 0, cmpres2
= 0;
875 res
= strcmp((char *)oldSk
, (char *)newSk
);
876 cmpres
= ucol_strcoll(coll
, lines
[i
-1].buff
, lines
[i
-1].buflen
, lines
[i
].buff
, lines
[i
].buflen
);
877 cmpres2
= ucol_strcoll(coll
, lines
[i
].buff
, lines
[i
].buflen
, lines
[i
-1].buff
, lines
[i
-1].buflen
);
881 if(cmpres
!= -cmpres2
) {
882 error("Compare result not symmetrical on line "+ line
);
886 if(((res
&0x80000000) != (cmpres
&0x80000000)) || (res
== 0 && cmpres
!= 0) || (res
!= 0 && cmpres
== 0)) {
887 error(UnicodeString("Difference between ucol_strcoll and sortkey compare on line ")+ UnicodeString(line
));
892 error(UnicodeString("Line %i is not greater or equal than previous line ")+ UnicodeString(i
));
894 } else if(res
== 0) { /* equal */
895 res
= u_strcmpCodePointOrder(lines
[i
-1].buff
, lines
[i
].buff
);
897 error(UnicodeString("Probable error in test file on line %i (comparing identical strings)")+ UnicodeString(i
));
901 * UCA 6.0 test files can have lines that compare == if they are
902 * different strings but canonically equivalent.
904 error(UnicodeString("Sortkeys are identical, but code point compare gives >0 on line ")+ UnicodeString(i));
914 newSk
= (newSk
== sk1
)?sk2
:sk1
;
919 void MultithreadTest::TestCollators()
922 UErrorCode status
= U_ZERO_ERROR
;
923 FILE *testFile
= NULL
;
924 char testDataPath
[1024];
925 strcpy(testDataPath
, IntlTest::getSourceTestData(status
));
926 if (U_FAILURE(status
)) {
927 errln("ERROR: could not open test data %s", u_errorName(status
));
930 strcat(testDataPath
, "CollationTest_");
932 const char* type
= "NON_IGNORABLE";
934 const char *ext
= ".txt";
939 strcpy(buffer
, testDataPath
);
940 strcat(buffer
, type
);
941 size_t bufLen
= strlen(buffer
);
943 // we try to open 3 files:
944 // path/CollationTest_type.txt
945 // path/CollationTest_type_SHORT.txt
946 // path/CollationTest_type_STUB.txt
947 // we are going to test with the first one that we manage to open.
949 strcpy(buffer
+bufLen
, ext
);
951 testFile
= fopen(buffer
, "rb");
954 strcpy(buffer
+bufLen
, "_SHORT");
956 testFile
= fopen(buffer
, "rb");
959 strcpy(buffer
+bufLen
, "_STUB");
961 testFile
= fopen(buffer
, "rb");
964 *(buffer
+bufLen
) = 0;
965 dataerrln("could not open any of the conformance test files, tried opening base %s", buffer
);
969 "INFO: Working with the stub file.\n"
970 "If you need the full conformance test, please\n"
971 "download the appropriate data files from:\n"
972 "http://source.icu-project.org/repos/icu/tools/trunk/unicodetools/com/ibm/text/data/");
977 Line
*lines
= new Line
[200000];
978 memset(lines
, 0, sizeof(Line
)*200000);
986 while (fgets(buffer
, 1024, testFile
) != NULL
) {
988 if(*buffer
== 0 || strlen(buffer
) < 3 || buffer
[0] == '#') {
991 offset
= u_parseString(buffer
, bufferU
, 1024, &first
, &status
);
993 bufferU
[offset
++] = 0;
994 lines
[lineNum
].buflen
= buflen
;
995 //lines[lineNum].buff = new UChar[buflen+1];
996 u_memcpy(lines
[lineNum
].buff
, bufferU
, buflen
);
1000 if(U_FAILURE(status
)) {
1001 dataerrln("Couldn't read the test file!");
1005 UCollator
*coll
= ucol_open("root", &status
);
1006 if(U_FAILURE(status
)) {
1007 errcheckln(status
, "Couldn't open UCA collator");
1010 ucol_setAttribute(coll
, UCOL_NORMALIZATION_MODE
, UCOL_ON
, &status
);
1011 ucol_setAttribute(coll
, UCOL_CASE_FIRST
, UCOL_OFF
, &status
);
1012 ucol_setAttribute(coll
, UCOL_CASE_LEVEL
, UCOL_OFF
, &status
);
1013 ucol_setAttribute(coll
, UCOL_STRENGTH
, UCOL_TERTIARY
, &status
);
1014 ucol_setAttribute(coll
, UCOL_ALTERNATE_HANDLING
, UCOL_NON_IGNORABLE
, &status
);
1016 int32_t noSpawned
= 0;
1017 int32_t spawnResult
= 0;
1018 LocalArray
<CollatorThreadTest
> tests(new CollatorThreadTest
[kCollatorThreadThreads
]);
1020 logln(UnicodeString("Spawning: ") + kCollatorThreadThreads
+ " threads * " + kFormatThreadIterations
+ " iterations each.");
1022 for(j
= 0; j
< kCollatorThreadThreads
; j
++) {
1023 //logln("Setting collator %i", j);
1024 tests
[j
].setCollator(coll
, lines
, lineNum
);
1026 for(j
= 0; j
< kCollatorThreadThreads
; j
++) {
1028 spawnResult
= tests
[j
].start();
1029 if(spawnResult
!= 0) {
1030 infoln("THREAD INFO: Couldn't spawn more than %i threads", noSpawned
);
1035 logln("Spawned all");
1036 if (noSpawned
== 0) {
1037 errln("No threads could be spawned.");
1041 for(int32_t patience
= kCollatorThreadPatience
;patience
> 0; patience
--)
1043 logln("Waiting...");
1047 int32_t completed
=0;
1049 for(i
=0;i
<kCollatorThreadThreads
;i
++)
1051 if (tests
[i
].isRunning() == FALSE
)
1055 //logln(UnicodeString("Test #") + i + " is complete.. ");
1057 UnicodeString theErr
;
1058 if(tests
[i
].getError(theErr
))
1061 errln(UnicodeString("#") + i
+ ": " + theErr
);
1063 // print out the error, too, if any.
1066 logln("Completed %i tests", completed
);
1068 if(completed
== noSpawned
)
1070 logln("Done! All %i tests are finished", noSpawned
);
1074 errln("There were errors.");
1075 SimpleThread::errorFunc();
1078 //for(i = 0; i < lineNum; i++) {
1079 //delete[] lines[i].buff;
1086 SimpleThread::sleep(900);
1088 errln("patience exceeded. ");
1089 SimpleThread::errorFunc();
1093 #endif /* #if !UCONFIG_NO_COLLATION */
1098 //-------------------------------------------------------------------------------------------
1100 // StringThreadTest2
1102 //-------------------------------------------------------------------------------------------
1104 const int kStringThreadIterations
= 2500;// # of iterations per thread
1105 const int kStringThreadThreads
= 10; // # of threads to spawn
1106 const int kStringThreadPatience
= 120; // time in seconds to wait for all threads
1109 class StringThreadTest2
: public ThreadWithStatus
1114 const UnicodeString
*fSharedString
;
1116 StringThreadTest2(const UnicodeString
*sharedString
, int num
) // constructor is NOT multithread safe.
1117 : ThreadWithStatus(),
1120 fSharedString(sharedString
)
1130 for (loopCount
= 0; loopCount
< kStringThreadIterations
; loopCount
++) {
1131 if (*fSharedString
!= "This is the original test string.") {
1132 error("Original string is corrupt.");
1135 UnicodeString s1
= *fSharedString
;
1137 UnicodeString
s2(s1
);
1138 UnicodeString s3
= *fSharedString
;
1144 // while (fNum == 4) {SimpleThread::sleep(10000);} // Force a failure by preventing thread from finishing
1150 // ** The actual test function.
1152 void MultithreadTest::TestString()
1158 UnicodeString
*testString
= new UnicodeString("This is the original test string.");
1160 // Not using LocalArray<StringThreadTest2> tests[kStringThreadThreads];
1161 // because we don't always want to delete them.
1162 // See the comments below the cleanupAndReturn label.
1163 StringThreadTest2
*tests
[kStringThreadThreads
];
1164 for(j
= 0; j
< kStringThreadThreads
; j
++) {
1165 tests
[j
] = new StringThreadTest2(testString
, j
);
1168 logln(UnicodeString("Spawning: ") + kStringThreadThreads
+ " threads * " + kStringThreadIterations
+ " iterations each.");
1169 for(j
= 0; j
< kStringThreadThreads
; j
++) {
1170 int32_t threadStatus
= tests
[j
]->start();
1171 if (threadStatus
!= 0) {
1172 errln("System Error %d starting thread number %d.", threadStatus
, j
);
1173 SimpleThread::errorFunc();
1174 goto cleanupAndReturn
;
1178 for(patience
= kStringThreadPatience
;patience
> 0; patience
--)
1180 logln("Waiting...");
1184 int32_t completed
=0;
1186 for(i
=0;i
<kStringThreadThreads
;i
++) {
1187 if (tests
[i
]->isRunning() == FALSE
)
1191 logln(UnicodeString("Test #") + i
+ " is complete.. ");
1193 UnicodeString theErr
;
1194 if(tests
[i
]->getError(theErr
))
1197 errln(UnicodeString("#") + i
+ ": " + theErr
);
1199 // print out the error, too, if any.
1203 if(completed
== kStringThreadThreads
)
1207 errln("There were errors.");
1212 SimpleThread::sleep(900);
1215 if (patience
<= 0) {
1216 errln("patience exceeded. ");
1217 // while (TRUE) {SimpleThread::sleep(10000);} // TODO: for debugging. Sleep forever on failure.
1222 SimpleThread::errorFunc();
1228 Don't clean up if there are errors. This prevents crashes if the
1229 threads are still running and using this data. This will only happen
1230 if there is an error with the test, ICU, or the machine is too slow.
1231 It's better to leak than crash.
1233 for(j
= 0; j
< kStringThreadThreads
; j
++) {
1240 #endif // ICU_USE_THREADS