1 /********************************************************************
3 * Copyright (c) 1999-2014, 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"
30 #include "unicode/translit.h"
31 #include "sharedobject.h"
32 #include "unifiedcache.h"
35 #if U_PLATFORM_USES_ONLY_WIN32_API
36 /* Prefer native Windows APIs even if POSIX is implemented (i.e., on Cygwin). */
38 #elif U_PLATFORM_IMPLEMENTS_POSIX
44 /* Needed by z/OS to get usleep */
45 #if U_PLATFORM == U_PF_OS390
57 #if (ICU_USE_THREADS == 1)
61 #if defined(__hpux) && defined(HPUX_CMA)
62 # if defined(read) // read being defined as cma_read causes trouble with iostream::read
67 /* Define __EXTENSIONS__ for Solaris and old friends in strict mode. */
68 #ifndef __EXTENSIONS__
69 #define __EXTENSIONS__
72 #if U_PLATFORM == U_PF_OS390
73 #include <sys/types.h>
76 #if U_PLATFORM != U_PF_OS390
80 /* Define _XPG4_2 for Solaris and friends. */
85 /* Define __USE_XOPEN_EXTENDED for Linux and glibc. */
86 #ifndef __USE_XOPEN_EXTENDED
87 #define __USE_XOPEN_EXTENDED
90 /* Define _INCLUDE_XOPEN_SOURCE_EXTENDED for HP/UX (11?). */
91 #ifndef _INCLUDE_XOPEN_SOURCE_EXTENDED
92 #define _INCLUDE_XOPEN_SOURCE_EXTENDED
103 #define TSMTHREAD_FAIL(msg) errln("%s at file %s, line %d", msg, __FILE__, __LINE__)
104 #define TSMTHREAD_ASSERT(expr) {if (!(expr)) {TSMTHREAD_FAIL("Fail");}}
106 MultithreadTest::MultithreadTest()
110 MultithreadTest::~MultithreadTest()
116 #if (ICU_USE_THREADS==0)
117 void MultithreadTest::runIndexedTest( int32_t index
, UBool exec
,
118 const char* &name
, char* /*par*/ ) {
119 if (exec
) logln("TestSuite MultithreadTest: ");
122 name
= "NO_THREADED_TESTS";
126 if(exec
) { logln("MultithreadTest - test DISABLED. ICU_USE_THREADS set to 0, check your configuration if this is a problem..");
133 #include <ctype.h> // tolower, toupper
135 #include "unicode/putil.h"
138 #include "unicode/numfmt.h"
139 #include "unicode/choicfmt.h"
140 #include "unicode/msgfmt.h"
141 #include "unicode/locid.h"
142 #include "unicode/coll.h"
143 #include "unicode/calendar.h"
146 void SimpleThread::errorFunc() {
147 // *(char *)0 = 3; // Force entry into a debugger via a crash;
150 void MultithreadTest::runIndexedTest( int32_t index
, UBool exec
,
151 const char* &name
, char* /*par*/ ) {
153 logln("TestSuite MultithreadTest: ");
156 name
= "TestThreads";
168 name
= "TestThreadedIntl";
169 #if !UCONFIG_NO_FORMATTING
177 name
= "TestCollators";
178 #if !UCONFIG_NO_COLLATION
182 #endif /* #if !UCONFIG_NO_COLLATION */
193 name
= "TestArabicShapingThreads";
195 TestArabicShapingThreads();
200 name
= "TestAnyTranslit";
207 name
= "TestConditionVariables";
209 TestConditionVariables();
213 name
= "TestUnifiedCache";
220 break; //needed to end loop
225 //-----------------------------------------------------------------------------------
227 // TestThreads -- see if threads really work at all.
229 // Set up N threads pointing at N chars. When they are started, they will
230 // each sleep 1 second and then set their chars. At the end we make sure they
233 //-----------------------------------------------------------------------------------
234 #define THREADTEST_NRTHREADS 8
235 #define ARABICSHAPE_THREADTEST 30
237 class TestThreadsThread
: public SimpleThread
240 TestThreadsThread(char* whatToChange
) { fWhatToChange
= whatToChange
; }
241 virtual void run() { SimpleThread::sleep(1000);
243 *fWhatToChange
= '*';
248 //-----------------------------------------------------------------------------------
250 // TestArabicShapeThreads -- see if calls to u_shapeArabic in many threads works successfully
252 // Set up N threads pointing at N chars. When they are started, they will make calls to doTailTest which tests
253 // u_shapeArabic, if the calls are successful it will the set * chars.
254 // At the end we make sure all threads managed to run u_shapeArabic successfully.
255 // This is a unit test for ticket 9473
257 //-----------------------------------------------------------------------------------
258 class TestArabicShapeThreads
: public SimpleThread
261 TestArabicShapeThreads(char* whatToChange
) { fWhatToChange
= whatToChange
;}
263 if(doTailTest()==TRUE
)
264 *fWhatToChange
= '*';
269 UBool
doTailTest(void) {
270 static const UChar src
[] = { 0x0020, 0x0633, 0 };
271 static const UChar dst_old
[] = { 0xFEB1, 0x200B,0 };
272 static const UChar dst_new
[] = { 0xFEB1, 0xFE73,0 };
273 UChar dst
[3] = { 0x0000, 0x0000,0 };
276 IntlTest inteltst
= IntlTest();
278 status
= U_ZERO_ERROR
;
279 length
= u_shapeArabic(src
, -1, dst
, UPRV_LENGTHOF(dst
),
280 U_SHAPE_LETTERS_SHAPE
|U_SHAPE_SEEN_TWOCELL_NEAR
, &status
);
281 if(U_FAILURE(status
)) {
282 inteltst
.errln("Fail: status %s\n", u_errorName(status
));
284 } else if(length
!=2) {
285 inteltst
.errln("Fail: len %d expected 3\n", length
);
287 } else if(u_strncmp(dst
,dst_old
,UPRV_LENGTHOF(dst
))) {
288 inteltst
.errln("Fail: got U+%04X U+%04X expected U+%04X U+%04X\n",
289 dst
[0],dst
[1],dst_old
[0],dst_old
[1]);
295 status
= U_ZERO_ERROR
;
296 length
= u_shapeArabic(src
, -1, dst
, UPRV_LENGTHOF(dst
),
297 U_SHAPE_LETTERS_SHAPE
|U_SHAPE_SEEN_TWOCELL_NEAR
|U_SHAPE_TAIL_NEW_UNICODE
, &status
);
298 if(U_FAILURE(status
)) {
299 inteltst
.errln("Fail: status %s\n", u_errorName(status
));
301 } else if(length
!=2) {
302 inteltst
.errln("Fail: len %d expected 3\n", length
);
304 } else if(u_strncmp(dst
,dst_new
,UPRV_LENGTHOF(dst
))) {
305 inteltst
.errln("Fail: got U+%04X U+%04X expected U+%04X U+%04X\n",
306 dst
[0],dst
[1],dst_new
[0],dst_new
[1]);
318 void MultithreadTest::TestThreads()
320 char threadTestChars
[THREADTEST_NRTHREADS
+ 1];
321 SimpleThread
*threads
[THREADTEST_NRTHREADS
];
322 int32_t numThreadsStarted
= 0;
325 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
327 threadTestChars
[i
] = ' ';
328 threads
[i
] = new TestThreadsThread(&threadTestChars
[i
]);
330 threadTestChars
[THREADTEST_NRTHREADS
] = '\0';
332 logln("->" + UnicodeString(threadTestChars
) + "<- Firing off threads.. ");
333 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
335 if (threads
[i
]->start() != 0) {
336 errln("Error starting thread %d", i
);
341 SimpleThread::sleep(100);
342 logln(" Subthread started.");
345 logln("Waiting for threads to be set..");
346 if (numThreadsStarted
== 0) {
347 errln("No threads could be started for testing!");
351 int32_t patience
= 40; // seconds to wait
357 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
359 if(threadTestChars
[i
] == '*')
366 if(count
== THREADTEST_NRTHREADS
)
368 logln("->" + UnicodeString(threadTestChars
) + "<- Got all threads! cya");
369 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
376 logln("->" + UnicodeString(threadTestChars
) + "<- Waiting..");
377 SimpleThread::sleep(500);
380 errln("->" + UnicodeString(threadTestChars
) + "<- PATIENCE EXCEEDED!! Still missing some.");
381 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
388 void MultithreadTest::TestArabicShapingThreads()
390 char threadTestChars
[ARABICSHAPE_THREADTEST
+ 1];
391 SimpleThread
*threads
[ARABICSHAPE_THREADTEST
];
392 int32_t numThreadsStarted
= 0;
396 for(i
=0;i
<ARABICSHAPE_THREADTEST
;i
++)
398 threadTestChars
[i
] = ' ';
399 threads
[i
] = new TestArabicShapeThreads(&threadTestChars
[i
]);
401 threadTestChars
[ARABICSHAPE_THREADTEST
] = '\0';
403 logln("-> do TestArabicShapingThreads <- Firing off threads.. ");
404 for(i
=0;i
<ARABICSHAPE_THREADTEST
;i
++)
406 if (threads
[i
]->start() != 0) {
407 errln("Error starting thread %d", i
);
412 //SimpleThread::sleep(100);
413 logln(" Subthread started.");
416 logln("Waiting for threads to be set..");
417 if (numThreadsStarted
== 0) {
418 errln("No threads could be started for testing!");
422 int32_t patience
= 100; // seconds to wait
428 for(i
=0;i
<ARABICSHAPE_THREADTEST
;i
++)
430 if(threadTestChars
[i
] == '*')
437 if(count
== ARABICSHAPE_THREADTEST
)
439 logln("->TestArabicShapingThreads <- Got all threads! cya");
440 for(i
=0;i
<ARABICSHAPE_THREADTEST
;i
++)
447 logln("-> TestArabicShapingThreads <- Waiting..");
448 SimpleThread::sleep(500);
451 errln("-> TestArabicShapingThreads <- PATIENCE EXCEEDED!! Still missing some.");
452 for(i
=0;i
<ARABICSHAPE_THREADTEST
;i
++)
460 //-----------------------------------------------------------------------
462 // TestMutex - a simple (non-stress) test to verify that ICU mutexes
463 // are actually mutexing. Does not test the use of
464 // mutexes within ICU services, but rather that the
465 // platform's mutex support is at least superficially there.
467 //----------------------------------------------------------------------
468 static UMutex gTestMutexA
= U_MUTEX_INITIALIZER
;
469 static UMutex gTestMutexB
= U_MUTEX_INITIALIZER
;
471 static int gThreadsStarted
= 0;
472 static int gThreadsInMiddle
= 0;
473 static int gThreadsDone
= 0;
475 static const int TESTMUTEX_THREAD_COUNT
= 4;
477 static int safeIncr(int &var
, int amt
) {
478 // Thread safe (using global mutex) increment of a variable.
479 // Return the updated value.
480 // Can also be used as a safe load of a variable by incrementing it by 0.
486 class TestMutexThread
: public SimpleThread
491 // This is the code that each of the spawned threads runs.
492 // All of the spawned threads bunch up together at each of the two mutexes
493 // because the main holds the mutexes until they do.
495 safeIncr(gThreadsStarted
, 1);
496 umtx_lock(&gTestMutexA
);
497 umtx_unlock(&gTestMutexA
);
498 safeIncr(gThreadsInMiddle
, 1);
499 umtx_lock(&gTestMutexB
);
500 umtx_unlock(&gTestMutexB
);
501 safeIncr(gThreadsDone
, 1);
505 void MultithreadTest::TestMutex()
507 // Start up the test threads. They should all pile up waiting on
508 // gTestMutexA, which we (the main thread) hold until the test threads
511 gThreadsInMiddle
= 0;
513 umtx_lock(&gTestMutexA
);
514 TestMutexThread
*threads
[TESTMUTEX_THREAD_COUNT
];
516 int32_t numThreadsStarted
= 0;
517 for (i
=0; i
<TESTMUTEX_THREAD_COUNT
; i
++) {
518 threads
[i
] = new TestMutexThread
;
519 if (threads
[i
]->start() != 0) {
520 errln("Error starting thread %d", i
);
526 if (numThreadsStarted
== 0) {
527 errln("No threads could be started for testing!");
532 while (safeIncr(gThreadsStarted
, 0) != TESTMUTEX_THREAD_COUNT
) {
533 if (patience
++ > 24) {
534 TSMTHREAD_FAIL("Patience Exceeded");
537 SimpleThread::sleep(500);
539 // None of the test threads should have advanced past the first mutex.
540 TSMTHREAD_ASSERT(gThreadsInMiddle
==0);
541 TSMTHREAD_ASSERT(gThreadsDone
==0);
543 // All of the test threads have made it to the first mutex.
544 // We (the main thread) now let them advance to the second mutex,
545 // where they should all pile up again.
546 umtx_lock(&gTestMutexB
);
547 umtx_unlock(&gTestMutexA
);
550 while (safeIncr(gThreadsInMiddle
, 0) != TESTMUTEX_THREAD_COUNT
) {
551 if (patience
++ > 24) {
552 TSMTHREAD_FAIL("Patience Exceeded");
555 SimpleThread::sleep(500);
557 TSMTHREAD_ASSERT(gThreadsDone
==0);
559 // All test threads made it to the second mutex.
560 // Now let them proceed from there. They will all terminate.
561 umtx_unlock(&gTestMutexB
);
563 while (safeIncr(gThreadsDone
, 0) != TESTMUTEX_THREAD_COUNT
) {
564 if (patience
++ > 24) {
565 TSMTHREAD_FAIL("Patience Exceeded");
568 SimpleThread::sleep(500);
571 // All threads made it by both mutexes.
573 for (i
=0; i
<TESTMUTEX_THREAD_COUNT
; i
++) {
580 //-------------------------------------------------------------------------------------------
582 // class ThreadWithStatus - a thread that we can check the status and error condition of
584 //-------------------------------------------------------------------------------------------
585 class ThreadWithStatus
: public SimpleThread
588 UBool
getError() { return (fErrors
> 0); }
589 UBool
getError(UnicodeString
& fillinError
) { fillinError
= fErrorString
; return (fErrors
> 0); }
590 virtual ~ThreadWithStatus(){}
592 ThreadWithStatus() : fErrors(0) {}
593 void error(const UnicodeString
&error
) {
594 fErrors
++; fErrorString
= error
;
595 SimpleThread::errorFunc();
597 void error() { error("An error occured."); }
600 UnicodeString fErrorString
;
605 //-------------------------------------------------------------------------------------------
607 // TestMultithreadedIntl. Test ICU Formatting n a multi-threaded environment
609 //-------------------------------------------------------------------------------------------
612 // * Show exactly where the string's differences lie.
613 UnicodeString
showDifference(const UnicodeString
& expected
, const UnicodeString
& result
)
616 res
= expected
+ "<Expected\n";
617 if(expected
.length() != result
.length())
618 res
+= " [ Different lengths ] \n";
621 for(int32_t i
=0;i
<expected
.length();i
++)
623 if(expected
[i
] == result
[i
])
632 res
+= "<Differences";
635 res
+= result
+ "<Result\n";
643 //-------------------------------------------------------------------------------------------
645 // FormatThreadTest - a thread that tests performing a number of numberformats.
647 //-------------------------------------------------------------------------------------------
649 const int kFormatThreadIterations
= 100; // # of iterations per thread
650 const int kFormatThreadThreads
= 10; // # of threads to spawn
652 #if !UCONFIG_NO_FORMATTING
656 struct FormatThreadTestData
659 UnicodeString string
;
660 FormatThreadTestData(double a
, const UnicodeString
& b
) : number(a
),string(b
) {}
664 // "Someone from {2} is receiving a #{0} error - {1}. Their telephone call is costing {3 number,currency}."
666 static void formatErrorMessage(UErrorCode
&realStatus
, const UnicodeString
& pattern
, const Locale
& theLocale
,
667 UErrorCode inStatus0
, /* statusString 1 */ const Locale
&inCountry2
, double currency3
, // these numbers are the message arguments.
668 UnicodeString
&result
)
670 if(U_FAILURE(realStatus
))
671 return; // you messed up
673 UnicodeString
errString1(u_errorName(inStatus0
));
675 UnicodeString countryName2
;
676 inCountry2
.getDisplayCountry(theLocale
,countryName2
);
678 Formattable myArgs
[] = {
679 Formattable((int32_t)inStatus0
), // inStatus0 {0}
680 Formattable(errString1
), // statusString1 {1}
681 Formattable(countryName2
), // inCountry2 {2}
682 Formattable(currency3
)// currency3 {3,number,currency}
685 MessageFormat
*fmt
= new MessageFormat("MessageFormat's API is broken!!!!!!!!!!!",realStatus
);
686 fmt
->setLocale(theLocale
);
687 fmt
->applyPattern(pattern
, realStatus
);
689 if (U_FAILURE(realStatus
)) {
694 FieldPosition ignore
= 0;
695 fmt
->format(myArgs
,4,result
,ignore
,realStatus
);
701 * Shared formatters & data used by instances of ThreadSafeFormat.
702 * Exactly one instance of this class is created, and it is then shared concurrently
703 * by the multiple instances of ThreadSafeFormat.
705 class ThreadSafeFormatSharedData
{
707 ThreadSafeFormatSharedData(UErrorCode
&status
);
708 ~ThreadSafeFormatSharedData();
709 LocalPointer
<NumberFormat
> fFormat
;
710 Formattable fYDDThing
;
711 Formattable fBBDThing
;
712 UnicodeString fYDDStr
;
713 UnicodeString fBBDStr
;
716 const ThreadSafeFormatSharedData
*gSharedData
= NULL
;
718 ThreadSafeFormatSharedData::ThreadSafeFormatSharedData(UErrorCode
&status
) {
719 fFormat
.adoptInstead(NumberFormat::createCurrencyInstance(Locale::getUS(), status
));
720 static const UChar kYDD
[] = { 0x59, 0x44, 0x44, 0x00 };
721 static const UChar kBBD
[] = { 0x42, 0x42, 0x44, 0x00 };
722 fYDDThing
.adoptObject(new CurrencyAmount(123.456, kYDD
, status
));
723 fBBDThing
.adoptObject(new CurrencyAmount(987.654, kBBD
, status
));
724 if (U_FAILURE(status
)) {
727 fFormat
->format(fYDDThing
, fYDDStr
, NULL
, status
);
728 fFormat
->format(fBBDThing
, fBBDStr
, NULL
, status
);
732 ThreadSafeFormatSharedData::~ThreadSafeFormatSharedData() {
737 * Class for thread-safe testing of format.
738 * Instances of this class appear as members of class FormatThreadTest.
739 * Multiple instances of FormatThreadTest coexist.
740 * ThreadSafeFormat::doStuff() is called concurrently to test the thread safety of
741 * various shared format operations.
743 class ThreadSafeFormat
{
745 /* give a unique offset to each thread */
746 ThreadSafeFormat(UErrorCode
&status
);
747 UBool
doStuff(int32_t offset
, UnicodeString
&appendErr
, UErrorCode
&status
) const;
749 LocalPointer
<NumberFormat
> fFormat
; // formatter - en_US constructed currency
753 ThreadSafeFormat::ThreadSafeFormat(UErrorCode
&status
) {
754 fFormat
.adoptInstead(NumberFormat::createCurrencyInstance(Locale::getUS(), status
));
757 static const UChar kUSD
[] = { 0x55, 0x53, 0x44, 0x00 };
759 UBool
ThreadSafeFormat::doStuff(int32_t offset
, UnicodeString
&appendErr
, UErrorCode
&status
) const {
762 if(u_strcmp(fFormat
->getCurrency(), kUSD
)) {
763 appendErr
.append("fFormat currency != ")
766 .append(fFormat
->getCurrency())
771 if(u_strcmp(gSharedData
->fFormat
->getCurrency(), kUSD
)) {
772 appendErr
.append("gFormat currency != ")
775 .append(gSharedData
->fFormat
->getCurrency())
780 const UnicodeString
*o
=NULL
;
782 const NumberFormat
*nf
= NULL
; // only operate on it as const.
784 case 0: f
= gSharedData
->fYDDThing
; o
= &gSharedData
->fYDDStr
; nf
= gSharedData
->fFormat
.getAlias(); break;
785 case 1: f
= gSharedData
->fBBDThing
; o
= &gSharedData
->fBBDStr
; nf
= gSharedData
->fFormat
.getAlias(); break;
786 case 2: f
= gSharedData
->fYDDThing
; o
= &gSharedData
->fYDDStr
; nf
= fFormat
.getAlias(); break;
787 case 3: f
= gSharedData
->fBBDThing
; o
= &gSharedData
->fBBDStr
; nf
= fFormat
.getAlias(); break;
789 nf
->format(f
, str
, NULL
, status
);
792 appendErr
.append(showDifference(*o
, str
));
798 UBool U_CALLCONV
isAcceptable(void *, const char *, const char *, const UDataInfo
*) {
802 //static UMTX debugMutex = NULL;
803 //static UMTX gDebugMutex;
806 class FormatThreadTest
: public ThreadWithStatus
812 LocalPointer
<ThreadSafeFormat
> fTSF
;
814 FormatThreadTest() // constructor is NOT multithread safe.
815 : ThreadWithStatus(),
822 UErrorCode status
= U_ZERO_ERROR
; // TODO: rearrange code to allow checking of status.
823 fTSF
.adoptInstead(new ThreadSafeFormat(status
));
824 static int32_t fgOffset
= 0;
833 LocalPointer
<NumberFormat
> percentFormatter
;
834 UErrorCode status
= U_ZERO_ERROR
;
838 for (int i
=0; i
<4000; i
++) {
839 status
= U_ZERO_ERROR
;
840 UDataMemory
*data1
= udata_openChoice(0, "res", "en_US", isAcceptable
, 0, &status
);
841 UDataMemory
*data2
= udata_openChoice(0, "res", "fr", isAcceptable
, 0, &status
);
844 if (U_FAILURE(status
)) {
845 error("udata_openChoice failed.\n");
855 for (m
=0; m
<4000; m
++) {
856 status
= U_ZERO_ERROR
;
857 UResourceBundle
*res
= NULL
;
858 const char *localeName
= NULL
;
860 Locale loc
= Locale::getEnglish();
862 localeName
= loc
.getName();
863 // localeName = "en";
865 // ResourceBundle bund = ResourceBundle(0, loc, status);
866 //umtx_lock(&gDebugMutex);
867 res
= ures_open(NULL
, localeName
, &status
);
868 //umtx_unlock(&gDebugMutex);
870 //umtx_lock(&gDebugMutex);
872 //umtx_unlock(&gDebugMutex);
874 if (U_FAILURE(status
)) {
875 error("Resource bundle construction failed.\n");
882 // Keep this data here to avoid static initialization.
883 FormatThreadTestData kNumberFormatTestData
[] =
885 FormatThreadTestData((double)5.0, UnicodeString("5", "")),
886 FormatThreadTestData( 6.0, UnicodeString("6", "")),
887 FormatThreadTestData( 20.0, UnicodeString("20", "")),
888 FormatThreadTestData( 8.0, UnicodeString("8", "")),
889 FormatThreadTestData( 8.3, UnicodeString("8.3", "")),
890 FormatThreadTestData( 12345, UnicodeString("12,345", "")),
891 FormatThreadTestData( 81890.23, UnicodeString("81,890.23", "")),
893 int32_t kNumberFormatTestDataLength
= UPRV_LENGTHOF(kNumberFormatTestData
);
895 // Keep this data here to avoid static initialization.
896 FormatThreadTestData kPercentFormatTestData
[] =
898 FormatThreadTestData((double)5.0, CharsToUnicodeString("500\\u00a0%")),
899 FormatThreadTestData( 1.0, CharsToUnicodeString("100\\u00a0%")),
900 FormatThreadTestData( 0.26, CharsToUnicodeString("26\\u00a0%")),
901 FormatThreadTestData(
902 16384.99, CharsToUnicodeString("1\\u00a0638\\u00a0499\\u00a0%")), // U+00a0 = NBSP
903 FormatThreadTestData(
904 81890.23, CharsToUnicodeString("8\\u00a0189\\u00a0023\\u00a0%")),
906 int32_t kPercentFormatTestDataLength
= UPRV_LENGTHOF(kPercentFormatTestData
);
909 status
= U_ZERO_ERROR
;
910 LocalPointer
<NumberFormat
> formatter(NumberFormat::createInstance(Locale::getEnglish(),status
));
911 if(U_FAILURE(status
)) {
912 error("Error on NumberFormat::createInstance().");
913 goto cleanupAndReturn
;
916 percentFormatter
.adoptInstead(NumberFormat::createPercentInstance(Locale::getFrench(),status
));
917 if(U_FAILURE(status
)) {
918 error("Error on NumberFormat::createPercentInstance().");
919 goto cleanupAndReturn
;
922 for(iteration
= 0;!getError() && iteration
<kFormatThreadIterations
;iteration
++)
925 int32_t whichLine
= (iteration
+ fOffset
)%kNumberFormatTestDataLength
;
927 UnicodeString output
;
929 formatter
->format(kNumberFormatTestData
[whichLine
].number
, output
);
931 if(0 != output
.compare(kNumberFormatTestData
[whichLine
].string
)) {
932 error("format().. expected " + kNumberFormatTestData
[whichLine
].string
934 goto cleanupAndReturn
;
937 // Now check percent.
939 whichLine
= (iteration
+ fOffset
)%kPercentFormatTestDataLength
;
941 percentFormatter
->format(kPercentFormatTestData
[whichLine
].number
, output
);
942 if(0 != output
.compare(kPercentFormatTestData
[whichLine
].string
))
944 error("percent format().. \n" +
945 showDifference(kPercentFormatTestData
[whichLine
].string
,output
));
946 goto cleanupAndReturn
;
949 // Test message error
950 const int kNumberOfMessageTests
= 3;
951 UErrorCode statusToCheck
;
952 UnicodeString patternToCheck
;
953 Locale messageLocale
;
954 Locale countryToCheck
;
955 double currencyToCheck
;
957 UnicodeString expected
;
960 switch((iteration
+fOffset
) % kNumberOfMessageTests
)
964 statusToCheck
= U_FILE_ACCESS_ERROR
;
965 patternToCheck
= "0:Someone from {2} is receiving a #{0}"
966 " error - {1}. Their telephone call is costing "
967 "{3,number,currency}."; // number,currency
968 messageLocale
= Locale("en","US");
969 countryToCheck
= Locale("","HR");
970 currencyToCheck
= 8192.77;
971 expected
= "0:Someone from Croatia is receiving a #4 error - "
972 "U_FILE_ACCESS_ERROR. Their telephone call is costing $8,192.77.";
975 statusToCheck
= U_INDEX_OUTOFBOUNDS_ERROR
;
976 patternToCheck
= "1:A customer in {2} is receiving a #{0} error - {1}. "
977 "Their telephone call is costing {3,number,currency}."; // number,currency
978 messageLocale
= Locale("de","DE@currency=DEM");
979 countryToCheck
= Locale("","BF");
980 currencyToCheck
= 2.32;
981 expected
= CharsToUnicodeString(
982 "1:A customer in Burkina Faso is receiving a #8 error - U_INDEX_OUTOFBOUNDS_ERROR. "
983 "Their telephone call is costing 2,32\\u00A0DM.");
986 statusToCheck
= U_MEMORY_ALLOCATION_ERROR
;
987 patternToCheck
= "2:user in {2} is receiving a #{0} error - {1}. "
988 "They insist they just spent {3,number,currency} "
989 "on memory."; // number,currency
990 messageLocale
= Locale("de","AT@currency=ATS"); // Austrian German
991 countryToCheck
= Locale("","US"); // hmm
992 currencyToCheck
= 40193.12;
993 expected
= CharsToUnicodeString(
994 "2:user in Vereinigte Staaten is receiving a #7 error"
995 " - U_MEMORY_ALLOCATION_ERROR. They insist they just spent"
996 " \\u00f6S\\u00A040.193,12 on memory.");
1000 UnicodeString result
;
1001 UErrorCode status
= U_ZERO_ERROR
;
1002 formatErrorMessage(status
,patternToCheck
,messageLocale
,statusToCheck
,
1003 countryToCheck
,currencyToCheck
,result
);
1004 if(U_FAILURE(status
))
1006 UnicodeString
tmp(u_errorName(status
));
1007 error("Failure on message format, pattern=" + patternToCheck
+
1008 ", error = " + tmp
);
1009 goto cleanupAndReturn
;
1012 if(result
!= expected
)
1014 error("PatternFormat: \n" + showDifference(expected
,result
));
1015 goto cleanupAndReturn
;
1017 // test the Thread Safe Format
1018 UnicodeString appendErr
;
1019 if(!fTSF
->doStuff(fNum
, appendErr
, status
)) {
1021 goto cleanupAndReturn
;
1023 } /* end of for loop */
1028 // while (fNum == 4) {SimpleThread::sleep(10000);} // Force a failure by preventing thread from finishing
1033 int32_t fOffset
; // where we are testing from.
1036 // ** The actual test function.
1038 void MultithreadTest::TestThreadedIntl()
1041 UnicodeString theErr
;
1042 UBool haveDisplayedInfo
[kFormatThreadThreads
];
1043 static const int32_t PATIENCE_SECONDS
= 45;
1045 UErrorCode threadSafeErr
= U_ZERO_ERROR
;
1047 ThreadSafeFormatSharedData
sharedData(threadSafeErr
);
1048 assertSuccess("initializing ThreadSafeFormat", threadSafeErr
, TRUE
);
1051 // Create and start the test threads
1053 logln("Spawning: %d threads * %d iterations each.",
1054 kFormatThreadThreads
, kFormatThreadIterations
);
1055 LocalArray
<FormatThreadTest
> tests(new FormatThreadTest
[kFormatThreadThreads
]);
1056 for(int32_t j
= 0; j
< kFormatThreadThreads
; j
++) {
1058 int32_t threadStatus
= tests
[j
].start();
1059 if (threadStatus
!= 0) {
1060 errln("System Error %d starting thread number %d.", threadStatus
, j
);
1061 SimpleThread::errorFunc();
1064 haveDisplayedInfo
[j
] = FALSE
;
1068 // Spin, waiting for the test threads to finish.
1070 UDate startTime
, endTime
;
1071 startTime
= Calendar::getNow();
1072 double lastComplaint
= 0;
1074 /* Spin until the test threads complete. */
1075 stillRunning
= FALSE
;
1076 endTime
= Calendar::getNow();
1077 double elapsedSeconds
= ((int32_t)(endTime
- startTime
)/U_MILLIS_PER_SECOND
);
1078 if (elapsedSeconds
> PATIENCE_SECONDS
) {
1079 errln("Patience exceeded. Test is taking too long.");
1081 } else if((elapsedSeconds
-lastComplaint
) > 2.0) {
1082 infoln("%.1f seconds elapsed (still waiting..)", elapsedSeconds
);
1083 lastComplaint
= elapsedSeconds
;
1086 The following sleep must be here because the *BSD operating systems
1087 have a brain dead thread scheduler. They starve the child threads from
1090 SimpleThread::sleep(1); // yield
1091 for(i
=0;i
<kFormatThreadThreads
;i
++) {
1092 if (tests
[i
].isRunning()) {
1093 stillRunning
= TRUE
;
1094 } else if (haveDisplayedInfo
[i
] == FALSE
) {
1095 logln("Thread # %d is complete..", i
);
1096 if(tests
[i
].getError(theErr
)) {
1097 dataerrln(UnicodeString("#") + i
+ ": " + theErr
);
1098 SimpleThread::errorFunc();
1100 haveDisplayedInfo
[i
] = TRUE
;
1103 } while (stillRunning
);
1106 // All threads have finished.
1108 assertSuccess("finalizing ThreadSafeFormat", threadSafeErr
, TRUE
);
1110 #endif /* #if !UCONFIG_NO_FORMATTING */
1116 //-------------------------------------------------------------------------------------------
1118 // Collation threading test
1120 //-------------------------------------------------------------------------------------------
1121 #if !UCONFIG_NO_COLLATION
1123 #define kCollatorThreadThreads 10 // # of threads to spawn
1124 #define kCollatorThreadPatience kCollatorThreadThreads*30
1132 skipLineBecauseOfBug(const UChar
*s
, int32_t length
) {
1133 // TODO: Fix ICU ticket #8052
1135 (s
[0] == 0xfb2 || s
[0] == 0xfb3) &&
1137 (s
[2] == 0xf73 || s
[2] == 0xf75 || s
[2] == 0xf81)) {
1143 static UCollationResult
1144 normalizeResult(int32_t result
) {
1145 return result
<0 ? UCOL_LESS
: result
==0 ? UCOL_EQUAL
: UCOL_GREATER
;
1148 class CollatorThreadTest
: public ThreadWithStatus
1151 const Collator
*coll
;
1154 UBool isAtLeastUCA62
;
1156 CollatorThreadTest() : ThreadWithStatus(),
1160 isAtLeastUCA62(TRUE
)
1163 void setCollator(Collator
*c
, Line
*l
, int32_t nl
, UBool atLeastUCA62
)
1168 isAtLeastUCA62
= atLeastUCA62
;
1170 virtual void run() {
1171 uint8_t sk1
[1024], sk2
[1024];
1172 uint8_t *oldSk
= NULL
, *newSk
= sk1
;
1177 for(i
= 0; i
< noLines
; i
++) {
1178 if(lines
[i
].buflen
== 0) { continue; }
1180 if(skipLineBecauseOfBug(lines
[i
].buff
, lines
[i
].buflen
)) { continue; }
1182 int32_t resLen
= coll
->getSortKey(lines
[i
].buff
, lines
[i
].buflen
, newSk
, 1024);
1185 int32_t skres
= strcmp((char *)oldSk
, (char *)newSk
);
1186 int32_t cmpres
= coll
->compare(lines
[prev
].buff
, lines
[prev
].buflen
, lines
[i
].buff
, lines
[i
].buflen
);
1187 int32_t cmpres2
= coll
->compare(lines
[i
].buff
, lines
[i
].buflen
, lines
[prev
].buff
, lines
[prev
].buflen
);
1189 if(cmpres
!= -cmpres2
) {
1190 error(UnicodeString("Compare result not symmetrical on line ") + (i
+ 1));
1194 if(cmpres
!= normalizeResult(skres
)) {
1195 error(UnicodeString("Difference between coll->compare and sortkey compare on line ") + (i
+ 1));
1199 int32_t res
= cmpres
;
1200 if(res
== 0 && !isAtLeastUCA62
) {
1201 // Up to UCA 6.1, the collation test files use a custom tie-breaker,
1202 // comparing the raw input strings.
1203 res
= u_strcmpCodePointOrder(lines
[prev
].buff
, lines
[i
].buff
);
1204 // Starting with UCA 6.2, the collation test files use the standard UCA tie-breaker,
1205 // comparing the NFD versions of the input strings,
1206 // which we do via setting strength=identical.
1209 error(UnicodeString("Line is not greater or equal than previous line, for line ") + (i
+ 1));
1216 (void)oldLen
; // Suppress set but not used warning.
1219 newSk
= (newSk
== sk1
)?sk2
:sk1
;
1224 void MultithreadTest::TestCollators()
1227 UErrorCode status
= U_ZERO_ERROR
;
1228 FILE *testFile
= NULL
;
1229 char testDataPath
[1024];
1230 strcpy(testDataPath
, IntlTest::getSourceTestData(status
));
1231 if (U_FAILURE(status
)) {
1232 errln("ERROR: could not open test data %s", u_errorName(status
));
1235 strcat(testDataPath
, "CollationTest_");
1237 const char* type
= "NON_IGNORABLE";
1239 const char *ext
= ".txt";
1244 strcpy(buffer
, testDataPath
);
1245 strcat(buffer
, type
);
1246 size_t bufLen
= strlen(buffer
);
1248 // we try to open 3 files:
1249 // path/CollationTest_type.txt
1250 // path/CollationTest_type_SHORT.txt
1251 // path/CollationTest_type_STUB.txt
1252 // we are going to test with the first one that we manage to open.
1254 strcpy(buffer
+bufLen
, ext
);
1256 testFile
= fopen(buffer
, "rb");
1259 strcpy(buffer
+bufLen
, "_SHORT");
1260 strcat(buffer
, ext
);
1261 testFile
= fopen(buffer
, "rb");
1264 strcpy(buffer
+bufLen
, "_STUB");
1265 strcat(buffer
, ext
);
1266 testFile
= fopen(buffer
, "rb");
1268 if (testFile
== 0) {
1269 *(buffer
+bufLen
) = 0;
1270 dataerrln("could not open any of the conformance test files, tried opening base %s", buffer
);
1274 "INFO: Working with the stub file.\n"
1275 "If you need the full conformance test, please\n"
1276 "download the appropriate data files from:\n"
1277 "http://source.icu-project.org/repos/icu/tools/trunk/unicodetools/com/ibm/text/data/");
1282 LocalArray
<Line
> lines(new Line
[200000]);
1283 memset(lines
.getAlias(), 0, sizeof(Line
)*200000);
1284 int32_t lineNum
= 0;
1286 UChar bufferU
[1024];
1289 while (fgets(buffer
, 1024, testFile
) != NULL
) {
1290 if(*buffer
== 0 || buffer
[0] == '#') {
1291 // Store empty and comment lines so that errors are reported
1292 // for the real test file lines.
1293 lines
[lineNum
].buflen
= 0;
1294 lines
[lineNum
].buff
[0] = 0;
1296 int32_t buflen
= u_parseString(buffer
, bufferU
, 1024, &first
, &status
);
1297 lines
[lineNum
].buflen
= buflen
;
1298 u_memcpy(lines
[lineNum
].buff
, bufferU
, buflen
);
1299 lines
[lineNum
].buff
[buflen
] = 0;
1304 if(U_FAILURE(status
)) {
1305 dataerrln("Couldn't read the test file!");
1309 UVersionInfo uniVersion
;
1310 static const UVersionInfo v62
= { 6, 2, 0, 0 };
1311 u_getUnicodeVersion(uniVersion
);
1312 UBool isAtLeastUCA62
= uprv_memcmp(uniVersion
, v62
, 4) >= 0;
1314 LocalPointer
<Collator
> coll(Collator::createInstance(Locale::getRoot(), status
));
1315 if(U_FAILURE(status
)) {
1316 errcheckln(status
, "Couldn't open UCA collator");
1319 coll
->setAttribute(UCOL_NORMALIZATION_MODE
, UCOL_ON
, status
);
1320 coll
->setAttribute(UCOL_CASE_FIRST
, UCOL_OFF
, status
);
1321 coll
->setAttribute(UCOL_CASE_LEVEL
, UCOL_OFF
, status
);
1322 coll
->setAttribute(UCOL_STRENGTH
, isAtLeastUCA62
? UCOL_IDENTICAL
: UCOL_TERTIARY
, status
);
1323 coll
->setAttribute(UCOL_ALTERNATE_HANDLING
, UCOL_NON_IGNORABLE
, status
);
1325 int32_t noSpawned
= 0;
1326 int32_t spawnResult
= 0;
1327 LocalArray
<CollatorThreadTest
> tests(new CollatorThreadTest
[kCollatorThreadThreads
]);
1329 logln(UnicodeString("Spawning: ") + kCollatorThreadThreads
+ " threads * " + kFormatThreadIterations
+ " iterations each.");
1331 for(j
= 0; j
< kCollatorThreadThreads
; j
++) {
1332 //logln("Setting collator %i", j);
1333 tests
[j
].setCollator(coll
.getAlias(), lines
.getAlias(), lineNum
, isAtLeastUCA62
);
1335 for(j
= 0; j
< kCollatorThreadThreads
; j
++) {
1337 spawnResult
= tests
[j
].start();
1338 if(spawnResult
!= 0) {
1339 infoln("THREAD INFO: Couldn't spawn more than %i threads", noSpawned
);
1344 logln("Spawned all");
1345 if (noSpawned
== 0) {
1346 errln("No threads could be spawned.");
1350 for(int32_t patience
= kCollatorThreadPatience
;patience
> 0; patience
--)
1352 logln("Waiting...");
1356 int32_t completed
=0;
1358 for(i
=0;i
<kCollatorThreadThreads
;i
++)
1360 if (tests
[i
].isRunning() == FALSE
)
1364 //logln(UnicodeString("Test #") + i + " is complete.. ");
1366 UnicodeString theErr
;
1367 if(tests
[i
].getError(theErr
))
1370 errln(UnicodeString("#") + i
+ ": " + theErr
);
1372 // print out the error, too, if any.
1375 logln("Completed %i tests", completed
);
1377 if(completed
== noSpawned
)
1379 logln("Done! All %i tests are finished", noSpawned
);
1383 errln("There were errors.");
1384 SimpleThread::errorFunc();
1389 SimpleThread::sleep(900);
1391 errln("patience exceeded. ");
1392 SimpleThread::errorFunc();
1395 #endif /* #if !UCONFIG_NO_COLLATION */
1400 //-------------------------------------------------------------------------------------------
1402 // StringThreadTest2
1404 //-------------------------------------------------------------------------------------------
1406 const int kStringThreadIterations
= 2500;// # of iterations per thread
1407 const int kStringThreadThreads
= 10; // # of threads to spawn
1408 const int kStringThreadPatience
= 120; // time in seconds to wait for all threads
1411 class StringThreadTest2
: public ThreadWithStatus
1416 const UnicodeString
*fSharedString
;
1418 StringThreadTest2(const UnicodeString
*sharedString
, int num
) // constructor is NOT multithread safe.
1419 : ThreadWithStatus(),
1422 fSharedString(sharedString
)
1432 for (loopCount
= 0; loopCount
< kStringThreadIterations
; loopCount
++) {
1433 if (*fSharedString
!= "This is the original test string.") {
1434 error("Original string is corrupt.");
1437 UnicodeString s1
= *fSharedString
;
1439 UnicodeString
s2(s1
);
1440 UnicodeString s3
= *fSharedString
;
1446 // while (fNum == 4) {SimpleThread::sleep(10000);} // Force a failure by preventing thread from finishing
1452 // ** The actual test function.
1454 void MultithreadTest::TestString()
1460 UnicodeString
*testString
= new UnicodeString("This is the original test string.");
1462 // Not using LocalArray<StringThreadTest2> tests[kStringThreadThreads];
1463 // because we don't always want to delete them.
1464 // See the comments below the cleanupAndReturn label.
1465 StringThreadTest2
*tests
[kStringThreadThreads
];
1466 for(j
= 0; j
< kStringThreadThreads
; j
++) {
1467 tests
[j
] = new StringThreadTest2(testString
, j
);
1470 logln(UnicodeString("Spawning: ") + kStringThreadThreads
+ " threads * " + kStringThreadIterations
+ " iterations each.");
1471 for(j
= 0; j
< kStringThreadThreads
; j
++) {
1472 int32_t threadStatus
= tests
[j
]->start();
1473 if (threadStatus
!= 0) {
1474 errln("System Error %d starting thread number %d.", threadStatus
, j
);
1475 SimpleThread::errorFunc();
1476 goto cleanupAndReturn
;
1480 for(patience
= kStringThreadPatience
;patience
> 0; patience
--)
1482 logln("Waiting...");
1486 int32_t completed
=0;
1488 for(i
=0;i
<kStringThreadThreads
;i
++) {
1489 if (tests
[i
]->isRunning() == FALSE
)
1493 logln(UnicodeString("Test #") + i
+ " is complete.. ");
1495 UnicodeString theErr
;
1496 if(tests
[i
]->getError(theErr
))
1499 errln(UnicodeString("#") + i
+ ": " + theErr
);
1501 // print out the error, too, if any.
1505 if(completed
== kStringThreadThreads
)
1509 errln("There were errors.");
1514 SimpleThread::sleep(900);
1517 if (patience
<= 0) {
1518 errln("patience exceeded. ");
1519 // while (TRUE) {SimpleThread::sleep(10000);} // TODO: for debugging. Sleep forever on failure.
1524 SimpleThread::errorFunc();
1530 Don't clean up if there are errors. This prevents crashes if the
1531 threads are still running and using this data. This will only happen
1532 if there is an error with the test, ICU, or the machine is too slow.
1533 It's better to leak than crash.
1535 for(j
= 0; j
< kStringThreadThreads
; j
++) {
1543 // Test for ticket #10673, race in cache code in AnyTransliterator.
1544 // It's difficult to make the original unsafe code actually fail, but
1545 // this test will fairly reliably take the code path for races in
1546 // populating the cache.
1548 #if !UCONFIG_NO_TRANSLITERATION
1549 class TxThread
: public SimpleThread
{
1551 Transliterator
*fSharedTranslit
;
1554 TxThread(Transliterator
*tx
) : fSharedTranslit(tx
), fSuccess(FALSE
) {};
1559 TxThread::~TxThread() {}
1560 void TxThread::run() {
1561 UnicodeString
greekString("\\u03B4\\u03B9\\u03B1\\u03C6\\u03BF\\u03C1\\u03B5\\u03C4\\u03B9\\u03BA\\u03BF\\u03CD\\u03C2");
1562 greekString
= greekString
.unescape();
1563 fSharedTranslit
->transliterate(greekString
);
1564 fSuccess
= greekString
[0] == 0x64; // 'd'. The whole transliterated string is "diaphoretikous" (accented u).
1569 void MultithreadTest::TestAnyTranslit() {
1570 #if !UCONFIG_NO_TRANSLITERATION
1571 UErrorCode status
= U_ZERO_ERROR
;
1572 LocalPointer
<Transliterator
> tx(Transliterator::createInstance("Any-Latin", UTRANS_FORWARD
, status
));
1573 if (U_FAILURE(status
)) {
1574 dataerrln("File %s, Line %d: Error, status = %s", __FILE__
, __LINE__
, u_errorName(status
));
1577 TxThread
* threads
[4];
1579 for (i
=0; i
<4; i
++) {
1580 threads
[i
] = new TxThread(tx
.getAlias());
1582 for (i
=0; i
<4; i
++) {
1583 threads
[i
]->start();
1585 int32_t patience
= 100;
1587 UBool someThreadRunning
;
1589 someThreadRunning
= FALSE
;
1591 for (i
=0; i
<4; i
++) {
1592 if (threads
[i
]->isRunning()) {
1593 someThreadRunning
= TRUE
;
1594 SimpleThread::sleep(10);
1597 if (threads
[i
]->fSuccess
== FALSE
) {
1602 } while (someThreadRunning
&& --patience
> 0);
1604 if (patience
<= 0) {
1605 errln("File %s, Line %d: Error, one or more threads did not complete.", __FILE__
, __LINE__
);
1607 if (success
== FALSE
) {
1608 errln("File %s, Line %d: Error, transliteration result incorrect.", __FILE__
, __LINE__
);
1611 for (i
=0; i
<4; i
++) {
1614 #endif // !UCONFIG_NO_TRANSLITERATION
1618 // Condition Variables Test
1619 // Create a swarm of threads.
1620 // Using a mutex and a condition variables each thread
1621 // Increments a global count of started threads.
1622 // Broadcasts that it has started.
1623 // Waits on the condition that all threads have started.
1624 // Increments a global count of finished threads.
1625 // Waits on the condition that all threads have finished.
1628 class CondThread
: public SimpleThread
{
1630 CondThread() :fFinished(false) {};
1636 static UMutex gCTMutex
= U_MUTEX_INITIALIZER
;
1637 static UConditionVar gCTConditionVar
= U_CONDITION_INITIALIZER
;
1638 int gConditionTestOne
= 1; // Value one. Non-const, extern linkage to inhibit
1639 // compiler assuming a known value.
1640 int gStartedThreads
;
1641 int gFinishedThreads
;
1642 static const int NUMTHREADS
= 10;
1644 static MultithreadTest
*gThisTest
= NULL
; // Make test frame work functions available to
1645 // non-member functions.
1647 // Worker thread function.
1648 void CondThread::run() {
1649 umtx_lock(&gCTMutex
);
1650 gStartedThreads
+= gConditionTestOne
;
1651 umtx_condBroadcast(&gCTConditionVar
);
1653 while (gStartedThreads
< NUMTHREADS
) {
1654 if (gFinishedThreads
!= 0) {
1655 gThisTest
->errln("File %s, Line %d: Error, gStartedThreads = %d, gFinishedThreads = %d",
1656 __FILE__
, __LINE__
, gStartedThreads
, gFinishedThreads
);
1658 umtx_condWait(&gCTConditionVar
, &gCTMutex
);
1661 gFinishedThreads
+= gConditionTestOne
;
1663 umtx_condBroadcast(&gCTConditionVar
);
1665 while (gFinishedThreads
< NUMTHREADS
) {
1666 umtx_condWait(&gCTConditionVar
, &gCTMutex
);
1668 umtx_unlock(&gCTMutex
);
1671 void MultithreadTest::TestConditionVariables() {
1673 gStartedThreads
= 0;
1674 gFinishedThreads
= 0;
1677 umtx_lock(&gCTMutex
);
1678 CondThread
*threads
[NUMTHREADS
];
1679 for (i
=0; i
<NUMTHREADS
; ++i
) {
1680 threads
[i
] = new CondThread
;
1681 threads
[i
]->start();
1684 while (gStartedThreads
< NUMTHREADS
) {
1685 umtx_condWait(&gCTConditionVar
, &gCTMutex
);
1688 while (gFinishedThreads
< NUMTHREADS
) {
1689 umtx_condWait(&gCTConditionVar
, &gCTMutex
);
1692 umtx_unlock(&gCTMutex
);
1694 for (i
=0; i
<NUMTHREADS
; ++i
) {
1695 if (!threads
[i
]->fFinished
) {
1696 errln("File %s, Line %d: Error, threads[%d]->fFinished == false", __FILE__
, __LINE__
, i
);
1702 static const char *gCacheLocales
[] = {"en_US", "en_GB", "fr_FR", "fr"};
1703 static int32_t gObjectsCreated
= 0;
1704 static const int32_t CACHE_LOAD
= 3;
1706 class UCTMultiThreadItem
: public SharedObject
{
1709 UCTMultiThreadItem(const char *x
) : value(NULL
) {
1710 value
= uprv_strdup(x
);
1712 virtual ~UCTMultiThreadItem() {
1720 const UCTMultiThreadItem
*LocaleCacheKey
<UCTMultiThreadItem
>::createObject(
1721 const void * /*unused*/, UErrorCode
& /* status */) const {
1722 // Since multiple threads are hitting the cache for the first time,
1723 // no objects should be created yet.
1724 umtx_lock(&gCTMutex
);
1725 if (gObjectsCreated
!= 0) {
1726 gThisTest
->errln("Expected no objects to be created yet.");
1728 umtx_unlock(&gCTMutex
);
1730 // Big, expensive object that takes 1 second to create.
1731 SimpleThread::sleep(1000);
1733 // Log that we created an object.
1734 umtx_lock(&gCTMutex
);
1736 umtx_unlock(&gCTMutex
);
1737 UCTMultiThreadItem
*result
= new UCTMultiThreadItem(fLoc
.getName());
1744 class UnifiedCacheThread
: public SimpleThread
{
1746 UnifiedCacheThread(const char *loc
) : fLoc(loc
) {};
1747 ~UnifiedCacheThread() {};
1752 void UnifiedCacheThread::run() {
1753 UErrorCode status
= U_ZERO_ERROR
;
1754 const UnifiedCache
*cache
= UnifiedCache::getInstance(status
);
1755 U_ASSERT(status
== U_ZERO_ERROR
);
1756 const UCTMultiThreadItem
*item
= NULL
;
1757 cache
->get(LocaleCacheKey
<UCTMultiThreadItem
>(fLoc
), item
, status
);
1758 U_ASSERT(item
!= NULL
);
1759 if (uprv_strcmp(fLoc
, item
->value
)) {
1760 gThisTest
->errln("Expected %s, got %s", fLoc
, item
->value
);
1764 // Mark this thread as finished
1765 umtx_lock(&gCTMutex
);
1767 umtx_condBroadcast(&gCTConditionVar
);
1768 umtx_unlock(&gCTMutex
);
1771 void MultithreadTest::TestUnifiedCache() {
1772 UErrorCode status
= U_ZERO_ERROR
;
1773 const UnifiedCache
*cache
= UnifiedCache::getInstance(status
);
1774 U_ASSERT(cache
!= NULL
);
1777 gFinishedThreads
= 0;
1778 gObjectsCreated
= 0;
1780 UnifiedCacheThread
*threads
[CACHE_LOAD
][UPRV_LENGTHOF(gCacheLocales
)];
1781 for (int32_t i
=0; i
<CACHE_LOAD
; ++i
) {
1782 for (int32_t j
=0; j
<UPRV_LENGTHOF(gCacheLocales
); ++j
) {
1783 threads
[i
][j
] = new UnifiedCacheThread(gCacheLocales
[j
]);
1784 threads
[i
][j
]->start();
1787 // Wait on all the threads to complete verify that LENGTHOF(gCacheLocales)
1788 // objects were created.
1789 umtx_lock(&gCTMutex
);
1790 while (gFinishedThreads
< CACHE_LOAD
*UPRV_LENGTHOF(gCacheLocales
)) {
1791 umtx_condWait(&gCTConditionVar
, &gCTMutex
);
1793 assertEquals("Objects created", UPRV_LENGTHOF(gCacheLocales
), gObjectsCreated
);
1794 umtx_unlock(&gCTMutex
);
1797 for (int32_t i
=0; i
<CACHE_LOAD
; ++i
) {
1798 for (int32_t j
=0; j
<UPRV_LENGTHOF(gCacheLocales
); ++j
) {
1799 delete threads
[i
][j
];
1804 #endif // ICU_USE_THREADS