1 /********************************************************************
3 * Copyright (c) 1999-2008, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ********************************************************************/
8 # ifndef _INCLUDE_POSIX_SOURCE
9 # define _INCLUDE_POSIX_SOURCE
13 /* Needed by z/OS to get usleep */
14 #if !defined(_XOPEN_SOURCE_EXTENDED)
15 #define _XOPEN_SOURCE_EXTENDED 1
18 #include "unicode/utypes.h"
19 #include "unicode/ustring.h"
24 #include "unicode/resbund.h"
25 #include "unicode/udata.h"
26 #include "unicode/uloc.h"
27 #include "unicode/locid.h"
29 #if !defined(U_WINDOWS) && !defined(XP_MAC) && !defined(U_RHAPSODY)
33 #if defined(POSIX) || defined(U_SOLARIS) || defined(U_AIX) || defined(U_HPUX)
37 #if (ICU_USE_THREADS == 1)
41 #if defined(__hpux) && defined(HPUX_CMA)
42 # if defined(read) // read being defined as cma_read causes trouble with iostream::read
47 /* Define __EXTENSIONS__ for Solaris and old friends in strict mode. */
48 #ifndef __EXTENSIONS__
49 #define __EXTENSIONS__
54 /* Define _XPG4_2 for Solaris and friends. */
59 /* Define __USE_XOPEN_EXTENDED for Linux and glibc. */
60 #ifndef __USE_XOPEN_EXTENDED
61 #define __USE_XOPEN_EXTENDED
64 /* Define _INCLUDE_XOPEN_SOURCE_EXTENDED for HP/UX (11?). */
65 #ifndef _INCLUDE_XOPEN_SOURCE_EXTENDED
66 #define _INCLUDE_XOPEN_SOURCE_EXTENDED
81 #define TSMTHREAD_FAIL(msg) errln("%s at file %s, line %d", msg, __FILE__, __LINE__)
82 #define TSMTHREAD_ASSERT(expr) {if (!(expr)) {TSMTHREAD_FAIL("Fail");}}
84 MultithreadTest::MultithreadTest()
88 MultithreadTest::~MultithreadTest()
94 #if (ICU_USE_THREADS==0)
95 void MultithreadTest::runIndexedTest( int32_t index
, UBool exec
,
96 const char* &name
, char* /*par*/ ) {
97 if (exec
) logln("TestSuite MultithreadTest: ");
100 name
= "NO_THREADED_TESTS";
104 if(exec
) { logln("MultithreadTest - test DISABLED. ICU_USE_THREADS set to 0, check your configuration if this is a problem..");
111 // Note: A LOT OF THE FUNCTIONS IN THIS FILE SHOULD LIVE ELSEWHERE!!!!!
112 // Note: A LOT OF THE FUNCTIONS IN THIS FILE SHOULD LIVE ELSEWHERE!!!!!
117 #include <ctype.h> // tolower, toupper
119 #include "unicode/putil.h"
122 #include "unicode/numfmt.h"
123 #include "unicode/choicfmt.h"
124 #include "unicode/msgfmt.h"
125 #include "unicode/locid.h"
126 #include "unicode/ucol.h"
127 #include "unicode/calendar.h"
130 //-----------------------------------------------------------------------------------
132 // class SimpleThread Of course we need a thread class first..
133 // This wrapper has a ported implementation.
135 //-----------------------------------------------------------------------------------
140 virtual ~SimpleThread();
141 int32_t start(void); // start the thread
142 UBool
isRunning(); // return true if a started thread has exited.
144 virtual void run(void) = 0; // Override this to provide the code to run
146 void *fImplementation
;
149 static void sleep(int32_t millis
); // probably shouldn't go here but oh well.
150 static void errorFunc(); // Empty function, provides a single convenient place
151 // to break on errors.
154 void SimpleThread::errorFunc() {
155 // *(char *)0 = 3; // Force entry into a debugger via a crash;
164 # define VC_EXTRALEAN
165 # define WIN32_LEAN_AND_MEAN
175 //-----------------------------------------------------------------------------------
177 // class SimpleThread Windows Implementation
179 //-----------------------------------------------------------------------------------
180 struct Win32ThreadImplementation
183 unsigned int fThreadID
;
187 extern "C" unsigned int __stdcall
SimpleThreadProc(void *arg
)
189 ((SimpleThread
*)arg
)->run();
193 SimpleThread::SimpleThread()
196 Win32ThreadImplementation
*imp
= new Win32ThreadImplementation
;
198 fImplementation
= imp
;
201 SimpleThread::~SimpleThread()
203 // Destructor. Because we start the thread running with _beginthreadex(),
204 // we own the Windows HANDLE for the thread and must
206 Win32ThreadImplementation
*imp
= (Win32ThreadImplementation
*)fImplementation
;
208 if (imp
->fHandle
!= 0) {
209 CloseHandle(imp
->fHandle
);
213 delete (Win32ThreadImplementation
*)fImplementation
;
216 int32_t SimpleThread::start()
218 Win32ThreadImplementation
*imp
= (Win32ThreadImplementation
*)fImplementation
;
219 if(imp
->fHandle
!= NULL
) {
220 // The thread appears to have already been started.
221 // This is probably an error on the part of our caller.
225 imp
->fHandle
= (HANDLE
) _beginthreadex(
227 0x20000, // Stack Size
228 SimpleThreadProc
, // Function to Run
229 (void *)this, // Arg List
230 0, // initflag. Start running, not suspended
231 &imp
->fThreadID
// thraddr
234 if (imp
->fHandle
== 0) {
246 UBool
SimpleThread::isRunning() {
248 // Test whether the thread associated with the SimpleThread object is
249 // still actually running.
251 // NOTE: on Win64 on Itanium processors, a crashes
252 // occur if the main thread of a process exits concurrently with some
253 // other thread(s) exiting. To avoid the possibility, we wait until the
254 // OS indicates that all threads have terminated, rather than waiting
255 // only until the end of the user's Run function has been reached.
257 // I don't know whether the crashes represent a Windows bug, or whether
258 // main() programs are supposed to have to wait for their threads.
260 Win32ThreadImplementation
*imp
= (Win32ThreadImplementation
*)fImplementation
;
263 DWORD threadExitCode
;
265 if (imp
->fHandle
== 0) {
266 // No handle, thread must not be running.
269 success
= GetExitCodeThread(imp
->fHandle
, &threadExitCode
) != 0;
271 // Can't get status, thread must not be running.
274 return (threadExitCode
== STILL_ACTIVE
);
278 void SimpleThread::sleep(int32_t millis
)
283 //-----------------------------------------------------------------------------------
285 // class SimpleThread NULL Implementation
287 //-----------------------------------------------------------------------------------
290 // since the Mac has no preemptive threading (at least on MacOS 8), only
291 // cooperative threading, threads are a no-op. We have no yield() calls
292 // anywhere in the ICU, so we are guaranteed to be thread-safe.
296 SimpleThread::SimpleThread()
299 SimpleThread::~SimpleThread()
303 SimpleThread::start()
311 SimpleThread::sleep(int32_t millis
)
315 SimpleThread::isRunning() {
322 //-----------------------------------------------------------------------------------
324 // class SimpleThread POSIX implementation
326 // A note on the POSIX vs the Windows implementations of this class..
327 // On Windows, the main thread must verify that other threads have finished
328 // before exiting, or crashes occasionally occur. (Seen on Itanium Win64 only)
329 // The function SimpleThread::isRunning() is used for this purpose.
331 // On POSIX, there is NO reliable non-blocking mechanism to determine
332 // whether a thread has exited. pthread_kill(thread, 0) almost works,
333 // but the system can recycle thread ids immediately, so seeing that a
334 // thread exists with this call could mean that the original thread has
335 // finished and a new one started with the same ID. Useless.
337 // So we need to do the check with user code, by setting a flag just before
338 // the thread function returns. A technique that is guaranteed to fail
339 // on Windows, because it indicates that the thread is done before all
340 // system level cleanup has happened.
342 //-----------------------------------------------------------------------------------
343 #if defined(POSIX)||defined(U_SOLARIS)||defined(U_AIX)||defined(U_HPUX)
346 struct PosixThreadImplementation
350 UBool fRan
; /* True if the thread was successfully started */
353 extern "C" void* SimpleThreadProc(void *arg
)
355 // This is the code that is run in the new separate thread.
356 SimpleThread
*This
= (SimpleThread
*)arg
;
357 This
->run(); // Run the user code.
359 // The user function has returned. Set the flag indicating that this thread
360 // is done. Need a mutex for memory barrier purposes only, so that other thread
361 // will reliably see that the flag has changed.
362 PosixThreadImplementation
*imp
= (PosixThreadImplementation
*)This
->fImplementation
;
364 imp
->fRunning
= FALSE
;
369 SimpleThread::SimpleThread()
371 PosixThreadImplementation
*imp
= new PosixThreadImplementation
;
372 imp
->fRunning
= FALSE
;
374 fImplementation
= imp
;
377 SimpleThread::~SimpleThread()
379 PosixThreadImplementation
*imp
= (PosixThreadImplementation
*)fImplementation
;
381 pthread_join(imp
->fThread
, NULL
);
384 fImplementation
= (void *)0xdeadbeef;
387 int32_t SimpleThread::start()
390 static pthread_attr_t attr
;
391 static UBool attrIsInitialized
= FALSE
;
393 PosixThreadImplementation
*imp
= (PosixThreadImplementation
*)fImplementation
;
394 imp
->fRunning
= TRUE
;
398 if (attrIsInitialized
== FALSE
) {
399 rc
= pthread_attr_create(&attr
);
400 attrIsInitialized
= TRUE
;
402 rc
= pthread_create(&(imp
->fThread
),attr
,&SimpleThreadProc
,(void*)this);
404 if (attrIsInitialized
== FALSE
) {
405 rc
= pthread_attr_init(&attr
);
408 int detachstate
= 0; /* jdc30: detach state of zero causes
409 threads created with this attr to be in
410 an undetached state. An undetached
411 thread will keep its resources after
413 pthread_attr_setdetachstate(&attr
, &detachstate
);
416 // pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
417 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_JOINABLE
);
419 attrIsInitialized
= TRUE
;
421 rc
= pthread_create(&(imp
->fThread
),&attr
,&SimpleThreadProc
,(void*)this);
425 // some kind of error occured, the thread did not start.
427 imp
->fRunning
= FALSE
;
435 SimpleThread::isRunning() {
436 // Note: Mutex functions are used here not for synchronization,
437 // but to force memory barriors to exist, to ensure that one thread
438 // can see changes made by another when running on processors
439 // with memory models having weak coherency.
440 PosixThreadImplementation
*imp
= (PosixThreadImplementation
*)fImplementation
;
442 UBool retVal
= imp
->fRunning
;
448 void SimpleThread::sleep(int32_t millis
)
455 cma_sleep(millis
/100);
456 #elif defined(U_HPUX) || defined(OS390)
458 while(millis
>= 1000000) {
466 usleep(millis
* 1000);
475 #error No implementation for threads! Cannot test.
480 // *************** end fluff ******************
482 /* now begins the real test. */
483 void MultithreadTest::runIndexedTest( int32_t index
, UBool exec
,
484 const char* &name
, char* /*par*/ ) {
486 logln("TestSuite MultithreadTest: ");
489 name
= "TestThreads";
501 name
= "TestThreadedIntl";
502 #if !UCONFIG_NO_FORMATTING
510 name
= "TestCollators";
511 #if !UCONFIG_NO_COLLATION
515 #endif /* #if !UCONFIG_NO_COLLATION */
527 break; //needed to end loop
532 //-----------------------------------------------------------------------------------
534 // TestThreads -- see if threads really work at all.
536 // Set up N threads pointing at N chars. When they are started, they will
537 // each sleep 1 second and then set their chars. At the end we make sure they
540 //-----------------------------------------------------------------------------------
541 #define THREADTEST_NRTHREADS 8
543 class TestThreadsThread
: public SimpleThread
546 TestThreadsThread(char* whatToChange
) { fWhatToChange
= whatToChange
; }
547 virtual void run() { SimpleThread::sleep(1000);
549 *fWhatToChange
= '*';
555 void MultithreadTest::TestThreads()
557 char threadTestChars
[THREADTEST_NRTHREADS
+ 1];
558 SimpleThread
*threads
[THREADTEST_NRTHREADS
];
559 int32_t numThreadsStarted
= 0;
562 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
564 threadTestChars
[i
] = ' ';
565 threads
[i
] = new TestThreadsThread(&threadTestChars
[i
]);
567 threadTestChars
[THREADTEST_NRTHREADS
] = '\0';
569 logln("->" + UnicodeString(threadTestChars
) + "<- Firing off threads.. ");
570 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
572 if (threads
[i
]->start() != 0) {
573 errln("Error starting thread %d", i
);
578 SimpleThread::sleep(100);
579 logln(" Subthread started.");
582 logln("Waiting for threads to be set..");
583 if (numThreadsStarted
== 0) {
584 errln("No threads could be started for testing!");
588 int32_t patience
= 40; // seconds to wait
594 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
596 if(threadTestChars
[i
] == '*')
603 if(count
== THREADTEST_NRTHREADS
)
605 logln("->" + UnicodeString(threadTestChars
) + "<- Got all threads! cya");
606 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
613 logln("->" + UnicodeString(threadTestChars
) + "<- Waiting..");
614 SimpleThread::sleep(500);
617 errln("->" + UnicodeString(threadTestChars
) + "<- PATIENCE EXCEEDED!! Still missing some.");
618 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
625 //-----------------------------------------------------------------------
627 // TestMutex - a simple (non-stress) test to verify that ICU mutexes
628 // are actually mutexing. Does not test the use of
629 // mutexes within ICU services, but rather that the
630 // platform's mutex support is at least superficially there.
632 //----------------------------------------------------------------------
633 static UMTX gTestMutexA
= NULL
;
634 static UMTX gTestMutexB
= NULL
;
636 static int gThreadsStarted
= 0;
637 static int gThreadsInMiddle
= 0;
638 static int gThreadsDone
= 0;
640 static const int TESTMUTEX_THREAD_COUNT
= 4;
642 static int safeIncr(int &var
, int amt
) {
643 // Thread safe (using global mutex) increment of a variable.
644 // Return the updated value.
645 // Can also be used as a safe load of a variable by incrementing it by 0.
651 class TestMutexThread
: public SimpleThread
656 // This is the code that each of the spawned threads runs.
657 // All of the spawned threads bunch up together at each of the two mutexes
658 // because the main holds the mutexes until they do.
660 safeIncr(gThreadsStarted
, 1);
661 umtx_lock(&gTestMutexA
);
662 umtx_unlock(&gTestMutexA
);
663 safeIncr(gThreadsInMiddle
, 1);
664 umtx_lock(&gTestMutexB
);
665 umtx_unlock(&gTestMutexB
);
666 safeIncr(gThreadsDone
, 1);
670 void MultithreadTest::TestMutex()
672 // Start up the test threads. They should all pile up waiting on
673 // gTestMutexA, which we (the main thread) hold until the test threads
676 gThreadsInMiddle
= 0;
678 umtx_lock(&gTestMutexA
);
679 TestMutexThread
*threads
[TESTMUTEX_THREAD_COUNT
];
681 int32_t numThreadsStarted
= 0;
682 for (i
=0; i
<TESTMUTEX_THREAD_COUNT
; i
++) {
683 threads
[i
] = new TestMutexThread
;
684 if (threads
[i
]->start() != 0) {
685 errln("Error starting thread %d", i
);
691 if (numThreadsStarted
== 0) {
692 errln("No threads could be started for testing!");
697 while (safeIncr(gThreadsStarted
, 0) != TESTMUTEX_THREAD_COUNT
) {
698 if (patience
++ > 24) {
699 TSMTHREAD_FAIL("Patience Exceeded");
702 SimpleThread::sleep(500);
704 // None of the test threads should have advanced past the first mutex.
705 TSMTHREAD_ASSERT(gThreadsInMiddle
==0);
706 TSMTHREAD_ASSERT(gThreadsDone
==0);
708 // All of the test threads have made it to the first mutex.
709 // We (the main thread) now let them advance to the second mutex,
710 // where they should all pile up again.
711 umtx_lock(&gTestMutexB
);
712 umtx_unlock(&gTestMutexA
);
715 while (safeIncr(gThreadsInMiddle
, 0) != TESTMUTEX_THREAD_COUNT
) {
716 if (patience
++ > 24) {
717 TSMTHREAD_FAIL("Patience Exceeded");
720 SimpleThread::sleep(500);
722 TSMTHREAD_ASSERT(gThreadsDone
==0);
724 // All test threads made it to the second mutex.
725 // Now let them proceed from there. They will all terminate.
726 umtx_unlock(&gTestMutexB
);
728 while (safeIncr(gThreadsDone
, 0) != TESTMUTEX_THREAD_COUNT
) {
729 if (patience
++ > 24) {
730 TSMTHREAD_FAIL("Patience Exceeded");
733 SimpleThread::sleep(500);
736 // All threads made it by both mutexes.
737 // Destroy the test mutexes.
738 umtx_destroy(&gTestMutexA
);
739 umtx_destroy(&gTestMutexB
);
743 for (i
=0; i
<TESTMUTEX_THREAD_COUNT
; i
++) {
750 //-------------------------------------------------------------------------------------------
752 // class ThreadWithStatus - a thread that we can check the status and error condition of
754 //-------------------------------------------------------------------------------------------
755 class ThreadWithStatus
: public SimpleThread
758 UBool
getError() { return (fErrors
> 0); }
759 UBool
getError(UnicodeString
& fillinError
) { fillinError
= fErrorString
; return (fErrors
> 0); }
760 virtual ~ThreadWithStatus(){}
762 ThreadWithStatus() : fErrors(0) {}
763 void error(const UnicodeString
&error
) {
764 fErrors
++; fErrorString
= error
;
765 SimpleThread::errorFunc();
767 void error() { error("An error occured."); }
770 UnicodeString fErrorString
;
775 //-------------------------------------------------------------------------------------------
777 // TestMultithreadedIntl. Test ICU Formatting n a multi-threaded environment
779 //-------------------------------------------------------------------------------------------
782 // * Show exactly where the string's differences lie.
783 UnicodeString
showDifference(const UnicodeString
& expected
, const UnicodeString
& result
)
786 res
= expected
+ "<Expected\n";
787 if(expected
.length() != result
.length())
788 res
+= " [ Different lengths ] \n";
791 for(int32_t i
=0;i
<expected
.length();i
++)
793 if(expected
[i
] == result
[i
])
802 res
+= "<Differences";
805 res
+= result
+ "<Result\n";
813 //-------------------------------------------------------------------------------------------
815 // FormatThreadTest - a thread that tests performing a number of numberformats.
817 //-------------------------------------------------------------------------------------------
819 const int kFormatThreadIterations
= 20; // # of iterations per thread
820 const int kFormatThreadThreads
= 10; // # of threads to spawn
821 const int kFormatThreadPatience
= 60; // time in seconds to wait for all threads
823 #if !UCONFIG_NO_FORMATTING
827 struct FormatThreadTestData
830 UnicodeString string
;
831 FormatThreadTestData(double a
, const UnicodeString
& b
) : number(a
),string(b
) {}
835 // "Someone from {2} is receiving a #{0} error - {1}. Their telephone call is costing {3 number,currency}."
837 void formatErrorMessage(UErrorCode
&realStatus
, const UnicodeString
& pattern
, const Locale
& theLocale
,
838 UErrorCode inStatus0
, /* statusString 1 */ const Locale
&inCountry2
, double currency3
, // these numbers are the message arguments.
839 UnicodeString
&result
)
841 if(U_FAILURE(realStatus
))
842 return; // you messed up
844 UnicodeString
errString1(u_errorName(inStatus0
));
846 UnicodeString countryName2
;
847 inCountry2
.getDisplayCountry(theLocale
,countryName2
);
849 Formattable myArgs
[] = {
850 Formattable((int32_t)inStatus0
), // inStatus0 {0}
851 Formattable(errString1
), // statusString1 {1}
852 Formattable(countryName2
), // inCountry2 {2}
853 Formattable(currency3
)// currency3 {3,number,currency}
856 MessageFormat
*fmt
= new MessageFormat("MessageFormat's API is broken!!!!!!!!!!!",realStatus
);
857 fmt
->setLocale(theLocale
);
858 fmt
->applyPattern(pattern
, realStatus
);
860 if (U_FAILURE(realStatus
)) {
865 FieldPosition ignore
= 0;
866 fmt
->format(myArgs
,4,result
,ignore
,realStatus
);
872 UBool U_CALLCONV
isAcceptable(void *, const char *, const char *, const UDataInfo
*) {
876 //static UMTX debugMutex = NULL;
877 //static UMTX gDebugMutex;
880 class FormatThreadTest
: public ThreadWithStatus
886 FormatThreadTest() // constructor is NOT multithread safe.
887 : ThreadWithStatus(),
893 static int32_t fgOffset
= 0;
902 NumberFormat
*formatter
= NULL
;
903 NumberFormat
*percentFormatter
= NULL
;
904 UErrorCode status
= U_ZERO_ERROR
;
908 for (int i
=0; i
<4000; i
++) {
909 status
= U_ZERO_ERROR
;
910 UDataMemory
*data1
= udata_openChoice(0, "res", "en_US", isAcceptable
, 0, &status
);
911 UDataMemory
*data2
= udata_openChoice(0, "res", "fr", isAcceptable
, 0, &status
);
914 if (U_FAILURE(status
)) {
915 error("udata_openChoice failed.\n");
925 for (m
=0; m
<4000; m
++) {
926 status
= U_ZERO_ERROR
;
927 UResourceBundle
*res
= NULL
;
928 const char *localeName
= NULL
;
930 Locale loc
= Locale::getEnglish();
932 localeName
= loc
.getName();
933 // localeName = "en";
935 // ResourceBundle bund = ResourceBundle(0, loc, status);
936 //umtx_lock(&gDebugMutex);
937 res
= ures_open(NULL
, localeName
, &status
);
938 //umtx_unlock(&gDebugMutex);
940 //umtx_lock(&gDebugMutex);
942 //umtx_unlock(&gDebugMutex);
944 if (U_FAILURE(status
)) {
945 error("Resource bundle construction failed.\n");
952 // Keep this data here to avoid static initialization.
953 FormatThreadTestData kNumberFormatTestData
[] =
955 FormatThreadTestData((double)5.0, UnicodeString("5", "")),
956 FormatThreadTestData( 6.0, UnicodeString("6", "")),
957 FormatThreadTestData( 20.0, UnicodeString("20", "")),
958 FormatThreadTestData( 8.0, UnicodeString("8", "")),
959 FormatThreadTestData( 8.3, UnicodeString("8.3", "")),
960 FormatThreadTestData( 12345, UnicodeString("12,345", "")),
961 FormatThreadTestData( 81890.23, UnicodeString("81,890.23", "")),
963 int32_t kNumberFormatTestDataLength
= (int32_t)(sizeof(kNumberFormatTestData
) /
964 sizeof(kNumberFormatTestData
[0]));
966 // Keep this data here to avoid static initialization.
967 FormatThreadTestData kPercentFormatTestData
[] =
969 FormatThreadTestData((double)5.0, CharsToUnicodeString("500\\u00a0%")),
970 FormatThreadTestData( 1.0, CharsToUnicodeString("100\\u00a0%")),
971 FormatThreadTestData( 0.26, CharsToUnicodeString("26\\u00a0%")),
972 FormatThreadTestData(
973 16384.99, CharsToUnicodeString("1\\u00a0638\\u00a0499\\u00a0%")), // U+00a0 = NBSP
974 FormatThreadTestData(
975 81890.23, CharsToUnicodeString("8\\u00a0189\\u00a0023\\u00a0%")),
977 int32_t kPercentFormatTestDataLength
=
978 (int32_t)(sizeof(kPercentFormatTestData
) / sizeof(kPercentFormatTestData
[0]));
981 status
= U_ZERO_ERROR
;
982 formatter
= NumberFormat::createInstance(Locale::getEnglish(),status
);
983 if(U_FAILURE(status
)) {
984 error("Error on NumberFormat::createInstance()");
985 goto cleanupAndReturn
;
988 percentFormatter
= NumberFormat::createPercentInstance(Locale::getFrench(),status
);
989 if(U_FAILURE(status
)) {
990 error("Error on NumberFormat::createPercentInstance()");
991 goto cleanupAndReturn
;
994 for(iteration
= 0;!getError() && iteration
<kFormatThreadIterations
;iteration
++)
997 int32_t whichLine
= (iteration
+ fOffset
)%kNumberFormatTestDataLength
;
999 UnicodeString output
;
1001 formatter
->format(kNumberFormatTestData
[whichLine
].number
, output
);
1003 if(0 != output
.compare(kNumberFormatTestData
[whichLine
].string
)) {
1004 error("format().. expected " + kNumberFormatTestData
[whichLine
].string
1005 + " got " + output
);
1006 goto cleanupAndReturn
;
1009 // Now check percent.
1011 whichLine
= (iteration
+ fOffset
)%kPercentFormatTestDataLength
;
1013 percentFormatter
->format(kPercentFormatTestData
[whichLine
].number
, output
);
1014 if(0 != output
.compare(kPercentFormatTestData
[whichLine
].string
))
1016 error("percent format().. \n" +
1017 showDifference(kPercentFormatTestData
[whichLine
].string
,output
));
1018 goto cleanupAndReturn
;
1021 // Test message error
1022 const int kNumberOfMessageTests
= 3;
1023 UErrorCode statusToCheck
;
1024 UnicodeString patternToCheck
;
1025 Locale messageLocale
;
1026 Locale countryToCheck
;
1027 double currencyToCheck
;
1029 UnicodeString expected
;
1032 switch((iteration
+fOffset
) % kNumberOfMessageTests
)
1036 statusToCheck
= U_FILE_ACCESS_ERROR
;
1037 patternToCheck
= "0:Someone from {2} is receiving a #{0}"
1038 " error - {1}. Their telephone call is costing "
1039 "{3,number,currency}."; // number,currency
1040 messageLocale
= Locale("en","US");
1041 countryToCheck
= Locale("","HR");
1042 currencyToCheck
= 8192.77;
1043 expected
= "0:Someone from Croatia is receiving a #4 error - "
1044 "U_FILE_ACCESS_ERROR. Their telephone call is costing $8,192.77.";
1047 statusToCheck
= U_INDEX_OUTOFBOUNDS_ERROR
;
1048 patternToCheck
= "1:A customer in {2} is receiving a #{0} error - {1}. Their telephone call is costing {3,number,currency}."; // number,currency
1049 messageLocale
= Locale("de","DE@currency=DEM");
1050 countryToCheck
= Locale("","BF");
1051 currencyToCheck
= 2.32;
1052 expected
= CharsToUnicodeString(
1053 "1:A customer in Burkina Faso is receiving a #8 error - U_INDEX_OUTOFBOUNDS_ERROR. Their telephone call is costing 2,32\\u00A0DM.");
1056 statusToCheck
= U_MEMORY_ALLOCATION_ERROR
;
1057 patternToCheck
= "2:user in {2} is receiving a #{0} error - {1}. "
1058 "They insist they just spent {3,number,currency} "
1059 "on memory."; // number,currency
1060 messageLocale
= Locale("de","AT@currency=ATS"); // Austrian German
1061 countryToCheck
= Locale("","US"); // hmm
1062 currencyToCheck
= 40193.12;
1063 expected
= CharsToUnicodeString(
1064 "2:user in Vereinigte Staaten is receiving a #7 error"
1065 " - U_MEMORY_ALLOCATION_ERROR. They insist they just spent"
1066 " \\u00f6S\\u00A040.193,12 on memory.");
1070 UnicodeString result
;
1071 UErrorCode status
= U_ZERO_ERROR
;
1072 formatErrorMessage(status
,patternToCheck
,messageLocale
,statusToCheck
,
1073 countryToCheck
,currencyToCheck
,result
);
1074 if(U_FAILURE(status
))
1076 UnicodeString
tmp(u_errorName(status
));
1077 error("Failure on message format, pattern=" + patternToCheck
+
1078 ", error = " + tmp
);
1079 goto cleanupAndReturn
;
1082 if(result
!= expected
)
1084 error("PatternFormat: \n" + showDifference(expected
,result
));
1085 goto cleanupAndReturn
;
1087 } /* end of for loop */
1091 delete percentFormatter
;
1093 // while (fNum == 4) {SimpleThread::sleep(10000);} // Force a failure by preventing thread from finishing
1098 int32_t fOffset
; // where we are testing from.
1101 // ** The actual test function.
1103 void MultithreadTest::TestThreadedIntl()
1106 UnicodeString theErr
;
1107 UBool haveDisplayedInfo
[kFormatThreadThreads
];
1108 static const int32_t PATIENCE_SECONDS
= 45;
1111 // Create and start the test threads
1113 logln("Spawning: %d threads * %d iterations each.",
1114 kFormatThreadThreads
, kFormatThreadIterations
);
1115 FormatThreadTest
*tests
= new FormatThreadTest
[kFormatThreadThreads
];
1116 for(int32_t j
= 0; j
< kFormatThreadThreads
; j
++) {
1118 int32_t threadStatus
= tests
[j
].start();
1119 if (threadStatus
!= 0) {
1120 errln("System Error %d starting thread number %d.", threadStatus
, j
);
1121 SimpleThread::errorFunc();
1122 goto cleanupAndReturn
;
1124 haveDisplayedInfo
[j
] = FALSE
;
1128 // Spin, waiting for the test threads to finish.
1130 UDate startTime
, endTime
;
1131 startTime
= Calendar::getNow();
1133 /* Spin until the test threads complete. */
1134 stillRunning
= FALSE
;
1135 endTime
= Calendar::getNow();
1136 if (((int32_t)(endTime
- startTime
)/U_MILLIS_PER_SECOND
) > PATIENCE_SECONDS
) {
1137 errln("Patience exceeded. Test is taking too long.");
1141 The following sleep must be here because the *BSD operating systems
1142 have a brain dead thread scheduler. They starve the child threads from
1145 SimpleThread::sleep(1); // yield
1146 for(i
=0;i
<kFormatThreadThreads
;i
++) {
1147 if (tests
[i
].isRunning()) {
1148 stillRunning
= TRUE
;
1149 } else if (haveDisplayedInfo
[i
] == FALSE
) {
1150 logln("Thread # %d is complete..", i
);
1151 if(tests
[i
].getError(theErr
)) {
1152 errln(UnicodeString("#") + i
+ ": " + theErr
);
1153 SimpleThread::errorFunc();
1155 haveDisplayedInfo
[i
] = TRUE
;
1158 } while (stillRunning
);
1161 // All threads have finished.
1166 #endif /* #if !UCONFIG_NO_FORMATTING */
1172 //-------------------------------------------------------------------------------------------
1174 // Collation threading test
1176 //-------------------------------------------------------------------------------------------
1177 #if !UCONFIG_NO_COLLATION
1179 #define kCollatorThreadThreads 10 // # of threads to spawn
1180 #define kCollatorThreadPatience kCollatorThreadThreads*30
1187 class CollatorThreadTest
: public ThreadWithStatus
1190 const UCollator
*coll
;
1194 CollatorThreadTest() : ThreadWithStatus(),
1200 void setCollator(UCollator
*c
, Line
*l
, int32_t nl
)
1206 virtual void run() {
1210 uint8_t sk1
[1024], sk2
[1024];
1211 uint8_t *oldSk
= NULL
, *newSk
= sk1
;
1212 int32_t resLen
= 0, oldLen
= 0;
1215 for(i
= 0; i
< noLines
; i
++) {
1216 resLen
= ucol_getSortKey(coll
, lines
[i
].buff
, lines
[i
].buflen
, newSk
, 1024);
1218 int32_t res
= 0, cmpres
= 0, cmpres2
= 0;
1221 res
= strcmp((char *)oldSk
, (char *)newSk
);
1222 cmpres
= ucol_strcoll(coll
, lines
[i
-1].buff
, lines
[i
-1].buflen
, lines
[i
].buff
, lines
[i
].buflen
);
1223 cmpres2
= ucol_strcoll(coll
, lines
[i
].buff
, lines
[i
].buflen
, lines
[i
-1].buff
, lines
[i
-1].buflen
);
1225 //cmpres2 = -cmpres;
1227 if(cmpres
!= -cmpres2
) {
1228 error("Compare result not symmetrical on line "+ line
);
1232 if(((res
&0x80000000) != (cmpres
&0x80000000)) || (res
== 0 && cmpres
!= 0) || (res
!= 0 && cmpres
== 0)) {
1233 error(UnicodeString("Difference between ucol_strcoll and sortkey compare on line ")+ UnicodeString(line
));
1238 error(UnicodeString("Line %i is not greater or equal than previous line ")+ UnicodeString(i
));
1240 } else if(res
== 0) { /* equal */
1241 res
= u_strcmpCodePointOrder(lines
[i
-1].buff
, lines
[i
].buff
);
1243 error(UnicodeString("Probable error in test file on line %i (comparing identical strings)")+ UnicodeString(i
));
1245 } else if (res
> 0) {
1246 error(UnicodeString("Sortkeys are identical, but code point comapare gives >0 on line ")+ UnicodeString(i
));
1255 newSk
= (newSk
== sk1
)?sk2
:sk1
;
1261 void MultithreadTest::TestCollators()
1264 UErrorCode status
= U_ZERO_ERROR
;
1265 FILE *testFile
= NULL
;
1266 char testDataPath
[1024];
1267 strcpy(testDataPath
, IntlTest::getSourceTestData(status
));
1268 if (U_FAILURE(status
)) {
1269 errln("ERROR: could not open test data %s", u_errorName(status
));
1272 strcat(testDataPath
, "CollationTest_");
1274 const char* type
= "NON_IGNORABLE";
1276 const char *ext
= ".txt";
1281 strcpy(buffer
, testDataPath
);
1282 strcat(buffer
, type
);
1283 size_t bufLen
= strlen(buffer
);
1285 // we try to open 3 files:
1286 // path/CollationTest_type.txt
1287 // path/CollationTest_type_SHORT.txt
1288 // path/CollationTest_type_STUB.txt
1289 // we are going to test with the first one that we manage to open.
1291 strcpy(buffer
+bufLen
, ext
);
1293 testFile
= fopen(buffer
, "rb");
1296 strcpy(buffer
+bufLen
, "_SHORT");
1297 strcat(buffer
, ext
);
1298 testFile
= fopen(buffer
, "rb");
1301 strcpy(buffer
+bufLen
, "_STUB");
1302 strcat(buffer
, ext
);
1303 testFile
= fopen(buffer
, "rb");
1305 if (testFile
== 0) {
1306 *(buffer
+bufLen
) = 0;
1307 dataerrln("[DATA] could not open any of the conformance test files, tried opening base %s", buffer
);
1311 "INFO: Working with the stub file.\n"
1312 "If you need the full conformance test, please\n"
1313 "download the appropriate data files from:\n"
1314 "http://source.icu-project.org/repos/icu/tools/trunk/unicodetools/com/ibm/text/data/");
1319 Line
*lines
= new Line
[200000];
1320 memset(lines
, 0, sizeof(Line
)*200000);
1321 int32_t lineNum
= 0;
1323 UChar bufferU
[1024];
1326 uint32_t offset
= 0;
1328 while (fgets(buffer
, 1024, testFile
) != NULL
) {
1330 if(*buffer
== 0 || strlen(buffer
) < 3 || buffer
[0] == '#') {
1333 offset
= u_parseString(buffer
, bufferU
, 1024, &first
, &status
);
1335 bufferU
[offset
++] = 0;
1336 lines
[lineNum
].buflen
= buflen
;
1337 //lines[lineNum].buff = new UChar[buflen+1];
1338 u_memcpy(lines
[lineNum
].buff
, bufferU
, buflen
);
1342 if(U_FAILURE(status
)) {
1343 dataerrln("[DATA] Couldn't read the test file!");
1347 UCollator
*coll
= ucol_open("root", &status
);
1348 if(U_FAILURE(status
)) {
1349 errln("Couldn't open UCA collator");
1352 ucol_setAttribute(coll
, UCOL_NORMALIZATION_MODE
, UCOL_ON
, &status
);
1353 ucol_setAttribute(coll
, UCOL_CASE_FIRST
, UCOL_OFF
, &status
);
1354 ucol_setAttribute(coll
, UCOL_CASE_LEVEL
, UCOL_OFF
, &status
);
1355 ucol_setAttribute(coll
, UCOL_STRENGTH
, UCOL_TERTIARY
, &status
);
1356 ucol_setAttribute(coll
, UCOL_ALTERNATE_HANDLING
, UCOL_NON_IGNORABLE
, &status
);
1358 int32_t noSpawned
= 0;
1359 int32_t spawnResult
= 0;
1360 CollatorThreadTest
*tests
;
1361 tests
= new CollatorThreadTest
[kCollatorThreadThreads
];
1363 logln(UnicodeString("Spawning: ") + kCollatorThreadThreads
+ " threads * " + kFormatThreadIterations
+ " iterations each.");
1365 for(j
= 0; j
< kCollatorThreadThreads
; j
++) {
1366 //logln("Setting collator %i", j);
1367 tests
[j
].setCollator(coll
, lines
, lineNum
);
1369 for(j
= 0; j
< kCollatorThreadThreads
; j
++) {
1371 spawnResult
= tests
[j
].start();
1372 if(spawnResult
!= 0) {
1373 infoln("THREAD INFO: Couldn't spawn more than %i threads", noSpawned
);
1378 logln("Spawned all");
1379 if (noSpawned
== 0) {
1380 errln("No threads could be spawned.");
1384 for(int32_t patience
= kCollatorThreadPatience
;patience
> 0; patience
--)
1386 logln("Waiting...");
1390 int32_t completed
=0;
1392 for(i
=0;i
<kCollatorThreadThreads
;i
++)
1394 if (tests
[i
].isRunning() == FALSE
)
1398 //logln(UnicodeString("Test #") + i + " is complete.. ");
1400 UnicodeString theErr
;
1401 if(tests
[i
].getError(theErr
))
1404 errln(UnicodeString("#") + i
+ ": " + theErr
);
1406 // print out the error, too, if any.
1409 logln("Completed %i tests", completed
);
1411 if(completed
== noSpawned
)
1413 logln("Done! All %i tests are finished", noSpawned
);
1417 errln("There were errors.");
1418 SimpleThread::errorFunc();
1422 //for(i = 0; i < lineNum; i++) {
1423 //delete[] lines[i].buff;
1430 SimpleThread::sleep(900);
1432 errln("patience exceeded. ");
1433 SimpleThread::errorFunc();
1437 #endif /* #if !UCONFIG_NO_COLLATION */
1442 //-------------------------------------------------------------------------------------------
1444 // StringThreadTest2
1446 //-------------------------------------------------------------------------------------------
1448 const int kStringThreadIterations
= 2500;// # of iterations per thread
1449 const int kStringThreadThreads
= 10; // # of threads to spawn
1450 const int kStringThreadPatience
= 120; // time in seconds to wait for all threads
1453 class StringThreadTest2
: public ThreadWithStatus
1458 const UnicodeString
*fSharedString
;
1460 StringThreadTest2(const UnicodeString
*sharedString
, int num
) // constructor is NOT multithread safe.
1461 : ThreadWithStatus(),
1464 fSharedString(sharedString
)
1474 for (loopCount
= 0; loopCount
< kStringThreadIterations
; loopCount
++) {
1475 if (*fSharedString
!= "This is the original test string.") {
1476 error("Original string is corrupt.");
1479 UnicodeString s1
= *fSharedString
;
1481 UnicodeString
s2(s1
);
1482 UnicodeString s3
= *fSharedString
;
1488 // while (fNum == 4) {SimpleThread::sleep(10000);} // Force a failure by preventing thread from finishing
1494 // ** The actual test function.
1496 void MultithreadTest::TestString()
1502 UnicodeString
*testString
= new UnicodeString("This is the original test string.");
1504 StringThreadTest2
*tests
[kStringThreadThreads
];
1505 for(j
= 0; j
< kStringThreadThreads
; j
++) {
1506 tests
[j
] = new StringThreadTest2(testString
, j
);
1509 logln(UnicodeString("Spawning: ") + kStringThreadThreads
+ " threads * " + kStringThreadIterations
+ " iterations each.");
1510 for(j
= 0; j
< kStringThreadThreads
; j
++) {
1511 int32_t threadStatus
= tests
[j
]->start();
1512 if (threadStatus
!= 0) {
1513 errln("System Error %d starting thread number %d.", threadStatus
, j
);
1514 SimpleThread::errorFunc();
1515 goto cleanupAndReturn
;
1519 for(patience
= kStringThreadPatience
;patience
> 0; patience
--)
1521 logln("Waiting...");
1525 int32_t completed
=0;
1527 for(i
=0;i
<kStringThreadThreads
;i
++) {
1528 if (tests
[i
]->isRunning() == FALSE
)
1532 logln(UnicodeString("Test #") + i
+ " is complete.. ");
1534 UnicodeString theErr
;
1535 if(tests
[i
]->getError(theErr
))
1538 errln(UnicodeString("#") + i
+ ": " + theErr
);
1540 // print out the error, too, if any.
1544 if(completed
== kStringThreadThreads
)
1548 errln("There were errors.");
1553 SimpleThread::sleep(900);
1556 if (patience
<= 0) {
1557 errln("patience exceeded. ");
1558 // while (TRUE) {SimpleThread::sleep(10000);} // TODO: for debugging. Sleep forever on failure.
1563 SimpleThread::errorFunc();
1569 Don't clean up if there are errors. This prevents crashes if the
1570 threads are still running and using this data. This will only happen
1571 if there is an error with the test, ICU, or the machine is too slow.
1572 It's better to leak than crash.
1574 for(j
= 0; j
< kStringThreadThreads
; j
++) {
1585 #endif // ICU_USE_THREADS