]> git.saurik.com Git - apple/icu.git/blob - icuSources/test/intltest/tsmthred.cpp
ICU-8.11.4.tar.gz
[apple/icu.git] / icuSources / test / intltest / tsmthred.cpp
1 /********************************************************************
2 * COPYRIGHT:
3 * Copyright (c) 1999-2006, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ********************************************************************/
6
7 #if defined(hpux)
8 # ifndef _INCLUDE_POSIX_SOURCE
9 # define _INCLUDE_POSIX_SOURCE
10 # endif
11 #endif
12
13 #include "unicode/utypes.h"
14 #include "unicode/ustring.h"
15 #include "umutex.h"
16 #include "cmemory.h"
17 #include "cstring.h"
18 #include "uparse.h"
19 #include "unicode/resbund.h"
20 #include "unicode/udata.h"
21 #include "unicode/uloc.h"
22 #include "unicode/locid.h"
23 #include "putilimp.h"
24 #if !defined(U_WINDOWS) && !defined(XP_MAC) && !defined(U_RHAPSODY)
25 #define POSIX 1
26 #endif
27
28 #if defined(POSIX) || defined(U_SOLARIS) || defined(U_AIX) || defined(U_HPUX)
29
30 #define HAVE_IMP
31
32 #if (ICU_USE_THREADS == 1)
33 #include <pthread.h>
34 #endif
35
36 #if defined(__hpux) && defined(HPUX_CMA)
37 # if defined(read) // read being defined as cma_read causes trouble with iostream::read
38 # undef read
39 # endif
40 #endif
41
42 /* Define __EXTENSIONS__ for Solaris and old friends in strict mode. */
43 #ifndef __EXTENSIONS__
44 #define __EXTENSIONS__
45 #endif
46
47 #include <signal.h>
48
49 /* Define _XPG4_2 for Solaris and friends. */
50 #ifndef _XPG4_2
51 #define _XPG4_2
52 #endif
53
54 /* Define __USE_XOPEN_EXTENDED for Linux and glibc. */
55 #ifndef __USE_XOPEN_EXTENDED
56 #define __USE_XOPEN_EXTENDED
57 #endif
58
59 /* Define _INCLUDE_XOPEN_SOURCE_EXTENDED for HP/UX (11?). */
60 #ifndef _INCLUDE_XOPEN_SOURCE_EXTENDED
61 #define _INCLUDE_XOPEN_SOURCE_EXTENDED
62 #endif
63
64 #include <unistd.h>
65
66 #endif
67 /* HPUX */
68 #ifdef sleep
69 #undef sleep
70 #endif
71
72
73
74 #include "tsmthred.h"
75
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");}}
78
79 MultithreadTest::MultithreadTest()
80 {
81 }
82
83 MultithreadTest::~MultithreadTest()
84 {
85 }
86
87
88
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: ");
93
94 if(index == 0)
95 name = "NO_THREADED_TESTS";
96 else
97 name = "";
98
99 if(exec) { logln("MultithreadTest - test DISABLED. ICU_USE_THREADS set to 0, check your configuration if this is a problem..");
100 }
101 }
102 #else
103
104
105
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!!!!!
108 // -srl
109
110 #include <stdio.h>
111 #include <string.h>
112 #include <ctype.h> // tolower, toupper
113
114 #include "unicode/putil.h"
115
116 /* for mthreadtest*/
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"
123 #include "ucaconf.h"
124
125 //-----------------------------------------------------------------------------------
126 //
127 // class SimpleThread Of course we need a thread class first..
128 // This wrapper has a ported implementation.
129 //
130 //-----------------------------------------------------------------------------------
131 class SimpleThread
132 {
133 public:
134 SimpleThread();
135 virtual ~SimpleThread();
136 int32_t start(void); // start the thread
137 UBool isRunning(); // return true if a started thread has exited.
138
139 virtual void run(void) = 0; // Override this to provide the code to run
140 // in the thread.
141 void *fImplementation;
142
143 public:
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.
147 };
148
149 void SimpleThread::errorFunc() {
150 // *(char *)0 = 3; // Force entry into a debugger via a crash;
151 }
152
153
154
155
156 #ifdef U_WINDOWS
157 #define HAVE_IMP
158
159 # define VC_EXTRALEAN
160 # define WIN32_LEAN_AND_MEAN
161 # define NOUSER
162 # define NOSERVICE
163 # define NOIME
164 # define NOMCX
165 #include <windows.h>
166 #include <process.h>
167
168
169
170 //-----------------------------------------------------------------------------------
171 //
172 // class SimpleThread Windows Implementation
173 //
174 //-----------------------------------------------------------------------------------
175 struct Win32ThreadImplementation
176 {
177 HANDLE fHandle;
178 unsigned int fThreadID;
179 };
180
181
182 extern "C" unsigned int __stdcall SimpleThreadProc(void *arg)
183 {
184 ((SimpleThread*)arg)->run();
185 return 0;
186 }
187
188 SimpleThread::SimpleThread()
189 :fImplementation(0)
190 {
191 Win32ThreadImplementation *imp = new Win32ThreadImplementation;
192 imp->fHandle = 0;
193 fImplementation = imp;
194 }
195
196 SimpleThread::~SimpleThread()
197 {
198 // Destructor. Because we start the thread running with _beginthreadex(),
199 // we own the Windows HANDLE for the thread and must
200 // close it here.
201 Win32ThreadImplementation *imp = (Win32ThreadImplementation*)fImplementation;
202 if (imp != 0) {
203 if (imp->fHandle != 0) {
204 CloseHandle(imp->fHandle);
205 imp->fHandle = 0;
206 }
207 }
208 delete (Win32ThreadImplementation*)fImplementation;
209 }
210
211 int32_t SimpleThread::start()
212 {
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.
217 return -1;
218 }
219
220 imp->fHandle = (HANDLE) _beginthreadex(
221 NULL, // Security
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
227 );
228
229 if (imp->fHandle == 0) {
230 // An error occured
231 int err = errno;
232 if (err == 0) {
233 err = -1;
234 }
235 return err;
236 }
237 return 0;
238 }
239
240
241 UBool SimpleThread::isRunning() {
242 //
243 // Test whether the thread associated with the SimpleThread object is
244 // still actually running.
245 //
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.
251 //
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.
254 //
255 Win32ThreadImplementation *imp = (Win32ThreadImplementation*)fImplementation;
256
257 bool success;
258 DWORD threadExitCode;
259
260 if (imp->fHandle == 0) {
261 // No handle, thread must not be running.
262 return FALSE;
263 }
264 success = GetExitCodeThread(imp->fHandle, &threadExitCode) != 0;
265 if (! success) {
266 // Can't get status, thread must not be running.
267 return FALSE;
268 }
269 return (threadExitCode == STILL_ACTIVE);
270 }
271
272
273 void SimpleThread::sleep(int32_t millis)
274 {
275 ::Sleep(millis);
276 }
277
278 //-----------------------------------------------------------------------------------
279 //
280 // class SimpleThread NULL Implementation
281 //
282 //-----------------------------------------------------------------------------------
283 #elif defined XP_MAC
284
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.
288
289 #define HAVE_IMP
290
291 SimpleThread::SimpleThread()
292 {}
293
294 SimpleThread::~SimpleThread()
295 {}
296
297 int32_t
298 SimpleThread::start()
299 { return 0; }
300
301 void
302 SimpleThread::run()
303 {}
304
305 void
306 SimpleThread::sleep(int32_t millis)
307 {}
308
309 UBool
310 SimpleThread::isRunning() {
311 return FALSE;
312 }
313
314 #endif
315
316
317 //-----------------------------------------------------------------------------------
318 //
319 // class SimpleThread POSIX implementation
320 //
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.
325 //
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.
331 //
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.
336 //
337 //-----------------------------------------------------------------------------------
338 #if defined(POSIX)||defined(U_SOLARIS)||defined(U_AIX)||defined(U_HPUX)
339 #define HAVE_IMP
340
341 struct PosixThreadImplementation
342 {
343 pthread_t fThread;
344 UBool fRunning;
345 UBool fRan; /* True if the thread was successfully started */
346 };
347
348 extern "C" void* SimpleThreadProc(void *arg)
349 {
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.
353
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;
358 umtx_lock(NULL);
359 imp->fRunning = FALSE;
360 umtx_unlock(NULL);
361 return 0;
362 }
363
364 SimpleThread::SimpleThread()
365 {
366 PosixThreadImplementation *imp = new PosixThreadImplementation;
367 imp->fRunning = FALSE;
368 imp->fRan = FALSE;
369 fImplementation = imp;
370 }
371
372 SimpleThread::~SimpleThread()
373 {
374 PosixThreadImplementation *imp = (PosixThreadImplementation*)fImplementation;
375 if (imp->fRan) {
376 pthread_join(imp->fThread, NULL);
377 }
378 delete imp;
379 fImplementation = (void *)0xdeadbeef;
380 }
381
382 int32_t SimpleThread::start()
383 {
384 int32_t rc;
385 static pthread_attr_t attr;
386 static UBool attrIsInitialized = FALSE;
387
388 PosixThreadImplementation *imp = (PosixThreadImplementation*)fImplementation;
389 imp->fRunning = TRUE;
390 imp->fRan = TRUE;
391
392 #ifdef HPUX_CMA
393 if (attrIsInitialized == FALSE) {
394 rc = pthread_attr_create(&attr);
395 attrIsInitialized = TRUE;
396 }
397 rc = pthread_create(&(imp->fThread),attr,&SimpleThreadProc,(void*)this);
398 #else
399 if (attrIsInitialized == FALSE) {
400 rc = pthread_attr_init(&attr);
401 #if defined(OS390)
402 {
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
407 termination. */
408 pthread_attr_setdetachstate(&attr, &detachstate);
409 }
410 #else
411 // pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
412 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
413 #endif
414 attrIsInitialized = TRUE;
415 }
416 rc = pthread_create(&(imp->fThread),&attr,&SimpleThreadProc,(void*)this);
417 #endif
418
419 if (rc != 0) {
420 // some kind of error occured, the thread did not start.
421 imp->fRan = FALSE;
422 imp->fRunning = FALSE;
423 }
424
425 return rc;
426 }
427
428
429 UBool
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;
436 umtx_lock(NULL);
437 UBool retVal = imp->fRunning;
438 umtx_unlock(NULL);
439 return retVal;
440 }
441
442
443 void SimpleThread::sleep(int32_t millis)
444 {
445 #ifdef U_SOLARIS
446 sigignore(SIGALRM);
447 #endif
448
449 #ifdef HPUX_CMA
450 cma_sleep(millis/100);
451 #elif defined(U_HPUX) || defined(OS390)
452 millis *= 1000;
453 while(millis >= 1000000) {
454 usleep(999999);
455 millis -= 1000000;
456 }
457 if(millis > 0) {
458 usleep(millis);
459 }
460 #else
461 usleep(millis * 1000);
462 #endif
463 }
464
465 #endif
466 // end POSIX
467
468
469 #ifndef HAVE_IMP
470 #error No implementation for threads! Cannot test.
471 0 = 216; //die
472 #endif
473
474
475 // *************** end fluff ******************
476
477 /* now begins the real test. */
478 void MultithreadTest::runIndexedTest( int32_t index, UBool exec,
479 const char* &name, char* /*par*/ ) {
480 if (exec)
481 logln("TestSuite MultithreadTest: ");
482 switch (index) {
483 case 0:
484 name = "TestThreads";
485 if (exec)
486 TestThreads();
487 break;
488
489 case 1:
490 name = "TestMutex";
491 if (exec)
492 TestMutex();
493 break;
494
495 case 2:
496 name = "TestThreadedIntl";
497 #if !UCONFIG_NO_FORMATTING
498 if (exec) {
499 TestThreadedIntl();
500 }
501 #endif
502 break;
503
504 case 3:
505 name = "TestCollators";
506 #if !UCONFIG_NO_COLLATION
507 if (exec) {
508 TestCollators();
509 }
510 #endif /* #if !UCONFIG_NO_COLLATION */
511 break;
512
513 case 4:
514 name = "TestString";
515 if (exec) {
516 TestString();
517 }
518 break;
519
520 default:
521 name = "";
522 break; //needed to end loop
523 }
524 }
525
526
527 //-----------------------------------------------------------------------------------
528 //
529 // TestThreads -- see if threads really work at all.
530 //
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
533 // are all set.
534 //
535 //-----------------------------------------------------------------------------------
536 #define THREADTEST_NRTHREADS 8
537
538 class TestThreadsThread : public SimpleThread
539 {
540 public:
541 TestThreadsThread(char* whatToChange) { fWhatToChange = whatToChange; }
542 virtual void run() { SimpleThread::sleep(1000);
543 Mutex m;
544 *fWhatToChange = '*';
545 }
546 private:
547 char *fWhatToChange;
548 };
549
550 void MultithreadTest::TestThreads()
551 {
552 char threadTestChars[THREADTEST_NRTHREADS + 1];
553 SimpleThread *threads[THREADTEST_NRTHREADS];
554 int32_t numThreadsStarted = 0;
555
556 int32_t i;
557 for(i=0;i<THREADTEST_NRTHREADS;i++)
558 {
559 threadTestChars[i] = ' ';
560 threads[i] = new TestThreadsThread(&threadTestChars[i]);
561 }
562 threadTestChars[THREADTEST_NRTHREADS] = '\0';
563
564 logln("->" + UnicodeString(threadTestChars) + "<- Firing off threads.. ");
565 for(i=0;i<THREADTEST_NRTHREADS;i++)
566 {
567 if (threads[i]->start() != 0) {
568 errln("Error starting thread %d", i);
569 }
570 else {
571 numThreadsStarted++;
572 }
573 SimpleThread::sleep(100);
574 logln(" Subthread started.");
575 }
576
577 logln("Waiting for threads to be set..");
578 if (numThreadsStarted == 0) {
579 errln("No threads could be started for testing!");
580 return;
581 }
582
583 int32_t patience = 40; // seconds to wait
584
585 while(patience--)
586 {
587 int32_t count = 0;
588 umtx_lock(NULL);
589 for(i=0;i<THREADTEST_NRTHREADS;i++)
590 {
591 if(threadTestChars[i] == '*')
592 {
593 count++;
594 }
595 }
596 umtx_unlock(NULL);
597
598 if(count == THREADTEST_NRTHREADS)
599 {
600 logln("->" + UnicodeString(threadTestChars) + "<- Got all threads! cya");
601 for(i=0;i<THREADTEST_NRTHREADS;i++)
602 {
603 delete threads[i];
604 }
605 return;
606 }
607
608 logln("->" + UnicodeString(threadTestChars) + "<- Waiting..");
609 SimpleThread::sleep(500);
610 }
611
612 errln("->" + UnicodeString(threadTestChars) + "<- PATIENCE EXCEEDED!! Still missing some.");
613 for(i=0;i<THREADTEST_NRTHREADS;i++)
614 {
615 delete threads[i];
616 }
617 }
618
619
620 //-----------------------------------------------------------------------
621 //
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.
626 //
627 //----------------------------------------------------------------------
628 static UMTX gTestMutexA = NULL;
629 static UMTX gTestMutexB = NULL;
630
631 static int gThreadsStarted = 0;
632 static int gThreadsInMiddle = 0;
633 static int gThreadsDone = 0;
634
635 static const int TESTMUTEX_THREAD_COUNT = 4;
636
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.
641 Mutex m;
642 var += amt;
643 return var;
644 }
645
646 class TestMutexThread : public SimpleThread
647 {
648 public:
649 virtual void run()
650 {
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.
654 //
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);
662 }
663 };
664
665 void MultithreadTest::TestMutex()
666 {
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
669 // all get there.
670 gThreadsStarted = 0;
671 gThreadsInMiddle = 0;
672 gThreadsDone = 0;
673 umtx_lock(&gTestMutexA);
674 TestMutexThread *threads[TESTMUTEX_THREAD_COUNT];
675 int i;
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);
681 }
682 else {
683 numThreadsStarted++;
684 }
685 }
686 if (numThreadsStarted == 0) {
687 errln("No threads could be started for testing!");
688 return;
689 }
690
691 int patience = 0;
692 while (safeIncr(gThreadsStarted, 0) != TESTMUTEX_THREAD_COUNT) {
693 if (patience++ > 24) {
694 TSMTHREAD_FAIL("Patience Exceeded");
695 return;
696 }
697 SimpleThread::sleep(500);
698 }
699 // None of the test threads should have advanced past the first mutex.
700 TSMTHREAD_ASSERT(gThreadsInMiddle==0);
701 TSMTHREAD_ASSERT(gThreadsDone==0);
702
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);
708
709 patience = 0;
710 while (safeIncr(gThreadsInMiddle, 0) != TESTMUTEX_THREAD_COUNT) {
711 if (patience++ > 24) {
712 TSMTHREAD_FAIL("Patience Exceeded");
713 return;
714 }
715 SimpleThread::sleep(500);
716 }
717 TSMTHREAD_ASSERT(gThreadsDone==0);
718
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);
722 patience = 0;
723 while (safeIncr(gThreadsDone, 0) != TESTMUTEX_THREAD_COUNT) {
724 if (patience++ > 24) {
725 TSMTHREAD_FAIL("Patience Exceeded");
726 return;
727 }
728 SimpleThread::sleep(500);
729 }
730
731 // All threads made it by both mutexes.
732 // Destroy the test mutexes.
733 umtx_destroy(&gTestMutexA);
734 umtx_destroy(&gTestMutexB);
735 gTestMutexA=NULL;
736 gTestMutexB=NULL;
737
738 for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) {
739 delete threads[i];
740 }
741
742 }
743
744
745 //-------------------------------------------------------------------------------------------
746 //
747 // class ThreadWithStatus - a thread that we can check the status and error condition of
748 //
749 //-------------------------------------------------------------------------------------------
750 class ThreadWithStatus : public SimpleThread
751 {
752 public:
753 UBool getError() { return (fErrors > 0); }
754 UBool getError(UnicodeString& fillinError) { fillinError = fErrorString; return (fErrors > 0); }
755 virtual ~ThreadWithStatus(){}
756 protected:
757 ThreadWithStatus() : fErrors(0) {}
758 void error(const UnicodeString &error) {
759 fErrors++; fErrorString = error;
760 SimpleThread::errorFunc();
761 }
762 void error() { error("An error occured."); }
763 private:
764 int32_t fErrors;
765 UnicodeString fErrorString;
766 };
767
768
769
770 //-------------------------------------------------------------------------------------------
771 //
772 // TestMultithreadedIntl. Test ICU Formatting n a multi-threaded environment
773 //
774 //-------------------------------------------------------------------------------------------
775
776
777 // * Show exactly where the string's differences lie.
778 UnicodeString showDifference(const UnicodeString& expected, const UnicodeString& result)
779 {
780 UnicodeString res;
781 res = expected + "<Expected\n";
782 if(expected.length() != result.length())
783 res += " [ Different lengths ] \n";
784 else
785 {
786 for(int32_t i=0;i<expected.length();i++)
787 {
788 if(expected[i] == result[i])
789 {
790 res += " ";
791 }
792 else
793 {
794 res += "|";
795 }
796 }
797 res += "<Differences";
798 res += "\n";
799 }
800 res += result + "<Result\n";
801
802 return res;
803 }
804
805
806
807
808 //-------------------------------------------------------------------------------------------
809 //
810 // FormatThreadTest - a thread that tests performing a number of numberformats.
811 //
812 //-------------------------------------------------------------------------------------------
813
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
817
818 #if !UCONFIG_NO_FORMATTING
819
820
821
822 struct FormatThreadTestData
823 {
824 double number;
825 UnicodeString string;
826 FormatThreadTestData(double a, const UnicodeString& b) : number(a),string(b) {}
827 } ;
828
829
830 // "Someone from {2} is receiving a #{0} error - {1}. Their telephone call is costing {3 number,currency}."
831
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)
835 {
836 if(U_FAILURE(realStatus))
837 return; // you messed up
838
839 UnicodeString errString1(u_errorName(inStatus0));
840
841 UnicodeString countryName2;
842 inCountry2.getDisplayCountry(theLocale,countryName2);
843
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}
849 };
850
851 MessageFormat *fmt = new MessageFormat("MessageFormat's API is broken!!!!!!!!!!!",realStatus);
852 fmt->setLocale(theLocale);
853 fmt->applyPattern(pattern, realStatus);
854
855 if (U_FAILURE(realStatus)) {
856 delete fmt;
857 return;
858 }
859
860 FieldPosition ignore = 0;
861 fmt->format(myArgs,4,result,ignore,realStatus);
862
863 delete fmt;
864 }
865
866
867 UBool U_CALLCONV isAcceptable(void *, const char *, const char *, const UDataInfo *) {
868 return TRUE;
869 }
870
871 //static UMTX debugMutex = NULL;
872 //static UMTX gDebugMutex;
873
874
875 class FormatThreadTest : public ThreadWithStatus
876 {
877 public:
878 int fNum;
879 int fTraceInfo;
880
881 FormatThreadTest() // constructor is NOT multithread safe.
882 : ThreadWithStatus(),
883 fNum(0),
884 fTraceInfo(0),
885 fOffset(0)
886 // the locale to use
887 {
888 static int32_t fgOffset = 0;
889 fgOffset += 3;
890 fOffset = fgOffset;
891 }
892
893
894 virtual void run()
895 {
896 fTraceInfo = 1;
897 NumberFormat *formatter = NULL;
898 NumberFormat *percentFormatter = NULL;
899 UErrorCode status = U_ZERO_ERROR;
900
901 #if 0
902 // debugging code,
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);
907 udata_close(data1);
908 udata_close(data2);
909 if (U_FAILURE(status)) {
910 error("udata_openChoice failed.\n");
911 break;
912 }
913 }
914 return;
915 #endif
916
917 #if 1
918 // debugging code,
919 int m;
920 for (m=0; m<4000; m++) {
921 status = U_ZERO_ERROR;
922 UResourceBundle *res = NULL;
923 const char *localeName = NULL;
924
925 Locale loc = Locale::getEnglish();
926
927 localeName = loc.getName();
928 // localeName = "en";
929
930 // ResourceBundle bund = ResourceBundle(0, loc, status);
931 //umtx_lock(&gDebugMutex);
932 res = ures_open(NULL, localeName, &status);
933 //umtx_unlock(&gDebugMutex);
934
935 //umtx_lock(&gDebugMutex);
936 ures_close(res);
937 //umtx_unlock(&gDebugMutex);
938
939 if (U_FAILURE(status)) {
940 error("Resource bundle construction failed.\n");
941 break;
942 }
943 }
944 return;
945 #endif
946
947 // Keep this data here to avoid static initialization.
948 FormatThreadTestData kNumberFormatTestData[] =
949 {
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", "")),
957 };
958 int32_t kNumberFormatTestDataLength = (int32_t)(sizeof(kNumberFormatTestData) /
959 sizeof(kNumberFormatTestData[0]));
960
961 // Keep this data here to avoid static initialization.
962 FormatThreadTestData kPercentFormatTestData[] =
963 {
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%" )),
971 };
972 int32_t kPercentFormatTestDataLength =
973 (int32_t)(sizeof(kPercentFormatTestData) / sizeof(kPercentFormatTestData[0]));
974 int32_t iteration;
975
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;
981 }
982
983 percentFormatter = NumberFormat::createPercentInstance(Locale::getFrench(),status);
984 if(U_FAILURE(status)) {
985 error("Error on NumberFormat::createPercentInstance()");
986 goto cleanupAndReturn;
987 }
988
989 for(iteration = 0;!getError() && iteration<kFormatThreadIterations;iteration++)
990 {
991
992 int32_t whichLine = (iteration + fOffset)%kNumberFormatTestDataLength;
993
994 UnicodeString output;
995
996 formatter->format(kNumberFormatTestData[whichLine].number, output);
997
998 if(0 != output.compare(kNumberFormatTestData[whichLine].string)) {
999 error("format().. expected " + kNumberFormatTestData[whichLine].string
1000 + " got " + output);
1001 goto cleanupAndReturn;
1002 }
1003
1004 // Now check percent.
1005 output.remove();
1006 whichLine = (iteration + fOffset)%kPercentFormatTestDataLength;
1007
1008 percentFormatter->format(kPercentFormatTestData[whichLine].number, output);
1009 if(0 != output.compare(kPercentFormatTestData[whichLine].string))
1010 {
1011 error("percent format().. \n" +
1012 showDifference(kPercentFormatTestData[whichLine].string,output));
1013 goto cleanupAndReturn;
1014 }
1015
1016 // Test message error
1017 const int kNumberOfMessageTests = 3;
1018 UErrorCode statusToCheck;
1019 UnicodeString patternToCheck;
1020 Locale messageLocale;
1021 Locale countryToCheck;
1022 double currencyToCheck;
1023
1024 UnicodeString expected;
1025
1026 // load the cases.
1027 switch((iteration+fOffset) % kNumberOfMessageTests)
1028 {
1029 default:
1030 case 0:
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.";
1040 break;
1041 case 1:
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.";
1048 break;
1049 case 2:
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.");
1061 break;
1062 }
1063
1064 UnicodeString result;
1065 UErrorCode status = U_ZERO_ERROR;
1066 formatErrorMessage(status,patternToCheck,messageLocale,statusToCheck,
1067 countryToCheck,currencyToCheck,result);
1068 if(U_FAILURE(status))
1069 {
1070 UnicodeString tmp(u_errorName(status));
1071 error("Failure on message format, pattern=" + patternToCheck +
1072 ", error = " + tmp);
1073 goto cleanupAndReturn;
1074 }
1075
1076 if(result != expected)
1077 {
1078 error("PatternFormat: \n" + showDifference(expected,result));
1079 goto cleanupAndReturn;
1080 }
1081 } /* end of for loop */
1082
1083 cleanupAndReturn:
1084 delete formatter;
1085 delete percentFormatter;
1086
1087 // while (fNum == 4) {SimpleThread::sleep(10000);} // Force a failure by preventing thread from finishing
1088 fTraceInfo = 2;
1089 }
1090
1091 private:
1092 int32_t fOffset; // where we are testing from.
1093 };
1094
1095 // ** The actual test function.
1096
1097 void MultithreadTest::TestThreadedIntl()
1098 {
1099 int i;
1100 UnicodeString theErr;
1101 UBool haveDisplayedInfo[kFormatThreadThreads];
1102 static const int32_t PATIENCE_SECONDS = 45;
1103
1104 //
1105 // Create and start the test threads
1106 //
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++) {
1111 tests[j].fNum = 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;
1117 }
1118 haveDisplayedInfo[j] = FALSE;
1119 }
1120
1121
1122 // Spin, waiting for the test threads to finish.
1123 UBool stillRunning;
1124 UDate startTime, endTime;
1125 startTime = Calendar::getNow();
1126 do {
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.");
1132 return;
1133 }
1134 /*
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
1137 CPU time.
1138 */
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();
1148 }
1149 haveDisplayedInfo[i] = TRUE;
1150 }
1151 }
1152 } while (stillRunning);
1153
1154 //
1155 // All threads have finished.
1156 //
1157 cleanupAndReturn:
1158 delete [] tests;
1159 }
1160 #endif /* #if !UCONFIG_NO_FORMATTING */
1161
1162
1163
1164
1165
1166 //-------------------------------------------------------------------------------------------
1167 //
1168 // Collation threading test
1169 //
1170 //-------------------------------------------------------------------------------------------
1171 #if !UCONFIG_NO_COLLATION
1172
1173 #define kCollatorThreadThreads 10 // # of threads to spawn
1174 #define kCollatorThreadPatience kCollatorThreadThreads*30
1175
1176 struct Line {
1177 UChar buff[25];
1178 int32_t buflen;
1179 } ;
1180
1181 class CollatorThreadTest : public ThreadWithStatus
1182 {
1183 private:
1184 const UCollator *coll;
1185 const Line *lines;
1186 int32_t noLines;
1187 public:
1188 CollatorThreadTest() : ThreadWithStatus(),
1189 coll(NULL),
1190 lines(NULL),
1191 noLines(0)
1192 {
1193 };
1194 void setCollator(UCollator *c, Line *l, int32_t nl)
1195 {
1196 coll = c;
1197 lines = l;
1198 noLines = nl;
1199 }
1200 virtual void run() {
1201 //sleep(10000);
1202 int32_t line = 0;
1203
1204 uint8_t sk1[1024], sk2[1024];
1205 uint8_t *oldSk = NULL, *newSk = sk1;
1206 int32_t resLen = 0, oldLen = 0;
1207 int32_t i = 0;
1208
1209 for(i = 0; i < noLines; i++) {
1210 resLen = ucol_getSortKey(coll, lines[i].buff, lines[i].buflen, newSk, 1024);
1211
1212 int32_t res = 0, cmpres = 0, cmpres2 = 0;
1213
1214 if(oldSk != NULL) {
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);
1218 //cmpres = res;
1219 //cmpres2 = -cmpres;
1220
1221 if(cmpres != -cmpres2) {
1222 error("Compare result not symmetrical on line "+ line);
1223 break;
1224 }
1225
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));
1228 break;
1229 }
1230
1231 if(res > 0) {
1232 error(UnicodeString("Line %i is not greater or equal than previous line ")+ UnicodeString(i));
1233 break;
1234 } else if(res == 0) { /* equal */
1235 res = u_strcmpCodePointOrder(lines[i-1].buff, lines[i].buff);
1236 if (res == 0) {
1237 error(UnicodeString("Probable error in test file on line %i (comparing identical strings)")+ UnicodeString(i));
1238 break;
1239 } else if (res > 0) {
1240 error(UnicodeString("Sortkeys are identical, but code point comapare gives >0 on line ")+ UnicodeString(i));
1241 break;
1242 }
1243 }
1244 }
1245
1246 oldSk = newSk;
1247 oldLen = resLen;
1248
1249 newSk = (newSk == sk1)?sk2:sk1;
1250 }
1251 }
1252
1253 };
1254
1255 void MultithreadTest::TestCollators()
1256 {
1257
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));
1264 return;
1265 }
1266 strcat(testDataPath, "CollationTest_");
1267
1268 const char* type = "NON_IGNORABLE";
1269
1270 const char *ext = ".txt";
1271 if(testFile) {
1272 fclose(testFile);
1273 }
1274 char buffer[1024];
1275 strcpy(buffer, testDataPath);
1276 strcat(buffer, type);
1277 size_t bufLen = strlen(buffer);
1278
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.
1284
1285 strcpy(buffer+bufLen, ext);
1286
1287 testFile = fopen(buffer, "rb");
1288
1289 if(testFile == 0) {
1290 strcpy(buffer+bufLen, "_SHORT");
1291 strcat(buffer, ext);
1292 testFile = fopen(buffer, "rb");
1293
1294 if(testFile == 0) {
1295 strcpy(buffer+bufLen, "_STUB");
1296 strcat(buffer, ext);
1297 testFile = fopen(buffer, "rb");
1298
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);
1302 return;
1303 } else {
1304 infoln(
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/");
1309 }
1310 }
1311 }
1312
1313 Line *lines = new Line[200000];
1314 memset(lines, 0, sizeof(Line)*200000);
1315 int32_t lineNum = 0;
1316
1317 UChar bufferU[1024];
1318 int32_t buflen = 0;
1319 uint32_t first = 0;
1320 uint32_t offset = 0;
1321
1322 while (fgets(buffer, 1024, testFile) != NULL) {
1323 offset = 0;
1324 if(*buffer == 0 || strlen(buffer) < 3 || buffer[0] == '#') {
1325 continue;
1326 }
1327 offset = u_parseString(buffer, bufferU, 1024, &first, &status);
1328 buflen = offset;
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);
1333 lineNum++;
1334 }
1335 fclose(testFile);
1336 if(U_FAILURE(status)) {
1337 errln("Couldn't read the test file!");
1338 return;
1339 }
1340
1341 UCollator *coll = ucol_open("root", &status);
1342 if(U_FAILURE(status)) {
1343 errln("Couldn't open UCA collator");
1344 return;
1345 }
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);
1351
1352 int32_t noSpawned = 0;
1353 int32_t spawnResult = 0;
1354 CollatorThreadTest *tests;
1355 tests = new CollatorThreadTest[kCollatorThreadThreads];
1356
1357 logln(UnicodeString("Spawning: ") + kCollatorThreadThreads + " threads * " + kFormatThreadIterations + " iterations each.");
1358 int32_t j = 0;
1359 for(j = 0; j < kCollatorThreadThreads; j++) {
1360 //logln("Setting collator %i", j);
1361 tests[j].setCollator(coll, lines, lineNum);
1362 }
1363 for(j = 0; j < kCollatorThreadThreads; j++) {
1364 log("%i ", j);
1365 spawnResult = tests[j].start();
1366 if(spawnResult != 0) {
1367 infoln("THREAD INFO: Couldn't spawn more than %i threads", noSpawned);
1368 break;
1369 }
1370 noSpawned++;
1371 }
1372 logln("Spawned all");
1373 if (noSpawned == 0) {
1374 errln("No threads could be spawned.");
1375 return;
1376 }
1377
1378 for(int32_t patience = kCollatorThreadPatience;patience > 0; patience --)
1379 {
1380 logln("Waiting...");
1381
1382 int32_t i;
1383 int32_t terrs = 0;
1384 int32_t completed =0;
1385
1386 for(i=0;i<kCollatorThreadThreads;i++)
1387 {
1388 if (tests[i].isRunning() == FALSE)
1389 {
1390 completed++;
1391
1392 //logln(UnicodeString("Test #") + i + " is complete.. ");
1393
1394 UnicodeString theErr;
1395 if(tests[i].getError(theErr))
1396 {
1397 terrs++;
1398 errln(UnicodeString("#") + i + ": " + theErr);
1399 }
1400 // print out the error, too, if any.
1401 }
1402 }
1403 logln("Completed %i tests", completed);
1404
1405 if(completed == noSpawned)
1406 {
1407 logln("Done! All %i tests are finished", noSpawned);
1408
1409 if(terrs)
1410 {
1411 errln("There were errors.");
1412 SimpleThread::errorFunc();
1413 }
1414 ucol_close(coll);
1415 delete[] tests;
1416 //for(i = 0; i < lineNum; i++) {
1417 //delete[] lines[i].buff;
1418 //}
1419 delete[] lines;
1420
1421 return;
1422 }
1423
1424 SimpleThread::sleep(900);
1425 }
1426 errln("patience exceeded. ");
1427 SimpleThread::errorFunc();
1428 ucol_close(coll);
1429 }
1430
1431 #endif /* #if !UCONFIG_NO_COLLATION */
1432
1433
1434
1435
1436 //-------------------------------------------------------------------------------------------
1437 //
1438 // StringThreadTest2
1439 //
1440 //-------------------------------------------------------------------------------------------
1441
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
1445
1446
1447 class StringThreadTest2 : public ThreadWithStatus
1448 {
1449 public:
1450 int fNum;
1451 int fTraceInfo;
1452 const UnicodeString *fSharedString;
1453
1454 StringThreadTest2(const UnicodeString *sharedString, int num) // constructor is NOT multithread safe.
1455 : ThreadWithStatus(),
1456 fNum(num),
1457 fTraceInfo(0),
1458 fSharedString(sharedString)
1459 {
1460 };
1461
1462
1463 virtual void run()
1464 {
1465 fTraceInfo = 1;
1466 int loopCount = 0;
1467
1468 for (loopCount = 0; loopCount < kStringThreadIterations; loopCount++) {
1469 if (*fSharedString != "This is the original test string.") {
1470 error("Original string is corrupt.");
1471 break;
1472 }
1473 UnicodeString s1 = *fSharedString;
1474 s1 += "cat this";
1475 UnicodeString s2(s1);
1476 UnicodeString s3 = *fSharedString;
1477 s2 = s3;
1478 s3.truncate(12);
1479 s2.truncate(0);
1480 }
1481
1482 // while (fNum == 4) {SimpleThread::sleep(10000);} // Force a failure by preventing thread from finishing
1483 fTraceInfo = 2;
1484 }
1485
1486 };
1487
1488 // ** The actual test function.
1489
1490 void MultithreadTest::TestString()
1491 {
1492 int patience;
1493 int terrs = 0;
1494 int j;
1495
1496 UnicodeString *testString = new UnicodeString("This is the original test string.");
1497
1498 StringThreadTest2 *tests[kStringThreadThreads];
1499 for(j = 0; j < kStringThreadThreads; j++) {
1500 tests[j] = new StringThreadTest2(testString, j);
1501 }
1502
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;
1510 }
1511 }
1512
1513 for(patience = kStringThreadPatience;patience > 0; patience --)
1514 {
1515 logln("Waiting...");
1516
1517 int32_t i;
1518 terrs = 0;
1519 int32_t completed =0;
1520
1521 for(i=0;i<kStringThreadThreads;i++) {
1522 if (tests[i]->isRunning() == FALSE)
1523 {
1524 completed++;
1525
1526 logln(UnicodeString("Test #") + i + " is complete.. ");
1527
1528 UnicodeString theErr;
1529 if(tests[i]->getError(theErr))
1530 {
1531 terrs++;
1532 errln(UnicodeString("#") + i + ": " + theErr);
1533 }
1534 // print out the error, too, if any.
1535 }
1536 }
1537
1538 if(completed == kStringThreadThreads)
1539 {
1540 logln("Done!");
1541 if(terrs) {
1542 errln("There were errors.");
1543 }
1544 break;
1545 }
1546
1547 SimpleThread::sleep(900);
1548 }
1549
1550 if (patience <= 0) {
1551 errln("patience exceeded. ");
1552 // while (TRUE) {SimpleThread::sleep(10000);} // TODO: for debugging. Sleep forever on failure.
1553 terrs++;
1554 }
1555
1556 if (terrs > 0) {
1557 SimpleThread::errorFunc();
1558 }
1559
1560 cleanupAndReturn:
1561 if (terrs == 0) {
1562 /*
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.
1567 */
1568 for(j = 0; j < kStringThreadThreads; j++) {
1569 delete tests[j];
1570 }
1571 delete testString;
1572 }
1573 }
1574
1575
1576
1577
1578
1579 #endif // ICU_USE_THREADS
1580