1 /********************************************************************
3 * Copyright (c) 1999-2006, 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(U_WINDOWS) && !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
76 #define TSMTHREAD_FAIL(msg) errln("%s at file %s, line %d", msg, __FILE__, __LINE__)
77 #define TSMTHREAD_ASSERT(expr) {if (!(expr)) {TSMTHREAD_FAIL("Fail");}}
79 MultithreadTest::MultithreadTest()
83 MultithreadTest::~MultithreadTest()
89 #if (ICU_USE_THREADS==0)
90 void MultithreadTest::runIndexedTest( int32_t index
, UBool exec
,
91 const char* &name
, char* /*par*/ ) {
92 if (exec
) logln("TestSuite MultithreadTest: ");
95 name
= "NO_THREADED_TESTS";
99 if(exec
) { logln("MultithreadTest - test DISABLED. ICU_USE_THREADS set to 0, check your configuration if this is a problem..");
106 // Note: A LOT OF THE FUNCTIONS IN THIS FILE SHOULD LIVE ELSEWHERE!!!!!
107 // Note: A LOT OF THE FUNCTIONS IN THIS FILE SHOULD LIVE ELSEWHERE!!!!!
112 #include <ctype.h> // tolower, toupper
114 #include "unicode/putil.h"
117 #include "unicode/numfmt.h"
118 #include "unicode/choicfmt.h"
119 #include "unicode/msgfmt.h"
120 #include "unicode/locid.h"
121 #include "unicode/ucol.h"
122 #include "unicode/calendar.h"
125 //-----------------------------------------------------------------------------------
127 // class SimpleThread Of course we need a thread class first..
128 // This wrapper has a ported implementation.
130 //-----------------------------------------------------------------------------------
135 virtual ~SimpleThread();
136 int32_t start(void); // start the thread
137 UBool
isRunning(); // return true if a started thread has exited.
139 virtual void run(void) = 0; // Override this to provide the code to run
141 void *fImplementation
;
144 static void sleep(int32_t millis
); // probably shouldn't go here but oh well.
145 static void errorFunc(); // Empty function, provides a single convenient place
146 // to break on errors.
149 void SimpleThread::errorFunc() {
150 // *(char *)0 = 3; // Force entry into a debugger via a crash;
159 # define VC_EXTRALEAN
160 # define WIN32_LEAN_AND_MEAN
170 //-----------------------------------------------------------------------------------
172 // class SimpleThread Windows Implementation
174 //-----------------------------------------------------------------------------------
175 struct Win32ThreadImplementation
178 unsigned int fThreadID
;
182 extern "C" unsigned int __stdcall
SimpleThreadProc(void *arg
)
184 ((SimpleThread
*)arg
)->run();
188 SimpleThread::SimpleThread()
191 Win32ThreadImplementation
*imp
= new Win32ThreadImplementation
;
193 fImplementation
= imp
;
196 SimpleThread::~SimpleThread()
198 // Destructor. Because we start the thread running with _beginthreadex(),
199 // we own the Windows HANDLE for the thread and must
201 Win32ThreadImplementation
*imp
= (Win32ThreadImplementation
*)fImplementation
;
203 if (imp
->fHandle
!= 0) {
204 CloseHandle(imp
->fHandle
);
208 delete (Win32ThreadImplementation
*)fImplementation
;
211 int32_t SimpleThread::start()
213 Win32ThreadImplementation
*imp
= (Win32ThreadImplementation
*)fImplementation
;
214 if(imp
->fHandle
!= NULL
) {
215 // The thread appears to have already been started.
216 // This is probably an error on the part of our caller.
220 imp
->fHandle
= (HANDLE
) _beginthreadex(
222 0x20000, // Stack Size
223 SimpleThreadProc
, // Function to Run
224 (void *)this, // Arg List
225 0, // initflag. Start running, not suspended
226 &imp
->fThreadID
// thraddr
229 if (imp
->fHandle
== 0) {
241 UBool
SimpleThread::isRunning() {
243 // Test whether the thread associated with the SimpleThread object is
244 // still actually running.
246 // NOTE: on Win64 on Itanium processors, a crashes
247 // occur if the main thread of a process exits concurrently with some
248 // other thread(s) exiting. To avoid the possibility, we wait until the
249 // OS indicates that all threads have terminated, rather than waiting
250 // only until the end of the user's Run function has been reached.
252 // I don't know whether the crashes represent a Windows bug, or whether
253 // main() programs are supposed to have to wait for their threads.
255 Win32ThreadImplementation
*imp
= (Win32ThreadImplementation
*)fImplementation
;
258 DWORD threadExitCode
;
260 if (imp
->fHandle
== 0) {
261 // No handle, thread must not be running.
264 success
= GetExitCodeThread(imp
->fHandle
, &threadExitCode
) != 0;
266 // Can't get status, thread must not be running.
269 return (threadExitCode
== STILL_ACTIVE
);
273 void SimpleThread::sleep(int32_t millis
)
278 //-----------------------------------------------------------------------------------
280 // class SimpleThread NULL Implementation
282 //-----------------------------------------------------------------------------------
285 // since the Mac has no preemptive threading (at least on MacOS 8), only
286 // cooperative threading, threads are a no-op. We have no yield() calls
287 // anywhere in the ICU, so we are guaranteed to be thread-safe.
291 SimpleThread::SimpleThread()
294 SimpleThread::~SimpleThread()
298 SimpleThread::start()
306 SimpleThread::sleep(int32_t millis
)
310 SimpleThread::isRunning() {
317 //-----------------------------------------------------------------------------------
319 // class SimpleThread POSIX implementation
321 // A note on the POSIX vs the Windows implementations of this class..
322 // On Windows, the main thread must verify that other threads have finished
323 // before exiting, or crashes occasionally occur. (Seen on Itanium Win64 only)
324 // The function SimpleThread::isRunning() is used for this purpose.
326 // On POSIX, there is NO reliable non-blocking mechanism to determine
327 // whether a thread has exited. pthread_kill(thread, 0) almost works,
328 // but the system can recycle thread ids immediately, so seeing that a
329 // thread exists with this call could mean that the original thread has
330 // finished and a new one started with the same ID. Useless.
332 // So we need to do the check with user code, by setting a flag just before
333 // the thread function returns. A technique that is guaranteed to fail
334 // on Windows, because it indicates that the thread is done before all
335 // system level cleanup has happened.
337 //-----------------------------------------------------------------------------------
338 #if defined(POSIX)||defined(U_SOLARIS)||defined(U_AIX)||defined(U_HPUX)
341 struct PosixThreadImplementation
345 UBool fRan
; /* True if the thread was successfully started */
348 extern "C" void* SimpleThreadProc(void *arg
)
350 // This is the code that is run in the new separate thread.
351 SimpleThread
*This
= (SimpleThread
*)arg
;
352 This
->run(); // Run the user code.
354 // The user function has returned. Set the flag indicating that this thread
355 // is done. Need a mutex for memory barrier purposes only, so that other thread
356 // will reliably see that the flag has changed.
357 PosixThreadImplementation
*imp
= (PosixThreadImplementation
*)This
->fImplementation
;
359 imp
->fRunning
= FALSE
;
364 SimpleThread::SimpleThread()
366 PosixThreadImplementation
*imp
= new PosixThreadImplementation
;
367 imp
->fRunning
= FALSE
;
369 fImplementation
= imp
;
372 SimpleThread::~SimpleThread()
374 PosixThreadImplementation
*imp
= (PosixThreadImplementation
*)fImplementation
;
376 pthread_join(imp
->fThread
, NULL
);
379 fImplementation
= (void *)0xdeadbeef;
382 int32_t SimpleThread::start()
385 static pthread_attr_t attr
;
386 static UBool attrIsInitialized
= FALSE
;
388 PosixThreadImplementation
*imp
= (PosixThreadImplementation
*)fImplementation
;
389 imp
->fRunning
= TRUE
;
393 if (attrIsInitialized
== FALSE
) {
394 rc
= pthread_attr_create(&attr
);
395 attrIsInitialized
= TRUE
;
397 rc
= pthread_create(&(imp
->fThread
),attr
,&SimpleThreadProc
,(void*)this);
399 if (attrIsInitialized
== FALSE
) {
400 rc
= pthread_attr_init(&attr
);
403 int detachstate
= 0; /* jdc30: detach state of zero causes
404 threads created with this attr to be in
405 an undetached state. An undetached
406 thread will keep its resources after
408 pthread_attr_setdetachstate(&attr
, &detachstate
);
411 // pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
412 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_JOINABLE
);
414 attrIsInitialized
= TRUE
;
416 rc
= pthread_create(&(imp
->fThread
),&attr
,&SimpleThreadProc
,(void*)this);
420 // some kind of error occured, the thread did not start.
422 imp
->fRunning
= FALSE
;
430 SimpleThread::isRunning() {
431 // Note: Mutex functions are used here not for synchronization,
432 // but to force memory barriors to exist, to ensure that one thread
433 // can see changes made by another when running on processors
434 // with memory models having weak coherency.
435 PosixThreadImplementation
*imp
= (PosixThreadImplementation
*)fImplementation
;
437 UBool retVal
= imp
->fRunning
;
443 void SimpleThread::sleep(int32_t millis
)
450 cma_sleep(millis
/100);
451 #elif defined(U_HPUX) || defined(OS390)
453 while(millis
>= 1000000) {
461 usleep(millis
* 1000);
470 #error No implementation for threads! Cannot test.
475 // *************** end fluff ******************
477 /* now begins the real test. */
478 void MultithreadTest::runIndexedTest( int32_t index
, UBool exec
,
479 const char* &name
, char* /*par*/ ) {
481 logln("TestSuite MultithreadTest: ");
484 name
= "TestThreads";
496 name
= "TestThreadedIntl";
497 #if !UCONFIG_NO_FORMATTING
505 name
= "TestCollators";
506 #if !UCONFIG_NO_COLLATION
510 #endif /* #if !UCONFIG_NO_COLLATION */
522 break; //needed to end loop
527 //-----------------------------------------------------------------------------------
529 // TestThreads -- see if threads really work at all.
531 // Set up N threads pointing at N chars. When they are started, they will
532 // each sleep 1 second and then set their chars. At the end we make sure they
535 //-----------------------------------------------------------------------------------
536 #define THREADTEST_NRTHREADS 8
538 class TestThreadsThread
: public SimpleThread
541 TestThreadsThread(char* whatToChange
) { fWhatToChange
= whatToChange
; }
542 virtual void run() { SimpleThread::sleep(1000);
544 *fWhatToChange
= '*';
550 void MultithreadTest::TestThreads()
552 char threadTestChars
[THREADTEST_NRTHREADS
+ 1];
553 SimpleThread
*threads
[THREADTEST_NRTHREADS
];
554 int32_t numThreadsStarted
= 0;
557 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
559 threadTestChars
[i
] = ' ';
560 threads
[i
] = new TestThreadsThread(&threadTestChars
[i
]);
562 threadTestChars
[THREADTEST_NRTHREADS
] = '\0';
564 logln("->" + UnicodeString(threadTestChars
) + "<- Firing off threads.. ");
565 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
567 if (threads
[i
]->start() != 0) {
568 errln("Error starting thread %d", i
);
573 SimpleThread::sleep(100);
574 logln(" Subthread started.");
577 logln("Waiting for threads to be set..");
578 if (numThreadsStarted
== 0) {
579 errln("No threads could be started for testing!");
583 int32_t patience
= 40; // seconds to wait
589 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
591 if(threadTestChars
[i
] == '*')
598 if(count
== THREADTEST_NRTHREADS
)
600 logln("->" + UnicodeString(threadTestChars
) + "<- Got all threads! cya");
601 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
608 logln("->" + UnicodeString(threadTestChars
) + "<- Waiting..");
609 SimpleThread::sleep(500);
612 errln("->" + UnicodeString(threadTestChars
) + "<- PATIENCE EXCEEDED!! Still missing some.");
613 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
620 //-----------------------------------------------------------------------
622 // TestMutex - a simple (non-stress) test to verify that ICU mutexes
623 // are actually mutexing. Does not test the use of
624 // mutexes within ICU services, but rather that the
625 // platform's mutex support is at least superficially there.
627 //----------------------------------------------------------------------
628 static UMTX gTestMutexA
= NULL
;
629 static UMTX gTestMutexB
= NULL
;
631 static int gThreadsStarted
= 0;
632 static int gThreadsInMiddle
= 0;
633 static int gThreadsDone
= 0;
635 static const int TESTMUTEX_THREAD_COUNT
= 4;
637 static int safeIncr(int &var
, int amt
) {
638 // Thread safe (using global mutex) increment of a variable.
639 // Return the updated value.
640 // Can also be used as a safe load of a variable by incrementing it by 0.
646 class TestMutexThread
: public SimpleThread
651 // This is the code that each of the spawned threads runs.
652 // All of the spawned threads bunch up together at each of the two mutexes
653 // because the main holds the mutexes until they do.
655 safeIncr(gThreadsStarted
, 1);
656 umtx_lock(&gTestMutexA
);
657 umtx_unlock(&gTestMutexA
);
658 safeIncr(gThreadsInMiddle
, 1);
659 umtx_lock(&gTestMutexB
);
660 umtx_unlock(&gTestMutexB
);
661 safeIncr(gThreadsDone
, 1);
665 void MultithreadTest::TestMutex()
667 // Start up the test threads. They should all pile up waiting on
668 // gTestMutexA, which we (the main thread) hold until the test threads
671 gThreadsInMiddle
= 0;
673 umtx_lock(&gTestMutexA
);
674 TestMutexThread
*threads
[TESTMUTEX_THREAD_COUNT
];
676 int32_t numThreadsStarted
= 0;
677 for (i
=0; i
<TESTMUTEX_THREAD_COUNT
; i
++) {
678 threads
[i
] = new TestMutexThread
;
679 if (threads
[i
]->start() != 0) {
680 errln("Error starting thread %d", i
);
686 if (numThreadsStarted
== 0) {
687 errln("No threads could be started for testing!");
692 while (safeIncr(gThreadsStarted
, 0) != TESTMUTEX_THREAD_COUNT
) {
693 if (patience
++ > 24) {
694 TSMTHREAD_FAIL("Patience Exceeded");
697 SimpleThread::sleep(500);
699 // None of the test threads should have advanced past the first mutex.
700 TSMTHREAD_ASSERT(gThreadsInMiddle
==0);
701 TSMTHREAD_ASSERT(gThreadsDone
==0);
703 // All of the test threads have made it to the first mutex.
704 // We (the main thread) now let them advance to the second mutex,
705 // where they should all pile up again.
706 umtx_lock(&gTestMutexB
);
707 umtx_unlock(&gTestMutexA
);
710 while (safeIncr(gThreadsInMiddle
, 0) != TESTMUTEX_THREAD_COUNT
) {
711 if (patience
++ > 24) {
712 TSMTHREAD_FAIL("Patience Exceeded");
715 SimpleThread::sleep(500);
717 TSMTHREAD_ASSERT(gThreadsDone
==0);
719 // All test threads made it to the second mutex.
720 // Now let them proceed from there. They will all terminate.
721 umtx_unlock(&gTestMutexB
);
723 while (safeIncr(gThreadsDone
, 0) != TESTMUTEX_THREAD_COUNT
) {
724 if (patience
++ > 24) {
725 TSMTHREAD_FAIL("Patience Exceeded");
728 SimpleThread::sleep(500);
731 // All threads made it by both mutexes.
732 // Destroy the test mutexes.
733 umtx_destroy(&gTestMutexA
);
734 umtx_destroy(&gTestMutexB
);
738 for (i
=0; i
<TESTMUTEX_THREAD_COUNT
; i
++) {
745 //-------------------------------------------------------------------------------------------
747 // class ThreadWithStatus - a thread that we can check the status and error condition of
749 //-------------------------------------------------------------------------------------------
750 class ThreadWithStatus
: public SimpleThread
753 UBool
getError() { return (fErrors
> 0); }
754 UBool
getError(UnicodeString
& fillinError
) { fillinError
= fErrorString
; return (fErrors
> 0); }
755 virtual ~ThreadWithStatus(){}
757 ThreadWithStatus() : fErrors(0) {}
758 void error(const UnicodeString
&error
) {
759 fErrors
++; fErrorString
= error
;
760 SimpleThread::errorFunc();
762 void error() { error("An error occured."); }
765 UnicodeString fErrorString
;
770 //-------------------------------------------------------------------------------------------
772 // TestMultithreadedIntl. Test ICU Formatting n a multi-threaded environment
774 //-------------------------------------------------------------------------------------------
777 // * Show exactly where the string's differences lie.
778 UnicodeString
showDifference(const UnicodeString
& expected
, const UnicodeString
& result
)
781 res
= expected
+ "<Expected\n";
782 if(expected
.length() != result
.length())
783 res
+= " [ Different lengths ] \n";
786 for(int32_t i
=0;i
<expected
.length();i
++)
788 if(expected
[i
] == result
[i
])
797 res
+= "<Differences";
800 res
+= result
+ "<Result\n";
808 //-------------------------------------------------------------------------------------------
810 // FormatThreadTest - a thread that tests performing a number of numberformats.
812 //-------------------------------------------------------------------------------------------
814 const int kFormatThreadIterations
= 20; // # of iterations per thread
815 const int kFormatThreadThreads
= 10; // # of threads to spawn
816 const int kFormatThreadPatience
= 60; // time in seconds to wait for all threads
818 #if !UCONFIG_NO_FORMATTING
822 struct FormatThreadTestData
825 UnicodeString string
;
826 FormatThreadTestData(double a
, const UnicodeString
& b
) : number(a
),string(b
) {}
830 // "Someone from {2} is receiving a #{0} error - {1}. Their telephone call is costing {3 number,currency}."
832 void formatErrorMessage(UErrorCode
&realStatus
, const UnicodeString
& pattern
, const Locale
& theLocale
,
833 UErrorCode inStatus0
, /* statusString 1 */ const Locale
&inCountry2
, double currency3
, // these numbers are the message arguments.
834 UnicodeString
&result
)
836 if(U_FAILURE(realStatus
))
837 return; // you messed up
839 UnicodeString
errString1(u_errorName(inStatus0
));
841 UnicodeString countryName2
;
842 inCountry2
.getDisplayCountry(theLocale
,countryName2
);
844 Formattable myArgs
[] = {
845 Formattable((int32_t)inStatus0
), // inStatus0 {0}
846 Formattable(errString1
), // statusString1 {1}
847 Formattable(countryName2
), // inCountry2 {2}
848 Formattable(currency3
)// currency3 {3,number,currency}
851 MessageFormat
*fmt
= new MessageFormat("MessageFormat's API is broken!!!!!!!!!!!",realStatus
);
852 fmt
->setLocale(theLocale
);
853 fmt
->applyPattern(pattern
, realStatus
);
855 if (U_FAILURE(realStatus
)) {
860 FieldPosition ignore
= 0;
861 fmt
->format(myArgs
,4,result
,ignore
,realStatus
);
867 UBool U_CALLCONV
isAcceptable(void *, const char *, const char *, const UDataInfo
*) {
871 //static UMTX debugMutex = NULL;
872 //static UMTX gDebugMutex;
875 class FormatThreadTest
: public ThreadWithStatus
881 FormatThreadTest() // constructor is NOT multithread safe.
882 : ThreadWithStatus(),
888 static int32_t fgOffset
= 0;
897 NumberFormat
*formatter
= NULL
;
898 NumberFormat
*percentFormatter
= NULL
;
899 UErrorCode status
= U_ZERO_ERROR
;
903 for (int i
=0; i
<4000; i
++) {
904 status
= U_ZERO_ERROR
;
905 UDataMemory
*data1
= udata_openChoice(0, "res", "en_US", isAcceptable
, 0, &status
);
906 UDataMemory
*data2
= udata_openChoice(0, "res", "fr", isAcceptable
, 0, &status
);
909 if (U_FAILURE(status
)) {
910 error("udata_openChoice failed.\n");
920 for (m
=0; m
<4000; m
++) {
921 status
= U_ZERO_ERROR
;
922 UResourceBundle
*res
= NULL
;
923 const char *localeName
= NULL
;
925 Locale loc
= Locale::getEnglish();
927 localeName
= loc
.getName();
928 // localeName = "en";
930 // ResourceBundle bund = ResourceBundle(0, loc, status);
931 //umtx_lock(&gDebugMutex);
932 res
= ures_open(NULL
, localeName
, &status
);
933 //umtx_unlock(&gDebugMutex);
935 //umtx_lock(&gDebugMutex);
937 //umtx_unlock(&gDebugMutex);
939 if (U_FAILURE(status
)) {
940 error("Resource bundle construction failed.\n");
947 // Keep this data here to avoid static initialization.
948 FormatThreadTestData kNumberFormatTestData
[] =
950 FormatThreadTestData((double)5.0, UnicodeString("5", "")),
951 FormatThreadTestData( 6.0, UnicodeString("6", "")),
952 FormatThreadTestData( 20.0, UnicodeString("20", "")),
953 FormatThreadTestData( 8.0, UnicodeString("8", "")),
954 FormatThreadTestData( 8.3, UnicodeString("8.3", "")),
955 FormatThreadTestData( 12345, UnicodeString("12,345", "")),
956 FormatThreadTestData( 81890.23, UnicodeString("81,890.23", "")),
958 int32_t kNumberFormatTestDataLength
= (int32_t)(sizeof(kNumberFormatTestData
) /
959 sizeof(kNumberFormatTestData
[0]));
961 // Keep this data here to avoid static initialization.
962 FormatThreadTestData kPercentFormatTestData
[] =
964 FormatThreadTestData((double)5.0, UnicodeString("500%", "")),
965 FormatThreadTestData( 1.0, UnicodeString("100%", "")),
966 FormatThreadTestData( 0.26, UnicodeString("26%", "")),
967 FormatThreadTestData(
968 16384.99, CharsToUnicodeString("1\\u00a0638\\u00a0499%") ), // U+00a0 = NBSP
969 FormatThreadTestData(
970 81890.23, CharsToUnicodeString("8\\u00a0189\\u00a0023%" )),
972 int32_t kPercentFormatTestDataLength
=
973 (int32_t)(sizeof(kPercentFormatTestData
) / sizeof(kPercentFormatTestData
[0]));
976 status
= U_ZERO_ERROR
;
977 formatter
= NumberFormat::createInstance(Locale::getEnglish(),status
);
978 if(U_FAILURE(status
)) {
979 error("Error on NumberFormat::createInstance()");
980 goto cleanupAndReturn
;
983 percentFormatter
= NumberFormat::createPercentInstance(Locale::getFrench(),status
);
984 if(U_FAILURE(status
)) {
985 error("Error on NumberFormat::createPercentInstance()");
986 goto cleanupAndReturn
;
989 for(iteration
= 0;!getError() && iteration
<kFormatThreadIterations
;iteration
++)
992 int32_t whichLine
= (iteration
+ fOffset
)%kNumberFormatTestDataLength
;
994 UnicodeString output
;
996 formatter
->format(kNumberFormatTestData
[whichLine
].number
, output
);
998 if(0 != output
.compare(kNumberFormatTestData
[whichLine
].string
)) {
999 error("format().. expected " + kNumberFormatTestData
[whichLine
].string
1000 + " got " + output
);
1001 goto cleanupAndReturn
;
1004 // Now check percent.
1006 whichLine
= (iteration
+ fOffset
)%kPercentFormatTestDataLength
;
1008 percentFormatter
->format(kPercentFormatTestData
[whichLine
].number
, output
);
1009 if(0 != output
.compare(kPercentFormatTestData
[whichLine
].string
))
1011 error("percent format().. \n" +
1012 showDifference(kPercentFormatTestData
[whichLine
].string
,output
));
1013 goto cleanupAndReturn
;
1016 // Test message error
1017 const int kNumberOfMessageTests
= 3;
1018 UErrorCode statusToCheck
;
1019 UnicodeString patternToCheck
;
1020 Locale messageLocale
;
1021 Locale countryToCheck
;
1022 double currencyToCheck
;
1024 UnicodeString expected
;
1027 switch((iteration
+fOffset
) % kNumberOfMessageTests
)
1031 statusToCheck
= U_FILE_ACCESS_ERROR
;
1032 patternToCheck
= "0:Someone from {2} is receiving a #{0}"
1033 " error - {1}. Their telephone call is costing "
1034 "{3,number,currency}."; // number,currency
1035 messageLocale
= Locale("en","US");
1036 countryToCheck
= Locale("","HR");
1037 currencyToCheck
= 8192.77;
1038 expected
= "0:Someone from Croatia is receiving a #4 error - "
1039 "U_FILE_ACCESS_ERROR. Their telephone call is costing $8,192.77.";
1042 statusToCheck
= U_INDEX_OUTOFBOUNDS_ERROR
;
1043 patternToCheck
= "1:A customer in {2} is receiving a #{0} error - {1}. Their telephone call is costing {3,number,currency}."; // number,currency
1044 messageLocale
= Locale("de","DE@currency=DEM");
1045 countryToCheck
= Locale("","BF");
1046 currencyToCheck
= 2.32;
1047 expected
= "1:A customer in Burkina Faso is receiving a #8 error - U_INDEX_OUTOFBOUNDS_ERROR. Their telephone call is costing 2,32 DM.";
1050 statusToCheck
= U_MEMORY_ALLOCATION_ERROR
;
1051 patternToCheck
= "2:user in {2} is receiving a #{0} error - {1}. "
1052 "They insist they just spent {3,number,currency} "
1053 "on memory."; // number,currency
1054 messageLocale
= Locale("de","AT@currency=ATS"); // Austrian German
1055 countryToCheck
= Locale("","US"); // hmm
1056 currencyToCheck
= 40193.12;
1057 expected
= CharsToUnicodeString(
1058 "2:user in Vereinigte Staaten is receiving a #7 error"
1059 " - U_MEMORY_ALLOCATION_ERROR. They insist they just spent"
1060 " \\u00f6S 40.193,12 on memory.");
1064 UnicodeString result
;
1065 UErrorCode status
= U_ZERO_ERROR
;
1066 formatErrorMessage(status
,patternToCheck
,messageLocale
,statusToCheck
,
1067 countryToCheck
,currencyToCheck
,result
);
1068 if(U_FAILURE(status
))
1070 UnicodeString
tmp(u_errorName(status
));
1071 error("Failure on message format, pattern=" + patternToCheck
+
1072 ", error = " + tmp
);
1073 goto cleanupAndReturn
;
1076 if(result
!= expected
)
1078 error("PatternFormat: \n" + showDifference(expected
,result
));
1079 goto cleanupAndReturn
;
1081 } /* end of for loop */
1085 delete percentFormatter
;
1087 // while (fNum == 4) {SimpleThread::sleep(10000);} // Force a failure by preventing thread from finishing
1092 int32_t fOffset
; // where we are testing from.
1095 // ** The actual test function.
1097 void MultithreadTest::TestThreadedIntl()
1100 UnicodeString theErr
;
1101 UBool haveDisplayedInfo
[kFormatThreadThreads
];
1102 static const int32_t PATIENCE_SECONDS
= 45;
1105 // Create and start the test threads
1107 logln("Spawning: %d threads * %d iterations each.",
1108 kFormatThreadThreads
, kFormatThreadIterations
);
1109 FormatThreadTest
*tests
= new FormatThreadTest
[kFormatThreadThreads
];
1110 for(int32_t j
= 0; j
< kFormatThreadThreads
; j
++) {
1112 int32_t threadStatus
= tests
[j
].start();
1113 if (threadStatus
!= 0) {
1114 errln("System Error %d starting thread number %d.", threadStatus
, j
);
1115 SimpleThread::errorFunc();
1116 goto cleanupAndReturn
;
1118 haveDisplayedInfo
[j
] = FALSE
;
1122 // Spin, waiting for the test threads to finish.
1124 UDate startTime
, endTime
;
1125 startTime
= Calendar::getNow();
1127 /* Spin until the test threads complete. */
1128 stillRunning
= FALSE
;
1129 endTime
= Calendar::getNow();
1130 if (((int32_t)(endTime
- startTime
)/U_MILLIS_PER_SECOND
) > PATIENCE_SECONDS
) {
1131 errln("Patience exceeded. Test is taking too long.");
1135 The following sleep must be here because the *BSD operating systems
1136 have a brain dead thread scheduler. They starve the child threads from
1139 SimpleThread::sleep(1); // yield
1140 for(i
=0;i
<kFormatThreadThreads
;i
++) {
1141 if (tests
[i
].isRunning()) {
1142 stillRunning
= TRUE
;
1143 } else if (haveDisplayedInfo
[i
] == FALSE
) {
1144 logln("Thread # %d is complete..", i
);
1145 if(tests
[i
].getError(theErr
)) {
1146 errln(UnicodeString("#") + i
+ ": " + theErr
);
1147 SimpleThread::errorFunc();
1149 haveDisplayedInfo
[i
] = TRUE
;
1152 } while (stillRunning
);
1155 // All threads have finished.
1160 #endif /* #if !UCONFIG_NO_FORMATTING */
1166 //-------------------------------------------------------------------------------------------
1168 // Collation threading test
1170 //-------------------------------------------------------------------------------------------
1171 #if !UCONFIG_NO_COLLATION
1173 #define kCollatorThreadThreads 10 // # of threads to spawn
1174 #define kCollatorThreadPatience kCollatorThreadThreads*30
1181 class CollatorThreadTest
: public ThreadWithStatus
1184 const UCollator
*coll
;
1188 CollatorThreadTest() : ThreadWithStatus(),
1194 void setCollator(UCollator
*c
, Line
*l
, int32_t nl
)
1200 virtual void run() {
1204 uint8_t sk1
[1024], sk2
[1024];
1205 uint8_t *oldSk
= NULL
, *newSk
= sk1
;
1206 int32_t resLen
= 0, oldLen
= 0;
1209 for(i
= 0; i
< noLines
; i
++) {
1210 resLen
= ucol_getSortKey(coll
, lines
[i
].buff
, lines
[i
].buflen
, newSk
, 1024);
1212 int32_t res
= 0, cmpres
= 0, cmpres2
= 0;
1215 res
= strcmp((char *)oldSk
, (char *)newSk
);
1216 cmpres
= ucol_strcoll(coll
, lines
[i
-1].buff
, lines
[i
-1].buflen
, lines
[i
].buff
, lines
[i
].buflen
);
1217 cmpres2
= ucol_strcoll(coll
, lines
[i
].buff
, lines
[i
].buflen
, lines
[i
-1].buff
, lines
[i
-1].buflen
);
1219 //cmpres2 = -cmpres;
1221 if(cmpres
!= -cmpres2
) {
1222 error("Compare result not symmetrical on line "+ line
);
1226 if(((res
&0x80000000) != (cmpres
&0x80000000)) || (res
== 0 && cmpres
!= 0) || (res
!= 0 && cmpres
== 0)) {
1227 error(UnicodeString("Difference between ucol_strcoll and sortkey compare on line ")+ UnicodeString(line
));
1232 error(UnicodeString("Line %i is not greater or equal than previous line ")+ UnicodeString(i
));
1234 } else if(res
== 0) { /* equal */
1235 res
= u_strcmpCodePointOrder(lines
[i
-1].buff
, lines
[i
].buff
);
1237 error(UnicodeString("Probable error in test file on line %i (comparing identical strings)")+ UnicodeString(i
));
1239 } else if (res
> 0) {
1240 error(UnicodeString("Sortkeys are identical, but code point comapare gives >0 on line ")+ UnicodeString(i
));
1249 newSk
= (newSk
== sk1
)?sk2
:sk1
;
1255 void MultithreadTest::TestCollators()
1258 UErrorCode status
= U_ZERO_ERROR
;
1259 FILE *testFile
= NULL
;
1260 char testDataPath
[1024];
1261 strcpy(testDataPath
, IntlTest::getSourceTestData(status
));
1262 if (U_FAILURE(status
)) {
1263 errln("ERROR: could not open test data %s", u_errorName(status
));
1266 strcat(testDataPath
, "CollationTest_");
1268 const char* type
= "NON_IGNORABLE";
1270 const char *ext
= ".txt";
1275 strcpy(buffer
, testDataPath
);
1276 strcat(buffer
, type
);
1277 size_t bufLen
= strlen(buffer
);
1279 // we try to open 3 files:
1280 // path/CollationTest_type.txt
1281 // path/CollationTest_type_SHORT.txt
1282 // path/CollationTest_type_STUB.txt
1283 // we are going to test with the first one that we manage to open.
1285 strcpy(buffer
+bufLen
, ext
);
1287 testFile
= fopen(buffer
, "rb");
1290 strcpy(buffer
+bufLen
, "_SHORT");
1291 strcat(buffer
, ext
);
1292 testFile
= fopen(buffer
, "rb");
1295 strcpy(buffer
+bufLen
, "_STUB");
1296 strcat(buffer
, ext
);
1297 testFile
= fopen(buffer
, "rb");
1299 if (testFile
== 0) {
1300 *(buffer
+bufLen
) = 0;
1301 errln("ERROR: could not open any of the conformance test files, tried opening base %s", buffer
);
1305 "INFO: Working with the stub file.\n"
1306 "If you need the full conformance test, please\n"
1307 "download the appropriate data files from:\n"
1308 "http://dev.icu-project.org/cgi-bin/viewcvs.cgi/unicodetools/com/ibm/text/data/");
1313 Line
*lines
= new Line
[200000];
1314 memset(lines
, 0, sizeof(Line
)*200000);
1315 int32_t lineNum
= 0;
1317 UChar bufferU
[1024];
1320 uint32_t offset
= 0;
1322 while (fgets(buffer
, 1024, testFile
) != NULL
) {
1324 if(*buffer
== 0 || strlen(buffer
) < 3 || buffer
[0] == '#') {
1327 offset
= u_parseString(buffer
, bufferU
, 1024, &first
, &status
);
1329 bufferU
[offset
++] = 0;
1330 lines
[lineNum
].buflen
= buflen
;
1331 //lines[lineNum].buff = new UChar[buflen+1];
1332 u_memcpy(lines
[lineNum
].buff
, bufferU
, buflen
);
1336 if(U_FAILURE(status
)) {
1337 errln("Couldn't read the test file!");
1341 UCollator
*coll
= ucol_open("root", &status
);
1342 if(U_FAILURE(status
)) {
1343 errln("Couldn't open UCA collator");
1346 ucol_setAttribute(coll
, UCOL_NORMALIZATION_MODE
, UCOL_ON
, &status
);
1347 ucol_setAttribute(coll
, UCOL_CASE_FIRST
, UCOL_OFF
, &status
);
1348 ucol_setAttribute(coll
, UCOL_CASE_LEVEL
, UCOL_OFF
, &status
);
1349 ucol_setAttribute(coll
, UCOL_STRENGTH
, UCOL_TERTIARY
, &status
);
1350 ucol_setAttribute(coll
, UCOL_ALTERNATE_HANDLING
, UCOL_NON_IGNORABLE
, &status
);
1352 int32_t noSpawned
= 0;
1353 int32_t spawnResult
= 0;
1354 CollatorThreadTest
*tests
;
1355 tests
= new CollatorThreadTest
[kCollatorThreadThreads
];
1357 logln(UnicodeString("Spawning: ") + kCollatorThreadThreads
+ " threads * " + kFormatThreadIterations
+ " iterations each.");
1359 for(j
= 0; j
< kCollatorThreadThreads
; j
++) {
1360 //logln("Setting collator %i", j);
1361 tests
[j
].setCollator(coll
, lines
, lineNum
);
1363 for(j
= 0; j
< kCollatorThreadThreads
; j
++) {
1365 spawnResult
= tests
[j
].start();
1366 if(spawnResult
!= 0) {
1367 infoln("THREAD INFO: Couldn't spawn more than %i threads", noSpawned
);
1372 logln("Spawned all");
1373 if (noSpawned
== 0) {
1374 errln("No threads could be spawned.");
1378 for(int32_t patience
= kCollatorThreadPatience
;patience
> 0; patience
--)
1380 logln("Waiting...");
1384 int32_t completed
=0;
1386 for(i
=0;i
<kCollatorThreadThreads
;i
++)
1388 if (tests
[i
].isRunning() == FALSE
)
1392 //logln(UnicodeString("Test #") + i + " is complete.. ");
1394 UnicodeString theErr
;
1395 if(tests
[i
].getError(theErr
))
1398 errln(UnicodeString("#") + i
+ ": " + theErr
);
1400 // print out the error, too, if any.
1403 logln("Completed %i tests", completed
);
1405 if(completed
== noSpawned
)
1407 logln("Done! All %i tests are finished", noSpawned
);
1411 errln("There were errors.");
1412 SimpleThread::errorFunc();
1416 //for(i = 0; i < lineNum; i++) {
1417 //delete[] lines[i].buff;
1424 SimpleThread::sleep(900);
1426 errln("patience exceeded. ");
1427 SimpleThread::errorFunc();
1431 #endif /* #if !UCONFIG_NO_COLLATION */
1436 //-------------------------------------------------------------------------------------------
1438 // StringThreadTest2
1440 //-------------------------------------------------------------------------------------------
1442 const int kStringThreadIterations
= 2500;// # of iterations per thread
1443 const int kStringThreadThreads
= 10; // # of threads to spawn
1444 const int kStringThreadPatience
= 120; // time in seconds to wait for all threads
1447 class StringThreadTest2
: public ThreadWithStatus
1452 const UnicodeString
*fSharedString
;
1454 StringThreadTest2(const UnicodeString
*sharedString
, int num
) // constructor is NOT multithread safe.
1455 : ThreadWithStatus(),
1458 fSharedString(sharedString
)
1468 for (loopCount
= 0; loopCount
< kStringThreadIterations
; loopCount
++) {
1469 if (*fSharedString
!= "This is the original test string.") {
1470 error("Original string is corrupt.");
1473 UnicodeString s1
= *fSharedString
;
1475 UnicodeString
s2(s1
);
1476 UnicodeString s3
= *fSharedString
;
1482 // while (fNum == 4) {SimpleThread::sleep(10000);} // Force a failure by preventing thread from finishing
1488 // ** The actual test function.
1490 void MultithreadTest::TestString()
1496 UnicodeString
*testString
= new UnicodeString("This is the original test string.");
1498 StringThreadTest2
*tests
[kStringThreadThreads
];
1499 for(j
= 0; j
< kStringThreadThreads
; j
++) {
1500 tests
[j
] = new StringThreadTest2(testString
, j
);
1503 logln(UnicodeString("Spawning: ") + kStringThreadThreads
+ " threads * " + kStringThreadIterations
+ " iterations each.");
1504 for(j
= 0; j
< kStringThreadThreads
; j
++) {
1505 int32_t threadStatus
= tests
[j
]->start();
1506 if (threadStatus
!= 0) {
1507 errln("System Error %d starting thread number %d.", threadStatus
, j
);
1508 SimpleThread::errorFunc();
1509 goto cleanupAndReturn
;
1513 for(patience
= kStringThreadPatience
;patience
> 0; patience
--)
1515 logln("Waiting...");
1519 int32_t completed
=0;
1521 for(i
=0;i
<kStringThreadThreads
;i
++) {
1522 if (tests
[i
]->isRunning() == FALSE
)
1526 logln(UnicodeString("Test #") + i
+ " is complete.. ");
1528 UnicodeString theErr
;
1529 if(tests
[i
]->getError(theErr
))
1532 errln(UnicodeString("#") + i
+ ": " + theErr
);
1534 // print out the error, too, if any.
1538 if(completed
== kStringThreadThreads
)
1542 errln("There were errors.");
1547 SimpleThread::sleep(900);
1550 if (patience
<= 0) {
1551 errln("patience exceeded. ");
1552 // while (TRUE) {SimpleThread::sleep(10000);} // TODO: for debugging. Sleep forever on failure.
1557 SimpleThread::errorFunc();
1563 Don't clean up if there are errors. This prevents crashes if the
1564 threads are still running and using this data. This will only happen
1565 if there is an error with the test, ICU, or the machine is too slow.
1566 It's better to leak than crash.
1568 for(j
= 0; j
< kStringThreadThreads
; j
++) {
1579 #endif // ICU_USE_THREADS