1 /********************************************************************
3 * Copyright (c) 1999-2004, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ********************************************************************/
8 # ifndef _INCLUDE_POSIX_SOURCE
9 # define _INCLUDE_POSIX_SOURCE
13 #include "unicode/utypes.h"
14 #include "unicode/ustring.h"
19 #include "unicode/resbund.h"
20 #include "unicode/udata.h"
21 #include "unicode/uloc.h"
22 #include "unicode/locid.h"
24 #if !defined(WIN32) && !defined(XP_MAC) && !defined(U_RHAPSODY)
28 #if defined(POSIX) || defined(U_SOLARIS) || defined(U_AIX) || defined(U_HPUX)
32 #if (ICU_USE_THREADS == 1)
36 #if defined(__hpux) && defined(HPUX_CMA)
37 # if defined(read) // read being defined as cma_read causes trouble with iostream::read
42 /* Define __EXTENSIONS__ for Solaris and old friends in strict mode. */
43 #ifndef __EXTENSIONS__
44 #define __EXTENSIONS__
49 /* Define _XPG4_2 for Solaris and friends. */
54 /* Define __USE_XOPEN_EXTENDED for Linux and glibc. */
55 #ifndef __USE_XOPEN_EXTENDED
56 #define __USE_XOPEN_EXTENDED
59 /* Define _INCLUDE_XOPEN_SOURCE_EXTENDED for HP/UX (11?). */
60 #ifndef _INCLUDE_XOPEN_SOURCE_EXTENDED
61 #define _INCLUDE_XOPEN_SOURCE_EXTENDED
77 MultithreadTest::MultithreadTest()
81 MultithreadTest::~MultithreadTest()
87 #if (ICU_USE_THREADS==0)
88 void MultithreadTest::runIndexedTest( int32_t index
, UBool exec
,
89 const char* &name
, char* par
) {
90 if (exec
) logln("TestSuite MultithreadTest: ");
93 name
= "NO_THREADED_TESTS";
97 if(exec
) { logln("MultithreadTest - test DISABLED. ICU_USE_THREADS set to 0, check your configuration if this is a problem..");
104 // Note: A LOT OF THE FUNCTIONS IN THIS FILE SHOULD LIVE ELSEWHERE!!!!!
105 // Note: A LOT OF THE FUNCTIONS IN THIS FILE SHOULD LIVE ELSEWHERE!!!!!
110 #include <ctype.h> // tolower, toupper
112 #include "unicode/putil.h"
115 #include "unicode/numfmt.h"
116 #include "unicode/choicfmt.h"
117 #include "unicode/msgfmt.h"
118 #include "unicode/locid.h"
119 #include "unicode/ucol.h"
120 #include "unicode/calendar.h"
123 //-----------------------------------------------------------------------------------
125 // class SimpleThread Of course we need a thread class first..
126 // This wrapper has a ported implementation.
128 //-----------------------------------------------------------------------------------
133 virtual ~SimpleThread();
134 int32_t start(void); // start the thread
135 UBool
isRunning(); // return true if a started thread has exited.
137 virtual void run(void) = 0; // Override this to provide the code to run
139 void *fImplementation
;
142 static void sleep(int32_t millis
); // probably shouldn't go here but oh well.
143 static void errorFunc(); // Empty function, provides a single convenient place
144 // to break on errors.
147 void SimpleThread::errorFunc() {
148 // *(char *)0 = 3; // Force entry into a debugger via a crash;
157 # define VC_EXTRALEAN
158 # define WIN32_LEAN_AND_MEAN
168 //-----------------------------------------------------------------------------------
170 // class SimpleThread Windows Implementation
172 //-----------------------------------------------------------------------------------
173 struct Win32ThreadImplementation
176 unsigned int fThreadID
;
180 extern "C" unsigned int __stdcall
SimpleThreadProc(void *arg
)
182 ((SimpleThread
*)arg
)->run();
186 SimpleThread::SimpleThread()
189 Win32ThreadImplementation
*imp
= new Win32ThreadImplementation
;
191 fImplementation
= imp
;
194 SimpleThread::~SimpleThread()
196 // Destructor. Because we start the thread running with _beginthreadex(),
197 // we own the Windows HANDLE for the thread and must
199 Win32ThreadImplementation
*imp
= (Win32ThreadImplementation
*)fImplementation
;
201 if (imp
->fHandle
!= 0) {
202 CloseHandle(imp
->fHandle
);
206 delete (Win32ThreadImplementation
*)fImplementation
;
209 int32_t SimpleThread::start()
211 Win32ThreadImplementation
*imp
= (Win32ThreadImplementation
*)fImplementation
;
212 if(imp
->fHandle
!= NULL
) {
213 // The thread appears to have already been started.
214 // This is probably an error on the part of our caller.
218 imp
->fHandle
= (HANDLE
) _beginthreadex(
220 0x20000, // Stack Size
221 SimpleThreadProc
, // Function to Run
222 (void *)this, // Arg List
223 0, // initflag. Start running, not suspended
224 &imp
->fThreadID
// thraddr
227 if (imp
->fHandle
== 0) {
239 UBool
SimpleThread::isRunning() {
241 // Test whether the thread associated with the SimpleThread object is
242 // still actually running.
244 // NOTE: on Win64 on Itanium processors, a crashes
245 // occur if the main thread of a process exits concurrently with some
246 // other thread(s) exiting. To avoid the possibility, we wait until the
247 // OS indicates that all threads have terminated, rather than waiting
248 // only until the end of the user's Run function has been reached.
250 // I don't know whether the crashes represent a Windows bug, or whether
251 // main() programs are supposed to have to wait for their threads.
253 Win32ThreadImplementation
*imp
= (Win32ThreadImplementation
*)fImplementation
;
256 DWORD threadExitCode
;
258 if (imp
->fHandle
== 0) {
259 // No handle, thread must not be running.
262 success
= GetExitCodeThread(imp
->fHandle
, &threadExitCode
) != 0;
264 // Can't get status, thread must not be running.
267 return (threadExitCode
== STILL_ACTIVE
);
271 void SimpleThread::sleep(int32_t millis
)
276 //-----------------------------------------------------------------------------------
278 // class SimpleThread NULL Implementation
280 //-----------------------------------------------------------------------------------
283 // since the Mac has no preemptive threading (at least on MacOS 8), only
284 // cooperative threading, threads are a no-op. We have no yield() calls
285 // anywhere in the ICU, so we are guaranteed to be thread-safe.
289 SimpleThread::SimpleThread()
292 SimpleThread::~SimpleThread()
296 SimpleThread::start()
304 SimpleThread::sleep(int32_t millis
)
308 SimpleThread::isRunning() {
315 //-----------------------------------------------------------------------------------
317 // class SimpleThread POSIX implementation
319 // A note on the POSIX vs the Windows implementations of this class..
320 // On Windows, the main thread must verify that other threads have finished
321 // before exiting, or crashes occasionally occur. (Seen on Itanium Win64 only)
322 // The function SimpleThread::isRunning() is used for this purpose.
324 // On POSIX, there is NO reliable non-blocking mechanism to determine
325 // whether a thread has exited. pthread_kill(thread, 0) almost works,
326 // but the system can recycle thread ids immediately, so seeing that a
327 // thread exists with this call could mean that the original thread has
328 // finished and a new one started with the same ID. Useless.
330 // So we need to do the check with user code, by setting a flag just before
331 // the thread function returns. A technique that is guaranteed to fail
332 // on Windows, because it indicates that the thread is done before all
333 // system level cleanup has happened.
335 //-----------------------------------------------------------------------------------
336 #if defined(POSIX)||defined(U_SOLARIS)||defined(U_AIX)||defined(U_HPUX)
339 struct PosixThreadImplementation
343 UBool fRan
; /* True if the thread was successfully started */
346 extern "C" void* SimpleThreadProc(void *arg
)
348 // This is the code that is run in the new separate thread.
349 SimpleThread
*This
= (SimpleThread
*)arg
;
350 This
->run(); // Run the user code.
352 // The user function has returned. Set the flag indicating that this thread
353 // is done. Need a mutex for memory barrier purposes only, so that other thread
354 // will reliably see that the flag has changed.
355 PosixThreadImplementation
*imp
= (PosixThreadImplementation
*)This
->fImplementation
;
357 imp
->fRunning
= FALSE
;
362 SimpleThread::SimpleThread()
364 PosixThreadImplementation
*imp
= new PosixThreadImplementation
;
365 imp
->fRunning
= FALSE
;
367 fImplementation
= imp
;
370 SimpleThread::~SimpleThread()
372 PosixThreadImplementation
*imp
= (PosixThreadImplementation
*)fImplementation
;
374 pthread_join(imp
->fThread
, NULL
);
377 fImplementation
= (void *)0xdeadbeef;
380 int32_t SimpleThread::start()
383 static pthread_attr_t attr
;
384 static UBool attrIsInitialized
= FALSE
;
386 PosixThreadImplementation
*imp
= (PosixThreadImplementation
*)fImplementation
;
387 imp
->fRunning
= TRUE
;
391 if (attrIsInitialized
== FALSE
) {
392 rc
= pthread_attr_create(&attr
);
393 attrIsInitialized
= TRUE
;
395 rc
= pthread_create(&(imp
->fThread
),attr
,&SimpleThreadProc
,(void*)this);
397 if (attrIsInitialized
== FALSE
) {
398 rc
= pthread_attr_init(&attr
);
401 int detachstate
= 0; /* jdc30: detach state of zero causes
402 threads created with this attr to be in
403 an undetached state. An undetached
404 thread will keep its resources after
406 pthread_attr_setdetachstate(&attr
, &detachstate
);
409 // pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
410 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_JOINABLE
);
412 attrIsInitialized
= TRUE
;
414 rc
= pthread_create(&(imp
->fThread
),&attr
,&SimpleThreadProc
,(void*)this);
418 // some kind of error occured, the thread did not start.
420 imp
->fRunning
= FALSE
;
428 SimpleThread::isRunning() {
429 // Note: Mutex functions are used here not for synchronization,
430 // but to force memory barriors to exist, to ensure that one thread
431 // can see changes made by another when running on processors
432 // with memory models having weak coherency.
433 PosixThreadImplementation
*imp
= (PosixThreadImplementation
*)fImplementation
;
435 UBool retVal
= imp
->fRunning
;
441 void SimpleThread::sleep(int32_t millis
)
448 cma_sleep(millis
/100);
449 #elif defined(U_HPUX) || defined(OS390)
451 while(millis
>= 1000000) {
459 usleep(millis
* 1000);
468 #error No implementation for threads! Cannot test.
473 // *************** end fluff ******************
475 /* now begins the real test. */
476 void MultithreadTest::runIndexedTest( int32_t index
, UBool exec
,
477 const char* &name
, char* /*par*/ ) {
479 logln("TestSuite MultithreadTest: ");
482 name
= "TestThreads";
494 name
= "TestThreadedIntl";
495 #if !UCONFIG_NO_FORMATTING
503 name
= "TestCollators";
504 #if !UCONFIG_NO_COLLATION
508 #endif /* #if !UCONFIG_NO_COLLATION */
520 break; //needed to end loop
525 //-----------------------------------------------------------------------------------
527 // TestThreads -- see if threads really work at all.
529 // Set up N threads pointing at N chars. When they are started, they will
530 // each sleep 1 second and then set their chars. At the end we make sure they
533 //-----------------------------------------------------------------------------------
534 #define THREADTEST_NRTHREADS 8
536 class TestThreadsThread
: public SimpleThread
539 TestThreadsThread(char* whatToChange
) { fWhatToChange
= whatToChange
; }
540 virtual void run() { SimpleThread::sleep(1000);
542 *fWhatToChange
= '*';
548 void MultithreadTest::TestThreads()
550 char threadTestChars
[THREADTEST_NRTHREADS
+ 1];
551 SimpleThread
*threads
[THREADTEST_NRTHREADS
];
554 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
556 threadTestChars
[i
] = ' ';
557 threads
[i
] = new TestThreadsThread(&threadTestChars
[i
]);
559 threadTestChars
[THREADTEST_NRTHREADS
] = '\0';
561 logln("->" + UnicodeString(threadTestChars
) + "<- Firing off threads.. ");
562 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
564 if (threads
[i
]->start() != 0) {
565 errln("Error starting thread %d", i
);
567 SimpleThread::sleep(200);
568 logln(" Subthread started.");
571 logln("Waiting for threads to be set..");
573 int32_t patience
= 40; // seconds to wait
579 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
581 if(threadTestChars
[i
] == '*')
588 if(count
== THREADTEST_NRTHREADS
)
590 logln("->" + UnicodeString(threadTestChars
) + "<- Got all threads! cya");
591 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
598 logln("->" + UnicodeString(threadTestChars
) + "<- Waiting..");
599 SimpleThread::sleep(500);
602 errln("->" + UnicodeString(threadTestChars
) + "<- PATIENCE EXCEEDED!! Still missing some.");
603 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
610 class TestMutexThread1
: public SimpleThread
613 TestMutexThread1() : fDone(FALSE
) {}
616 Mutex m
; // grab the lock first thing
617 SimpleThread::sleep(900); // then wait
618 fDone
= TRUE
; // finally, set our flag
624 class TestMutexThread2
: public SimpleThread
627 TestMutexThread2(TestMutexThread1
& r
) : fOtherThread(r
), fDone(FALSE
), fErr(FALSE
) {}
630 SimpleThread::sleep(500); // wait, make sure they aquire the lock
631 fElapsed
= uprv_getUTCtime();
633 Mutex m
; // wait here
635 fElapsed
= uprv_getUTCtime() - fElapsed
;
637 if(fOtherThread
.fDone
== FALSE
)
638 fErr
= TRUE
; // they didnt get to it yet
640 fDone
= TRUE
; // we're done.
644 TestMutexThread1
& fOtherThread
;
649 * The assignment operator has no real implementation.
650 * It is provided to make the compiler happy. Do not call.
652 TestMutexThread2
& operator=(const TestMutexThread2
&) { return *this; }
655 void MultithreadTest::TestMutex()
657 /* this test uses printf so that we don't hang by calling UnicodeString inside of a mutex. */
659 // printf("Warning: MultiThreadTest::Testmutex() disabled.\n");
663 printf("Before mutex.\n");
667 printf(" Exited 2nd mutex\n");
670 printf("exited 1st mutex. Now testing with threads:");
672 TestMutexThread1 thread1
;
673 TestMutexThread2
thread2(thread1
);
674 if (thread2
.start() != 0 ||
675 thread1
.start() != 0 ) {
676 errln("Error starting threads.");
679 for(int32_t patience
= 12; patience
> 0;patience
--)
681 // TODO: Possible memory coherence issue in looking at fDone values
682 // that are set in another thread without the mutex here.
683 if(thread1
.fDone
&& verbose
)
684 printf("Thread1 done\n");
686 if(thread1
.fDone
&& thread2
.fDone
)
689 errln("Thread 2 says: thread1 didn't run before I aquired the mutex.");
690 logln("took %lu seconds for thread2 to aquire the mutex.", (int)(thread2
.fElapsed
/U_MILLIS_PER_DAY
));
693 SimpleThread::sleep(1000);
696 printf("patience exceeded. [WARNING mutex may still be acquired.] ");
702 //-------------------------------------------------------------------------------------------
704 // class ThreadWithStatus - a thread that we can check the status and error condition of
706 //-------------------------------------------------------------------------------------------
707 class ThreadWithStatus
: public SimpleThread
710 UBool
getError() { return (fErrors
> 0); }
711 UBool
getError(UnicodeString
& fillinError
) { fillinError
= fErrorString
; return (fErrors
> 0); }
712 virtual ~ThreadWithStatus(){}
714 ThreadWithStatus() : fErrors(0) {}
715 void error(const UnicodeString
&error
) {
716 fErrors
++; fErrorString
= error
;
717 SimpleThread::errorFunc();
719 void error() { error("An error occured."); }
722 UnicodeString fErrorString
;
727 //-------------------------------------------------------------------------------------------
729 // TestMultithreadedIntl. Test ICU Formatting n a multi-threaded environment
731 //-------------------------------------------------------------------------------------------
734 // * Show exactly where the string's differences lie.
735 UnicodeString
showDifference(const UnicodeString
& expected
, const UnicodeString
& result
)
738 res
= expected
+ "<Expected\n";
739 if(expected
.length() != result
.length())
740 res
+= " [ Different lengths ] \n";
743 for(int32_t i
=0;i
<expected
.length();i
++)
745 if(expected
[i
] == result
[i
])
754 res
+= "<Differences";
757 res
+= result
+ "<Result\n";
765 //-------------------------------------------------------------------------------------------
767 // FormatThreadTest - a thread that tests performing a number of numberformats.
769 //-------------------------------------------------------------------------------------------
771 const int kFormatThreadIterations
= 20; // # of iterations per thread
772 const int kFormatThreadThreads
= 10; // # of threads to spawn
773 const int kFormatThreadPatience
= 60; // time in seconds to wait for all threads
775 #if !UCONFIG_NO_FORMATTING
779 struct FormatThreadTestData
782 UnicodeString string
;
783 FormatThreadTestData(double a
, const UnicodeString
& b
) : number(a
),string(b
) {}
787 void errorToString(UErrorCode theStatus
, UnicodeString
&string
)
789 string
=u_errorName(theStatus
);
792 // "Someone from {2} is receiving a #{0} error - {1}. Their telephone call is costing {3 number,currency}."
794 void formatErrorMessage(UErrorCode
&realStatus
, const UnicodeString
& pattern
, const Locale
& theLocale
,
795 UErrorCode inStatus0
, /* statusString 1 */ const Locale
&inCountry2
, double currency3
, // these numbers are the message arguments.
796 UnicodeString
&result
)
798 if(U_FAILURE(realStatus
))
799 return; // you messed up
801 UnicodeString errString1
;
802 errorToString(inStatus0
, errString1
);
804 UnicodeString countryName2
;
805 inCountry2
.getDisplayCountry(theLocale
,countryName2
);
807 Formattable myArgs
[] = {
808 Formattable((int32_t)inStatus0
), // inStatus0 {0}
809 Formattable(errString1
), // statusString1 {1}
810 Formattable(countryName2
), // inCountry2 {2}
811 Formattable(currency3
)// currency3 {3,number,currency}
814 MessageFormat
*fmt
= new MessageFormat("MessageFormat's API is broken!!!!!!!!!!!",realStatus
);
815 fmt
->setLocale(theLocale
);
816 fmt
->applyPattern(pattern
, realStatus
);
818 if (U_FAILURE(realStatus
)) {
823 FieldPosition ignore
= 0;
824 fmt
->format(myArgs
,4,result
,ignore
,realStatus
);
830 UBool U_CALLCONV
isAcceptable(void *, const char *, const char *, const UDataInfo
*) {
834 //static UMTX debugMutex = NULL;
835 //static UMTX gDebugMutex;
838 class FormatThreadTest
: public ThreadWithStatus
844 FormatThreadTest() // constructor is NOT multithread safe.
845 : ThreadWithStatus(),
851 static int32_t fgOffset
= 0;
860 NumberFormat
*formatter
= NULL
;
861 NumberFormat
*percentFormatter
= NULL
;
862 UErrorCode status
= U_ZERO_ERROR
;
866 for (int i
=0; i
<4000; i
++) {
867 status
= U_ZERO_ERROR
;
868 UDataMemory
*data1
= udata_openChoice(0, "res", "en_US", isAcceptable
, 0, &status
);
869 UDataMemory
*data2
= udata_openChoice(0, "res", "fr", isAcceptable
, 0, &status
);
872 if (U_FAILURE(status
)) {
873 error("udata_openChoice failed.\n");
883 for (m
=0; m
<4000; m
++) {
884 status
= U_ZERO_ERROR
;
885 UResourceBundle
*res
= NULL
;
886 const char *localeName
= NULL
;
888 Locale loc
= Locale::getEnglish();
890 localeName
= loc
.getName();
891 // localeName = "en";
893 // ResourceBundle bund = ResourceBundle(0, loc, status);
894 //umtx_lock(&gDebugMutex);
895 res
= ures_open(NULL
, localeName
, &status
);
896 //umtx_unlock(&gDebugMutex);
898 //umtx_lock(&gDebugMutex);
900 //umtx_unlock(&gDebugMutex);
902 if (U_FAILURE(status
)) {
903 error("Resource bundle construction failed.\n");
910 // Keep this data here to avoid static initialization.
911 FormatThreadTestData kNumberFormatTestData
[] =
913 FormatThreadTestData((double)5.0, UnicodeString("5", "")),
914 FormatThreadTestData( 6.0, UnicodeString("6", "")),
915 FormatThreadTestData( 20.0, UnicodeString("20", "")),
916 FormatThreadTestData( 8.0, UnicodeString("8", "")),
917 FormatThreadTestData( 8.3, UnicodeString("8.3", "")),
918 FormatThreadTestData( 12345, UnicodeString("12,345", "")),
919 FormatThreadTestData( 81890.23, UnicodeString("81,890.23", "")),
921 int32_t kNumberFormatTestDataLength
= (int32_t)(sizeof(kNumberFormatTestData
) /
922 sizeof(kNumberFormatTestData
[0]));
924 // Keep this data here to avoid static initialization.
925 FormatThreadTestData kPercentFormatTestData
[] =
927 FormatThreadTestData((double)5.0, UnicodeString("500%", "")),
928 FormatThreadTestData( 1.0, UnicodeString("100%", "")),
929 FormatThreadTestData( 0.26, UnicodeString("26%", "")),
930 FormatThreadTestData(
931 16384.99, CharsToUnicodeString("1\\u00a0638\\u00a0499%") ), // U+00a0 = NBSP
932 FormatThreadTestData(
933 81890.23, CharsToUnicodeString("8\\u00a0189\\u00a0023%" )),
935 int32_t kPercentFormatTestDataLength
=
936 (int32_t)(sizeof(kPercentFormatTestData
) / sizeof(kPercentFormatTestData
[0]));
939 status
= U_ZERO_ERROR
;
940 formatter
= NumberFormat::createInstance(Locale::getEnglish(),status
);
941 if(U_FAILURE(status
)) {
942 error("Error on NumberFormat::createInstance()");
943 goto cleanupAndReturn
;
946 percentFormatter
= NumberFormat::createPercentInstance(Locale::getFrench(),status
);
947 if(U_FAILURE(status
)) {
948 error("Error on NumberFormat::createPercentInstance()");
949 goto cleanupAndReturn
;
952 for(iteration
= 0;!getError() && iteration
<kFormatThreadIterations
;iteration
++)
955 int32_t whichLine
= (iteration
+ fOffset
)%kNumberFormatTestDataLength
;
957 UnicodeString output
;
959 formatter
->format(kNumberFormatTestData
[whichLine
].number
, output
);
961 if(0 != output
.compare(kNumberFormatTestData
[whichLine
].string
)) {
962 error("format().. expected " + kNumberFormatTestData
[whichLine
].string
964 goto cleanupAndReturn
;
967 // Now check percent.
969 whichLine
= (iteration
+ fOffset
)%kPercentFormatTestDataLength
;
971 percentFormatter
->format(kPercentFormatTestData
[whichLine
].number
, output
);
972 if(0 != output
.compare(kPercentFormatTestData
[whichLine
].string
))
974 error("percent format().. \n" +
975 showDifference(kPercentFormatTestData
[whichLine
].string
,output
));
976 goto cleanupAndReturn
;
979 // Test message error
980 const int kNumberOfMessageTests
= 3;
981 UErrorCode statusToCheck
;
982 UnicodeString patternToCheck
;
983 Locale messageLocale
;
984 Locale countryToCheck
;
985 double currencyToCheck
;
987 UnicodeString expected
;
990 switch((iteration
+fOffset
) % kNumberOfMessageTests
)
994 statusToCheck
= U_FILE_ACCESS_ERROR
;
995 patternToCheck
= "0:Someone from {2} is receiving a #{0}"
996 " error - {1}. Their telephone call is costing "
997 "{3,number,currency}."; // number,currency
998 messageLocale
= Locale("en","US");
999 countryToCheck
= Locale("","HR");
1000 currencyToCheck
= 8192.77;
1001 expected
= "0:Someone from Croatia is receiving a #4 error - "
1002 "U_FILE_ACCESS_ERROR. Their telephone call is costing $8,192.77.";
1005 statusToCheck
= U_INDEX_OUTOFBOUNDS_ERROR
;
1006 patternToCheck
= "1:A customer in {2} is receiving a #{0} error - {1}. Their telephone call is costing {3,number,currency}."; // number,currency
1007 messageLocale
= Locale("de","DE@currency=DEM");
1008 countryToCheck
= Locale("","BF");
1009 currencyToCheck
= 2.32;
1010 expected
= "1:A customer in Burkina Faso is receiving a #8 error - U_INDEX_OUTOFBOUNDS_ERROR. Their telephone call is costing 2,32 DM.";
1013 statusToCheck
= U_MEMORY_ALLOCATION_ERROR
;
1014 patternToCheck
= "2:user in {2} is receiving a #{0} error - {1}. "
1015 "They insist they just spent {3,number,currency} "
1016 "on memory."; // number,currency
1017 messageLocale
= Locale("de","AT@currency=ATS"); // Austrian German
1018 countryToCheck
= Locale("","US"); // hmm
1019 currencyToCheck
= 40193.12;
1020 expected
= CharsToUnicodeString(
1021 "2:user in Vereinigte Staaten is receiving a #7 error"
1022 " - U_MEMORY_ALLOCATION_ERROR. They insist they just spent"
1023 " \\u00f6S 40.193,12 on memory.");
1027 UnicodeString result
;
1028 UErrorCode status
= U_ZERO_ERROR
;
1029 formatErrorMessage(status
,patternToCheck
,messageLocale
,statusToCheck
,
1030 countryToCheck
,currencyToCheck
,result
);
1031 if(U_FAILURE(status
))
1034 errorToString(status
,tmp
);
1035 error("Failure on message format, pattern=" + patternToCheck
+
1036 ", error = " + tmp
);
1037 goto cleanupAndReturn
;
1040 if(result
!= expected
)
1042 error("PatternFormat: \n" + showDifference(expected
,result
));
1043 goto cleanupAndReturn
;
1045 } /* end of for loop */
1049 delete percentFormatter
;
1051 // while (fNum == 4) {SimpleThread::sleep(10000);} // Force a failure by preventing thread from finishing
1056 int32_t fOffset
; // where we are testing from.
1059 // ** The actual test function.
1061 void MultithreadTest::TestThreadedIntl()
1064 UnicodeString theErr
;
1065 UBool haveDisplayedInfo
[kFormatThreadThreads
];
1068 // Create and start the test threads
1070 logln("Spawning: %d threads * %d iterations each.",
1071 kFormatThreadThreads
, kFormatThreadIterations
);
1072 FormatThreadTest
*tests
= new FormatThreadTest
[kFormatThreadThreads
];
1073 for(int32_t j
= 0; j
< kFormatThreadThreads
; j
++) {
1075 int32_t threadStatus
= tests
[j
].start();
1076 if (threadStatus
!= 0) {
1077 errln("System Error %d starting thread number %d.", threadStatus
, j
);
1078 SimpleThread::errorFunc();
1079 goto cleanupAndReturn
;
1081 haveDisplayedInfo
[j
] = FALSE
;
1085 // Spin, waiting for the test threads to finish.
1086 // (An earlier version used a wait in this loop, but that seems to trigger
1087 // a bug in some versions of AIX.)
1090 /* Spin until the test threads complete. */
1091 stillRunning
= FALSE
;
1092 for(i
=0;i
<kFormatThreadThreads
;i
++) {
1093 if (tests
[i
].isRunning()) {
1094 stillRunning
= TRUE
;
1095 } else if (haveDisplayedInfo
[i
] == FALSE
) {
1096 logln("Thread # %d is complete..", i
);
1097 if(tests
[i
].getError(theErr
)) {
1098 errln(UnicodeString("#") + i
+ ": " + theErr
);
1099 SimpleThread::errorFunc();
1101 haveDisplayedInfo
[i
] = TRUE
;
1104 } while (stillRunning
);
1107 // All threads have finished.
1114 #endif /* #if !UCONFIG_NO_FORMATTING */
1120 //-------------------------------------------------------------------------------------------
1122 // Collation threading test
1124 //-------------------------------------------------------------------------------------------
1125 #if !UCONFIG_NO_COLLATION
1127 #define kCollatorThreadThreads 10 // # of threads to spawn
1128 #define kCollatorThreadPatience kCollatorThreadThreads*100
1135 class CollatorThreadTest
: public ThreadWithStatus
1138 const UCollator
*coll
;
1142 CollatorThreadTest() : ThreadWithStatus(),
1148 void setCollator(UCollator
*c
, Line
*l
, int32_t nl
)
1154 virtual void run() {
1158 uint8_t sk1
[1024], sk2
[1024];
1159 uint8_t *oldSk
= NULL
, *newSk
= sk1
;
1160 int32_t resLen
= 0, oldLen
= 0;
1163 for(i
= 0; i
< noLines
; i
++) {
1164 resLen
= ucol_getSortKey(coll
, lines
[i
].buff
, lines
[i
].buflen
, newSk
, 1024);
1166 int32_t res
= 0, cmpres
= 0, cmpres2
= 0;
1169 res
= strcmp((char *)oldSk
, (char *)newSk
);
1170 cmpres
= ucol_strcoll(coll
, lines
[i
-1].buff
, lines
[i
-1].buflen
, lines
[i
].buff
, lines
[i
].buflen
);
1171 cmpres2
= ucol_strcoll(coll
, lines
[i
].buff
, lines
[i
].buflen
, lines
[i
-1].buff
, lines
[i
-1].buflen
);
1173 //cmpres2 = -cmpres;
1175 if(cmpres
!= -cmpres2
) {
1176 error("Compare result not symmetrical on line "+ line
);
1180 if(((res
&0x80000000) != (cmpres
&0x80000000)) || (res
== 0 && cmpres
!= 0) || (res
!= 0 && cmpres
== 0)) {
1181 error(UnicodeString("Difference between ucol_strcoll and sortkey compare on line ")+ UnicodeString(line
));
1186 error(UnicodeString("Line %i is not greater or equal than previous line ")+ UnicodeString(i
));
1188 } else if(res
== 0) { /* equal */
1189 res
= u_strcmpCodePointOrder(lines
[i
-1].buff
, lines
[i
].buff
);
1191 error(UnicodeString("Probable error in test file on line %i (comparing identical strings)")+ UnicodeString(i
));
1193 } else if (res
> 0) {
1194 error(UnicodeString("Sortkeys are identical, but code point comapare gives >0 on line ")+ UnicodeString(i
));
1203 newSk
= (newSk
== sk1
)?sk2
:sk1
;
1209 void MultithreadTest::TestCollators()
1212 UErrorCode status
= U_ZERO_ERROR
;
1213 FILE *testFile
= NULL
;
1214 char testDataPath
[1024];
1215 strcpy(testDataPath
, IntlTest::getSourceTestData(status
));
1216 if (U_FAILURE(status
)) {
1217 errln("ERROR: could not open test data %s", u_errorName(status
));
1220 strcat(testDataPath
, "CollationTest_");
1222 const char* type
= "NON_IGNORABLE";
1224 const char *ext
= ".txt";
1229 strcpy(buffer
, testDataPath
);
1230 strcat(buffer
, type
);
1231 size_t bufLen
= strlen(buffer
);
1233 // we try to open 3 files:
1234 // path/CollationTest_type.txt
1235 // path/CollationTest_type_SHORT.txt
1236 // path/CollationTest_type_STUB.txt
1237 // we are going to test with the first one that we manage to open.
1239 strcpy(buffer
+bufLen
, ext
);
1241 testFile
= fopen(buffer
, "rb");
1244 strcpy(buffer
+bufLen
, "_SHORT");
1245 strcat(buffer
, ext
);
1246 testFile
= fopen(buffer
, "rb");
1249 strcpy(buffer
+bufLen
, "_STUB");
1250 strcat(buffer
, ext
);
1251 testFile
= fopen(buffer
, "rb");
1253 if (testFile
== 0) {
1254 *(buffer
+bufLen
) = 0;
1255 errln("ERROR: could not open any of the conformance test files, tried opening base %s", buffer
);
1259 "INFO: Working with the stub file.\n"
1260 "If you need the full conformance test, please\n"
1261 "download the appropriate data files from:\n"
1262 "http://oss.software.ibm.com/cvs/icu4j/unicodetools/com/ibm/text/data/");
1267 Line
*lines
= new Line
[200000];
1268 memset(lines
, 0, sizeof(Line
)*200000);
1269 int32_t lineNum
= 0;
1271 UChar bufferU
[1024];
1274 uint32_t offset
= 0;
1276 while (fgets(buffer
, 1024, testFile
) != NULL
) {
1278 if(*buffer
== 0 || buffer
[0] == '#') {
1281 offset
= u_parseString(buffer
, bufferU
, 1024, &first
, &status
);
1283 bufferU
[offset
++] = 0;
1284 lines
[lineNum
].buflen
= buflen
;
1285 //lines[lineNum].buff = new UChar[buflen+1];
1286 u_memcpy(lines
[lineNum
].buff
, bufferU
, buflen
);
1293 UCollator
*coll
= ucol_open("root", &status
);
1294 if(U_FAILURE(status
)) {
1295 errln("Couldn't open UCA collator");
1298 ucol_setAttribute(coll
, UCOL_NORMALIZATION_MODE
, UCOL_ON
, &status
);
1299 ucol_setAttribute(coll
, UCOL_CASE_FIRST
, UCOL_OFF
, &status
);
1300 ucol_setAttribute(coll
, UCOL_CASE_LEVEL
, UCOL_OFF
, &status
);
1301 ucol_setAttribute(coll
, UCOL_STRENGTH
, UCOL_TERTIARY
, &status
);
1302 ucol_setAttribute(coll
, UCOL_ALTERNATE_HANDLING
, UCOL_NON_IGNORABLE
, &status
);
1304 int32_t noSpawned
= 0;
1305 int32_t spawnResult
= 0;
1306 CollatorThreadTest
*tests
;
1307 tests
= new CollatorThreadTest
[kCollatorThreadThreads
];
1309 logln(UnicodeString("Spawning: ") + kCollatorThreadThreads
+ " threads * " + kFormatThreadIterations
+ " iterations each.");
1311 for(j
= 0; j
< kCollatorThreadThreads
; j
++) {
1312 //logln("Setting collator %i", j);
1313 tests
[j
].setCollator(coll
, lines
, lineNum
);
1315 for(j
= 0; j
< kCollatorThreadThreads
; j
++) {
1317 spawnResult
= tests
[j
].start();
1318 if(spawnResult
!= 0) {
1319 infoln("THREAD INFO: Couldn't spawn more than %i threads", noSpawned
);
1324 logln("Spawned all");
1326 //for(int32_t patience = kCollatorThreadPatience;patience > 0; patience --)
1329 logln("Waiting...");
1333 int32_t completed
=0;
1335 for(i
=0;i
<kCollatorThreadThreads
;i
++)
1337 if (tests
[i
].isRunning() == FALSE
)
1341 //logln(UnicodeString("Test #") + i + " is complete.. ");
1343 UnicodeString theErr
;
1344 if(tests
[i
].getError(theErr
))
1347 errln(UnicodeString("#") + i
+ ": " + theErr
);
1349 // print out the error, too, if any.
1352 logln("Completed %i tests", completed
);
1354 if(completed
== noSpawned
)
1356 logln("Done! All %i tests are finished", noSpawned
);
1360 errln("There were errors.");
1361 SimpleThread::errorFunc();
1365 //for(i = 0; i < lineNum; i++) {
1366 //delete[] lines[i].buff;
1373 SimpleThread::sleep(900);
1375 errln("patience exceeded. ");
1376 SimpleThread::errorFunc();
1380 #endif /* #if !UCONFIG_NO_COLLATION */
1385 //-------------------------------------------------------------------------------------------
1387 // StringThreadTest2
1389 //-------------------------------------------------------------------------------------------
1391 const int kStringThreadIterations
= 2500;// # of iterations per thread
1392 const int kStringThreadThreads
= 10; // # of threads to spawn
1393 const int kStringThreadPatience
= 120; // time in seconds to wait for all threads
1396 class StringThreadTest2
: public ThreadWithStatus
1401 const UnicodeString
*fSharedString
;
1403 StringThreadTest2(const UnicodeString
*sharedString
, int num
) // constructor is NOT multithread safe.
1404 : ThreadWithStatus(),
1407 fSharedString(sharedString
)
1417 for (loopCount
= 0; loopCount
< kStringThreadIterations
; loopCount
++) {
1418 if (*fSharedString
!= "This is the original test string.") {
1419 error("Original string is corrupt.");
1422 UnicodeString s1
= *fSharedString
;
1424 UnicodeString
s2(s1
);
1425 UnicodeString s3
= *fSharedString
;
1431 // while (fNum == 4) {SimpleThread::sleep(10000);} // Force a failure by preventing thread from finishing
1437 // ** The actual test function.
1439 void MultithreadTest::TestString()
1445 UnicodeString
*testString
= new UnicodeString("This is the original test string.");
1447 StringThreadTest2
*tests
[kStringThreadThreads
];
1448 for(j
= 0; j
< kStringThreadThreads
; j
++) {
1449 tests
[j
] = new StringThreadTest2(testString
, j
);
1452 logln(UnicodeString("Spawning: ") + kStringThreadThreads
+ " threads * " + kStringThreadIterations
+ " iterations each.");
1453 for(j
= 0; j
< kStringThreadThreads
; j
++) {
1454 int32_t threadStatus
= tests
[j
]->start();
1455 if (threadStatus
!= 0) {
1456 errln("System Error %d starting thread number %d.", threadStatus
, j
);
1457 SimpleThread::errorFunc();
1458 goto cleanupAndReturn
;
1462 for(patience
= kStringThreadPatience
;patience
> 0; patience
--)
1464 logln("Waiting...");
1468 int32_t completed
=0;
1470 for(i
=0;i
<kStringThreadThreads
;i
++) {
1471 if (tests
[i
]->isRunning() == FALSE
)
1475 logln(UnicodeString("Test #") + i
+ " is complete.. ");
1477 UnicodeString theErr
;
1478 if(tests
[i
]->getError(theErr
))
1481 errln(UnicodeString("#") + i
+ ": " + theErr
);
1483 // print out the error, too, if any.
1487 if(completed
== kStringThreadThreads
)
1491 errln("There were errors.");
1496 SimpleThread::sleep(900);
1499 if (patience
<= 0) {
1500 errln("patience exceeded. ");
1501 // while (TRUE) {SimpleThread::sleep(10000);} // TODO: for debugging. Sleep forever on failure.
1506 SimpleThread::errorFunc();
1512 Don't clean up if there are errors. This prevents crashes if the
1513 threads are still running and using this data. This will only happen
1514 if there is an error with the test, ICU, or the machine is too slow.
1515 It's better to leak than crash.
1517 for(j
= 0; j
< kStringThreadThreads
; j
++) {
1528 #endif // ICU_USE_THREADS