]> git.saurik.com Git - apple/icu.git/blob - icuSources/test/intltest/tsmthred.cpp
ICU-400.38.tar.gz
[apple/icu.git] / icuSources / test / intltest / tsmthred.cpp
1 /********************************************************************
2 * COPYRIGHT:
3 * Copyright (c) 1999-2008, 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 /* Needed by z/OS to get usleep */
14 #if !defined(_XOPEN_SOURCE_EXTENDED)
15 #define _XOPEN_SOURCE_EXTENDED 1
16 #endif
17
18 #include "unicode/utypes.h"
19 #include "unicode/ustring.h"
20 #include "umutex.h"
21 #include "cmemory.h"
22 #include "cstring.h"
23 #include "uparse.h"
24 #include "unicode/resbund.h"
25 #include "unicode/udata.h"
26 #include "unicode/uloc.h"
27 #include "unicode/locid.h"
28 #include "putilimp.h"
29 #if !defined(U_WINDOWS) && !defined(XP_MAC) && !defined(U_RHAPSODY)
30 #define POSIX 1
31 #endif
32
33 #if defined(POSIX) || defined(U_SOLARIS) || defined(U_AIX) || defined(U_HPUX)
34
35 #define HAVE_IMP
36
37 #if (ICU_USE_THREADS == 1)
38 #include <pthread.h>
39 #endif
40
41 #if defined(__hpux) && defined(HPUX_CMA)
42 # if defined(read) // read being defined as cma_read causes trouble with iostream::read
43 # undef read
44 # endif
45 #endif
46
47 /* Define __EXTENSIONS__ for Solaris and old friends in strict mode. */
48 #ifndef __EXTENSIONS__
49 #define __EXTENSIONS__
50 #endif
51
52 #include <signal.h>
53
54 /* Define _XPG4_2 for Solaris and friends. */
55 #ifndef _XPG4_2
56 #define _XPG4_2
57 #endif
58
59 /* Define __USE_XOPEN_EXTENDED for Linux and glibc. */
60 #ifndef __USE_XOPEN_EXTENDED
61 #define __USE_XOPEN_EXTENDED
62 #endif
63
64 /* Define _INCLUDE_XOPEN_SOURCE_EXTENDED for HP/UX (11?). */
65 #ifndef _INCLUDE_XOPEN_SOURCE_EXTENDED
66 #define _INCLUDE_XOPEN_SOURCE_EXTENDED
67 #endif
68
69 #include <unistd.h>
70
71 #endif
72 /* HPUX */
73 #ifdef sleep
74 #undef sleep
75 #endif
76
77
78
79 #include "tsmthred.h"
80
81 #define TSMTHREAD_FAIL(msg) errln("%s at file %s, line %d", msg, __FILE__, __LINE__)
82 #define TSMTHREAD_ASSERT(expr) {if (!(expr)) {TSMTHREAD_FAIL("Fail");}}
83
84 MultithreadTest::MultithreadTest()
85 {
86 }
87
88 MultithreadTest::~MultithreadTest()
89 {
90 }
91
92
93
94 #if (ICU_USE_THREADS==0)
95 void MultithreadTest::runIndexedTest( int32_t index, UBool exec,
96 const char* &name, char* /*par*/ ) {
97 if (exec) logln("TestSuite MultithreadTest: ");
98
99 if(index == 0)
100 name = "NO_THREADED_TESTS";
101 else
102 name = "";
103
104 if(exec) { logln("MultithreadTest - test DISABLED. ICU_USE_THREADS set to 0, check your configuration if this is a problem..");
105 }
106 }
107 #else
108
109
110
111 // Note: A LOT OF THE FUNCTIONS IN THIS FILE SHOULD LIVE ELSEWHERE!!!!!
112 // Note: A LOT OF THE FUNCTIONS IN THIS FILE SHOULD LIVE ELSEWHERE!!!!!
113 // -srl
114
115 #include <stdio.h>
116 #include <string.h>
117 #include <ctype.h> // tolower, toupper
118
119 #include "unicode/putil.h"
120
121 /* for mthreadtest*/
122 #include "unicode/numfmt.h"
123 #include "unicode/choicfmt.h"
124 #include "unicode/msgfmt.h"
125 #include "unicode/locid.h"
126 #include "unicode/ucol.h"
127 #include "unicode/calendar.h"
128 #include "ucaconf.h"
129
130 //-----------------------------------------------------------------------------------
131 //
132 // class SimpleThread Of course we need a thread class first..
133 // This wrapper has a ported implementation.
134 //
135 //-----------------------------------------------------------------------------------
136 class SimpleThread
137 {
138 public:
139 SimpleThread();
140 virtual ~SimpleThread();
141 int32_t start(void); // start the thread
142 UBool isRunning(); // return true if a started thread has exited.
143
144 virtual void run(void) = 0; // Override this to provide the code to run
145 // in the thread.
146 void *fImplementation;
147
148 public:
149 static void sleep(int32_t millis); // probably shouldn't go here but oh well.
150 static void errorFunc(); // Empty function, provides a single convenient place
151 // to break on errors.
152 };
153
154 void SimpleThread::errorFunc() {
155 // *(char *)0 = 3; // Force entry into a debugger via a crash;
156 }
157
158
159
160
161 #ifdef U_WINDOWS
162 #define HAVE_IMP
163
164 # define VC_EXTRALEAN
165 # define WIN32_LEAN_AND_MEAN
166 # define NOUSER
167 # define NOSERVICE
168 # define NOIME
169 # define NOMCX
170 #include <windows.h>
171 #include <process.h>
172
173
174
175 //-----------------------------------------------------------------------------------
176 //
177 // class SimpleThread Windows Implementation
178 //
179 //-----------------------------------------------------------------------------------
180 struct Win32ThreadImplementation
181 {
182 HANDLE fHandle;
183 unsigned int fThreadID;
184 };
185
186
187 extern "C" unsigned int __stdcall SimpleThreadProc(void *arg)
188 {
189 ((SimpleThread*)arg)->run();
190 return 0;
191 }
192
193 SimpleThread::SimpleThread()
194 :fImplementation(0)
195 {
196 Win32ThreadImplementation *imp = new Win32ThreadImplementation;
197 imp->fHandle = 0;
198 fImplementation = imp;
199 }
200
201 SimpleThread::~SimpleThread()
202 {
203 // Destructor. Because we start the thread running with _beginthreadex(),
204 // we own the Windows HANDLE for the thread and must
205 // close it here.
206 Win32ThreadImplementation *imp = (Win32ThreadImplementation*)fImplementation;
207 if (imp != 0) {
208 if (imp->fHandle != 0) {
209 CloseHandle(imp->fHandle);
210 imp->fHandle = 0;
211 }
212 }
213 delete (Win32ThreadImplementation*)fImplementation;
214 }
215
216 int32_t SimpleThread::start()
217 {
218 Win32ThreadImplementation *imp = (Win32ThreadImplementation*)fImplementation;
219 if(imp->fHandle != NULL) {
220 // The thread appears to have already been started.
221 // This is probably an error on the part of our caller.
222 return -1;
223 }
224
225 imp->fHandle = (HANDLE) _beginthreadex(
226 NULL, // Security
227 0x20000, // Stack Size
228 SimpleThreadProc, // Function to Run
229 (void *)this, // Arg List
230 0, // initflag. Start running, not suspended
231 &imp->fThreadID // thraddr
232 );
233
234 if (imp->fHandle == 0) {
235 // An error occured
236 int err = errno;
237 if (err == 0) {
238 err = -1;
239 }
240 return err;
241 }
242 return 0;
243 }
244
245
246 UBool SimpleThread::isRunning() {
247 //
248 // Test whether the thread associated with the SimpleThread object is
249 // still actually running.
250 //
251 // NOTE: on Win64 on Itanium processors, a crashes
252 // occur if the main thread of a process exits concurrently with some
253 // other thread(s) exiting. To avoid the possibility, we wait until the
254 // OS indicates that all threads have terminated, rather than waiting
255 // only until the end of the user's Run function has been reached.
256 //
257 // I don't know whether the crashes represent a Windows bug, or whether
258 // main() programs are supposed to have to wait for their threads.
259 //
260 Win32ThreadImplementation *imp = (Win32ThreadImplementation*)fImplementation;
261
262 bool success;
263 DWORD threadExitCode;
264
265 if (imp->fHandle == 0) {
266 // No handle, thread must not be running.
267 return FALSE;
268 }
269 success = GetExitCodeThread(imp->fHandle, &threadExitCode) != 0;
270 if (! success) {
271 // Can't get status, thread must not be running.
272 return FALSE;
273 }
274 return (threadExitCode == STILL_ACTIVE);
275 }
276
277
278 void SimpleThread::sleep(int32_t millis)
279 {
280 ::Sleep(millis);
281 }
282
283 //-----------------------------------------------------------------------------------
284 //
285 // class SimpleThread NULL Implementation
286 //
287 //-----------------------------------------------------------------------------------
288 #elif defined XP_MAC
289
290 // since the Mac has no preemptive threading (at least on MacOS 8), only
291 // cooperative threading, threads are a no-op. We have no yield() calls
292 // anywhere in the ICU, so we are guaranteed to be thread-safe.
293
294 #define HAVE_IMP
295
296 SimpleThread::SimpleThread()
297 {}
298
299 SimpleThread::~SimpleThread()
300 {}
301
302 int32_t
303 SimpleThread::start()
304 { return 0; }
305
306 void
307 SimpleThread::run()
308 {}
309
310 void
311 SimpleThread::sleep(int32_t millis)
312 {}
313
314 UBool
315 SimpleThread::isRunning() {
316 return FALSE;
317 }
318
319 #endif
320
321
322 //-----------------------------------------------------------------------------------
323 //
324 // class SimpleThread POSIX implementation
325 //
326 // A note on the POSIX vs the Windows implementations of this class..
327 // On Windows, the main thread must verify that other threads have finished
328 // before exiting, or crashes occasionally occur. (Seen on Itanium Win64 only)
329 // The function SimpleThread::isRunning() is used for this purpose.
330 //
331 // On POSIX, there is NO reliable non-blocking mechanism to determine
332 // whether a thread has exited. pthread_kill(thread, 0) almost works,
333 // but the system can recycle thread ids immediately, so seeing that a
334 // thread exists with this call could mean that the original thread has
335 // finished and a new one started with the same ID. Useless.
336 //
337 // So we need to do the check with user code, by setting a flag just before
338 // the thread function returns. A technique that is guaranteed to fail
339 // on Windows, because it indicates that the thread is done before all
340 // system level cleanup has happened.
341 //
342 //-----------------------------------------------------------------------------------
343 #if defined(POSIX)||defined(U_SOLARIS)||defined(U_AIX)||defined(U_HPUX)
344 #define HAVE_IMP
345
346 struct PosixThreadImplementation
347 {
348 pthread_t fThread;
349 UBool fRunning;
350 UBool fRan; /* True if the thread was successfully started */
351 };
352
353 extern "C" void* SimpleThreadProc(void *arg)
354 {
355 // This is the code that is run in the new separate thread.
356 SimpleThread *This = (SimpleThread *)arg;
357 This->run(); // Run the user code.
358
359 // The user function has returned. Set the flag indicating that this thread
360 // is done. Need a mutex for memory barrier purposes only, so that other thread
361 // will reliably see that the flag has changed.
362 PosixThreadImplementation *imp = (PosixThreadImplementation*)This->fImplementation;
363 umtx_lock(NULL);
364 imp->fRunning = FALSE;
365 umtx_unlock(NULL);
366 return 0;
367 }
368
369 SimpleThread::SimpleThread()
370 {
371 PosixThreadImplementation *imp = new PosixThreadImplementation;
372 imp->fRunning = FALSE;
373 imp->fRan = FALSE;
374 fImplementation = imp;
375 }
376
377 SimpleThread::~SimpleThread()
378 {
379 PosixThreadImplementation *imp = (PosixThreadImplementation*)fImplementation;
380 if (imp->fRan) {
381 pthread_join(imp->fThread, NULL);
382 }
383 delete imp;
384 fImplementation = (void *)0xdeadbeef;
385 }
386
387 int32_t SimpleThread::start()
388 {
389 int32_t rc;
390 static pthread_attr_t attr;
391 static UBool attrIsInitialized = FALSE;
392
393 PosixThreadImplementation *imp = (PosixThreadImplementation*)fImplementation;
394 imp->fRunning = TRUE;
395 imp->fRan = TRUE;
396
397 #ifdef HPUX_CMA
398 if (attrIsInitialized == FALSE) {
399 rc = pthread_attr_create(&attr);
400 attrIsInitialized = TRUE;
401 }
402 rc = pthread_create(&(imp->fThread),attr,&SimpleThreadProc,(void*)this);
403 #else
404 if (attrIsInitialized == FALSE) {
405 rc = pthread_attr_init(&attr);
406 #if defined(OS390)
407 {
408 int detachstate = 0; /* jdc30: detach state of zero causes
409 threads created with this attr to be in
410 an undetached state. An undetached
411 thread will keep its resources after
412 termination. */
413 pthread_attr_setdetachstate(&attr, &detachstate);
414 }
415 #else
416 // pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
417 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
418 #endif
419 attrIsInitialized = TRUE;
420 }
421 rc = pthread_create(&(imp->fThread),&attr,&SimpleThreadProc,(void*)this);
422 #endif
423
424 if (rc != 0) {
425 // some kind of error occured, the thread did not start.
426 imp->fRan = FALSE;
427 imp->fRunning = FALSE;
428 }
429
430 return rc;
431 }
432
433
434 UBool
435 SimpleThread::isRunning() {
436 // Note: Mutex functions are used here not for synchronization,
437 // but to force memory barriors to exist, to ensure that one thread
438 // can see changes made by another when running on processors
439 // with memory models having weak coherency.
440 PosixThreadImplementation *imp = (PosixThreadImplementation*)fImplementation;
441 umtx_lock(NULL);
442 UBool retVal = imp->fRunning;
443 umtx_unlock(NULL);
444 return retVal;
445 }
446
447
448 void SimpleThread::sleep(int32_t millis)
449 {
450 #ifdef U_SOLARIS
451 sigignore(SIGALRM);
452 #endif
453
454 #ifdef HPUX_CMA
455 cma_sleep(millis/100);
456 #elif defined(U_HPUX) || defined(OS390)
457 millis *= 1000;
458 while(millis >= 1000000) {
459 usleep(999999);
460 millis -= 1000000;
461 }
462 if(millis > 0) {
463 usleep(millis);
464 }
465 #else
466 usleep(millis * 1000);
467 #endif
468 }
469
470 #endif
471 // end POSIX
472
473
474 #ifndef HAVE_IMP
475 #error No implementation for threads! Cannot test.
476 0 = 216; //die
477 #endif
478
479
480 // *************** end fluff ******************
481
482 /* now begins the real test. */
483 void MultithreadTest::runIndexedTest( int32_t index, UBool exec,
484 const char* &name, char* /*par*/ ) {
485 if (exec)
486 logln("TestSuite MultithreadTest: ");
487 switch (index) {
488 case 0:
489 name = "TestThreads";
490 if (exec)
491 TestThreads();
492 break;
493
494 case 1:
495 name = "TestMutex";
496 if (exec)
497 TestMutex();
498 break;
499
500 case 2:
501 name = "TestThreadedIntl";
502 #if !UCONFIG_NO_FORMATTING
503 if (exec) {
504 TestThreadedIntl();
505 }
506 #endif
507 break;
508
509 case 3:
510 name = "TestCollators";
511 #if !UCONFIG_NO_COLLATION
512 if (exec) {
513 TestCollators();
514 }
515 #endif /* #if !UCONFIG_NO_COLLATION */
516 break;
517
518 case 4:
519 name = "TestString";
520 if (exec) {
521 TestString();
522 }
523 break;
524
525 default:
526 name = "";
527 break; //needed to end loop
528 }
529 }
530
531
532 //-----------------------------------------------------------------------------------
533 //
534 // TestThreads -- see if threads really work at all.
535 //
536 // Set up N threads pointing at N chars. When they are started, they will
537 // each sleep 1 second and then set their chars. At the end we make sure they
538 // are all set.
539 //
540 //-----------------------------------------------------------------------------------
541 #define THREADTEST_NRTHREADS 8
542
543 class TestThreadsThread : public SimpleThread
544 {
545 public:
546 TestThreadsThread(char* whatToChange) { fWhatToChange = whatToChange; }
547 virtual void run() { SimpleThread::sleep(1000);
548 Mutex m;
549 *fWhatToChange = '*';
550 }
551 private:
552 char *fWhatToChange;
553 };
554
555 void MultithreadTest::TestThreads()
556 {
557 char threadTestChars[THREADTEST_NRTHREADS + 1];
558 SimpleThread *threads[THREADTEST_NRTHREADS];
559 int32_t numThreadsStarted = 0;
560
561 int32_t i;
562 for(i=0;i<THREADTEST_NRTHREADS;i++)
563 {
564 threadTestChars[i] = ' ';
565 threads[i] = new TestThreadsThread(&threadTestChars[i]);
566 }
567 threadTestChars[THREADTEST_NRTHREADS] = '\0';
568
569 logln("->" + UnicodeString(threadTestChars) + "<- Firing off threads.. ");
570 for(i=0;i<THREADTEST_NRTHREADS;i++)
571 {
572 if (threads[i]->start() != 0) {
573 errln("Error starting thread %d", i);
574 }
575 else {
576 numThreadsStarted++;
577 }
578 SimpleThread::sleep(100);
579 logln(" Subthread started.");
580 }
581
582 logln("Waiting for threads to be set..");
583 if (numThreadsStarted == 0) {
584 errln("No threads could be started for testing!");
585 return;
586 }
587
588 int32_t patience = 40; // seconds to wait
589
590 while(patience--)
591 {
592 int32_t count = 0;
593 umtx_lock(NULL);
594 for(i=0;i<THREADTEST_NRTHREADS;i++)
595 {
596 if(threadTestChars[i] == '*')
597 {
598 count++;
599 }
600 }
601 umtx_unlock(NULL);
602
603 if(count == THREADTEST_NRTHREADS)
604 {
605 logln("->" + UnicodeString(threadTestChars) + "<- Got all threads! cya");
606 for(i=0;i<THREADTEST_NRTHREADS;i++)
607 {
608 delete threads[i];
609 }
610 return;
611 }
612
613 logln("->" + UnicodeString(threadTestChars) + "<- Waiting..");
614 SimpleThread::sleep(500);
615 }
616
617 errln("->" + UnicodeString(threadTestChars) + "<- PATIENCE EXCEEDED!! Still missing some.");
618 for(i=0;i<THREADTEST_NRTHREADS;i++)
619 {
620 delete threads[i];
621 }
622 }
623
624
625 //-----------------------------------------------------------------------
626 //
627 // TestMutex - a simple (non-stress) test to verify that ICU mutexes
628 // are actually mutexing. Does not test the use of
629 // mutexes within ICU services, but rather that the
630 // platform's mutex support is at least superficially there.
631 //
632 //----------------------------------------------------------------------
633 static UMTX gTestMutexA = NULL;
634 static UMTX gTestMutexB = NULL;
635
636 static int gThreadsStarted = 0;
637 static int gThreadsInMiddle = 0;
638 static int gThreadsDone = 0;
639
640 static const int TESTMUTEX_THREAD_COUNT = 4;
641
642 static int safeIncr(int &var, int amt) {
643 // Thread safe (using global mutex) increment of a variable.
644 // Return the updated value.
645 // Can also be used as a safe load of a variable by incrementing it by 0.
646 Mutex m;
647 var += amt;
648 return var;
649 }
650
651 class TestMutexThread : public SimpleThread
652 {
653 public:
654 virtual void run()
655 {
656 // This is the code that each of the spawned threads runs.
657 // All of the spawned threads bunch up together at each of the two mutexes
658 // because the main holds the mutexes until they do.
659 //
660 safeIncr(gThreadsStarted, 1);
661 umtx_lock(&gTestMutexA);
662 umtx_unlock(&gTestMutexA);
663 safeIncr(gThreadsInMiddle, 1);
664 umtx_lock(&gTestMutexB);
665 umtx_unlock(&gTestMutexB);
666 safeIncr(gThreadsDone, 1);
667 }
668 };
669
670 void MultithreadTest::TestMutex()
671 {
672 // Start up the test threads. They should all pile up waiting on
673 // gTestMutexA, which we (the main thread) hold until the test threads
674 // all get there.
675 gThreadsStarted = 0;
676 gThreadsInMiddle = 0;
677 gThreadsDone = 0;
678 umtx_lock(&gTestMutexA);
679 TestMutexThread *threads[TESTMUTEX_THREAD_COUNT];
680 int i;
681 int32_t numThreadsStarted = 0;
682 for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) {
683 threads[i] = new TestMutexThread;
684 if (threads[i]->start() != 0) {
685 errln("Error starting thread %d", i);
686 }
687 else {
688 numThreadsStarted++;
689 }
690 }
691 if (numThreadsStarted == 0) {
692 errln("No threads could be started for testing!");
693 return;
694 }
695
696 int patience = 0;
697 while (safeIncr(gThreadsStarted, 0) != TESTMUTEX_THREAD_COUNT) {
698 if (patience++ > 24) {
699 TSMTHREAD_FAIL("Patience Exceeded");
700 return;
701 }
702 SimpleThread::sleep(500);
703 }
704 // None of the test threads should have advanced past the first mutex.
705 TSMTHREAD_ASSERT(gThreadsInMiddle==0);
706 TSMTHREAD_ASSERT(gThreadsDone==0);
707
708 // All of the test threads have made it to the first mutex.
709 // We (the main thread) now let them advance to the second mutex,
710 // where they should all pile up again.
711 umtx_lock(&gTestMutexB);
712 umtx_unlock(&gTestMutexA);
713
714 patience = 0;
715 while (safeIncr(gThreadsInMiddle, 0) != TESTMUTEX_THREAD_COUNT) {
716 if (patience++ > 24) {
717 TSMTHREAD_FAIL("Patience Exceeded");
718 return;
719 }
720 SimpleThread::sleep(500);
721 }
722 TSMTHREAD_ASSERT(gThreadsDone==0);
723
724 // All test threads made it to the second mutex.
725 // Now let them proceed from there. They will all terminate.
726 umtx_unlock(&gTestMutexB);
727 patience = 0;
728 while (safeIncr(gThreadsDone, 0) != TESTMUTEX_THREAD_COUNT) {
729 if (patience++ > 24) {
730 TSMTHREAD_FAIL("Patience Exceeded");
731 return;
732 }
733 SimpleThread::sleep(500);
734 }
735
736 // All threads made it by both mutexes.
737 // Destroy the test mutexes.
738 umtx_destroy(&gTestMutexA);
739 umtx_destroy(&gTestMutexB);
740 gTestMutexA=NULL;
741 gTestMutexB=NULL;
742
743 for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) {
744 delete threads[i];
745 }
746
747 }
748
749
750 //-------------------------------------------------------------------------------------------
751 //
752 // class ThreadWithStatus - a thread that we can check the status and error condition of
753 //
754 //-------------------------------------------------------------------------------------------
755 class ThreadWithStatus : public SimpleThread
756 {
757 public:
758 UBool getError() { return (fErrors > 0); }
759 UBool getError(UnicodeString& fillinError) { fillinError = fErrorString; return (fErrors > 0); }
760 virtual ~ThreadWithStatus(){}
761 protected:
762 ThreadWithStatus() : fErrors(0) {}
763 void error(const UnicodeString &error) {
764 fErrors++; fErrorString = error;
765 SimpleThread::errorFunc();
766 }
767 void error() { error("An error occured."); }
768 private:
769 int32_t fErrors;
770 UnicodeString fErrorString;
771 };
772
773
774
775 //-------------------------------------------------------------------------------------------
776 //
777 // TestMultithreadedIntl. Test ICU Formatting n a multi-threaded environment
778 //
779 //-------------------------------------------------------------------------------------------
780
781
782 // * Show exactly where the string's differences lie.
783 UnicodeString showDifference(const UnicodeString& expected, const UnicodeString& result)
784 {
785 UnicodeString res;
786 res = expected + "<Expected\n";
787 if(expected.length() != result.length())
788 res += " [ Different lengths ] \n";
789 else
790 {
791 for(int32_t i=0;i<expected.length();i++)
792 {
793 if(expected[i] == result[i])
794 {
795 res += " ";
796 }
797 else
798 {
799 res += "|";
800 }
801 }
802 res += "<Differences";
803 res += "\n";
804 }
805 res += result + "<Result\n";
806
807 return res;
808 }
809
810
811
812
813 //-------------------------------------------------------------------------------------------
814 //
815 // FormatThreadTest - a thread that tests performing a number of numberformats.
816 //
817 //-------------------------------------------------------------------------------------------
818
819 const int kFormatThreadIterations = 20; // # of iterations per thread
820 const int kFormatThreadThreads = 10; // # of threads to spawn
821 const int kFormatThreadPatience = 60; // time in seconds to wait for all threads
822
823 #if !UCONFIG_NO_FORMATTING
824
825
826
827 struct FormatThreadTestData
828 {
829 double number;
830 UnicodeString string;
831 FormatThreadTestData(double a, const UnicodeString& b) : number(a),string(b) {}
832 } ;
833
834
835 // "Someone from {2} is receiving a #{0} error - {1}. Their telephone call is costing {3 number,currency}."
836
837 void formatErrorMessage(UErrorCode &realStatus, const UnicodeString& pattern, const Locale& theLocale,
838 UErrorCode inStatus0, /* statusString 1 */ const Locale &inCountry2, double currency3, // these numbers are the message arguments.
839 UnicodeString &result)
840 {
841 if(U_FAILURE(realStatus))
842 return; // you messed up
843
844 UnicodeString errString1(u_errorName(inStatus0));
845
846 UnicodeString countryName2;
847 inCountry2.getDisplayCountry(theLocale,countryName2);
848
849 Formattable myArgs[] = {
850 Formattable((int32_t)inStatus0), // inStatus0 {0}
851 Formattable(errString1), // statusString1 {1}
852 Formattable(countryName2), // inCountry2 {2}
853 Formattable(currency3)// currency3 {3,number,currency}
854 };
855
856 MessageFormat *fmt = new MessageFormat("MessageFormat's API is broken!!!!!!!!!!!",realStatus);
857 fmt->setLocale(theLocale);
858 fmt->applyPattern(pattern, realStatus);
859
860 if (U_FAILURE(realStatus)) {
861 delete fmt;
862 return;
863 }
864
865 FieldPosition ignore = 0;
866 fmt->format(myArgs,4,result,ignore,realStatus);
867
868 delete fmt;
869 }
870
871
872 UBool U_CALLCONV isAcceptable(void *, const char *, const char *, const UDataInfo *) {
873 return TRUE;
874 }
875
876 //static UMTX debugMutex = NULL;
877 //static UMTX gDebugMutex;
878
879
880 class FormatThreadTest : public ThreadWithStatus
881 {
882 public:
883 int fNum;
884 int fTraceInfo;
885
886 FormatThreadTest() // constructor is NOT multithread safe.
887 : ThreadWithStatus(),
888 fNum(0),
889 fTraceInfo(0),
890 fOffset(0)
891 // the locale to use
892 {
893 static int32_t fgOffset = 0;
894 fgOffset += 3;
895 fOffset = fgOffset;
896 }
897
898
899 virtual void run()
900 {
901 fTraceInfo = 1;
902 NumberFormat *formatter = NULL;
903 NumberFormat *percentFormatter = NULL;
904 UErrorCode status = U_ZERO_ERROR;
905
906 #if 0
907 // debugging code,
908 for (int i=0; i<4000; i++) {
909 status = U_ZERO_ERROR;
910 UDataMemory *data1 = udata_openChoice(0, "res", "en_US", isAcceptable, 0, &status);
911 UDataMemory *data2 = udata_openChoice(0, "res", "fr", isAcceptable, 0, &status);
912 udata_close(data1);
913 udata_close(data2);
914 if (U_FAILURE(status)) {
915 error("udata_openChoice failed.\n");
916 break;
917 }
918 }
919 return;
920 #endif
921
922 #if 0
923 // debugging code,
924 int m;
925 for (m=0; m<4000; m++) {
926 status = U_ZERO_ERROR;
927 UResourceBundle *res = NULL;
928 const char *localeName = NULL;
929
930 Locale loc = Locale::getEnglish();
931
932 localeName = loc.getName();
933 // localeName = "en";
934
935 // ResourceBundle bund = ResourceBundle(0, loc, status);
936 //umtx_lock(&gDebugMutex);
937 res = ures_open(NULL, localeName, &status);
938 //umtx_unlock(&gDebugMutex);
939
940 //umtx_lock(&gDebugMutex);
941 ures_close(res);
942 //umtx_unlock(&gDebugMutex);
943
944 if (U_FAILURE(status)) {
945 error("Resource bundle construction failed.\n");
946 break;
947 }
948 }
949 return;
950 #endif
951
952 // Keep this data here to avoid static initialization.
953 FormatThreadTestData kNumberFormatTestData[] =
954 {
955 FormatThreadTestData((double)5.0, UnicodeString("5", "")),
956 FormatThreadTestData( 6.0, UnicodeString("6", "")),
957 FormatThreadTestData( 20.0, UnicodeString("20", "")),
958 FormatThreadTestData( 8.0, UnicodeString("8", "")),
959 FormatThreadTestData( 8.3, UnicodeString("8.3", "")),
960 FormatThreadTestData( 12345, UnicodeString("12,345", "")),
961 FormatThreadTestData( 81890.23, UnicodeString("81,890.23", "")),
962 };
963 int32_t kNumberFormatTestDataLength = (int32_t)(sizeof(kNumberFormatTestData) /
964 sizeof(kNumberFormatTestData[0]));
965
966 // Keep this data here to avoid static initialization.
967 FormatThreadTestData kPercentFormatTestData[] =
968 {
969 FormatThreadTestData((double)5.0, CharsToUnicodeString("500\\u00a0%")),
970 FormatThreadTestData( 1.0, CharsToUnicodeString("100\\u00a0%")),
971 FormatThreadTestData( 0.26, CharsToUnicodeString("26\\u00a0%")),
972 FormatThreadTestData(
973 16384.99, CharsToUnicodeString("1\\u00a0638\\u00a0499\\u00a0%")), // U+00a0 = NBSP
974 FormatThreadTestData(
975 81890.23, CharsToUnicodeString("8\\u00a0189\\u00a0023\\u00a0%")),
976 };
977 int32_t kPercentFormatTestDataLength =
978 (int32_t)(sizeof(kPercentFormatTestData) / sizeof(kPercentFormatTestData[0]));
979 int32_t iteration;
980
981 status = U_ZERO_ERROR;
982 formatter = NumberFormat::createInstance(Locale::getEnglish(),status);
983 if(U_FAILURE(status)) {
984 error("Error on NumberFormat::createInstance()");
985 goto cleanupAndReturn;
986 }
987
988 percentFormatter = NumberFormat::createPercentInstance(Locale::getFrench(),status);
989 if(U_FAILURE(status)) {
990 error("Error on NumberFormat::createPercentInstance()");
991 goto cleanupAndReturn;
992 }
993
994 for(iteration = 0;!getError() && iteration<kFormatThreadIterations;iteration++)
995 {
996
997 int32_t whichLine = (iteration + fOffset)%kNumberFormatTestDataLength;
998
999 UnicodeString output;
1000
1001 formatter->format(kNumberFormatTestData[whichLine].number, output);
1002
1003 if(0 != output.compare(kNumberFormatTestData[whichLine].string)) {
1004 error("format().. expected " + kNumberFormatTestData[whichLine].string
1005 + " got " + output);
1006 goto cleanupAndReturn;
1007 }
1008
1009 // Now check percent.
1010 output.remove();
1011 whichLine = (iteration + fOffset)%kPercentFormatTestDataLength;
1012
1013 percentFormatter->format(kPercentFormatTestData[whichLine].number, output);
1014 if(0 != output.compare(kPercentFormatTestData[whichLine].string))
1015 {
1016 error("percent format().. \n" +
1017 showDifference(kPercentFormatTestData[whichLine].string,output));
1018 goto cleanupAndReturn;
1019 }
1020
1021 // Test message error
1022 const int kNumberOfMessageTests = 3;
1023 UErrorCode statusToCheck;
1024 UnicodeString patternToCheck;
1025 Locale messageLocale;
1026 Locale countryToCheck;
1027 double currencyToCheck;
1028
1029 UnicodeString expected;
1030
1031 // load the cases.
1032 switch((iteration+fOffset) % kNumberOfMessageTests)
1033 {
1034 default:
1035 case 0:
1036 statusToCheck= U_FILE_ACCESS_ERROR;
1037 patternToCheck= "0:Someone from {2} is receiving a #{0}"
1038 " error - {1}. Their telephone call is costing "
1039 "{3,number,currency}."; // number,currency
1040 messageLocale= Locale("en","US");
1041 countryToCheck= Locale("","HR");
1042 currencyToCheck= 8192.77;
1043 expected= "0:Someone from Croatia is receiving a #4 error - "
1044 "U_FILE_ACCESS_ERROR. Their telephone call is costing $8,192.77.";
1045 break;
1046 case 1:
1047 statusToCheck= U_INDEX_OUTOFBOUNDS_ERROR;
1048 patternToCheck= "1:A customer in {2} is receiving a #{0} error - {1}. Their telephone call is costing {3,number,currency}."; // number,currency
1049 messageLocale= Locale("de","DE@currency=DEM");
1050 countryToCheck= Locale("","BF");
1051 currencyToCheck= 2.32;
1052 expected= CharsToUnicodeString(
1053 "1:A customer in Burkina Faso is receiving a #8 error - U_INDEX_OUTOFBOUNDS_ERROR. Their telephone call is costing 2,32\\u00A0DM.");
1054 break;
1055 case 2:
1056 statusToCheck= U_MEMORY_ALLOCATION_ERROR;
1057 patternToCheck= "2:user in {2} is receiving a #{0} error - {1}. "
1058 "They insist they just spent {3,number,currency} "
1059 "on memory."; // number,currency
1060 messageLocale= Locale("de","AT@currency=ATS"); // Austrian German
1061 countryToCheck= Locale("","US"); // hmm
1062 currencyToCheck= 40193.12;
1063 expected= CharsToUnicodeString(
1064 "2:user in Vereinigte Staaten is receiving a #7 error"
1065 " - U_MEMORY_ALLOCATION_ERROR. They insist they just spent"
1066 " \\u00f6S\\u00A040.193,12 on memory.");
1067 break;
1068 }
1069
1070 UnicodeString result;
1071 UErrorCode status = U_ZERO_ERROR;
1072 formatErrorMessage(status,patternToCheck,messageLocale,statusToCheck,
1073 countryToCheck,currencyToCheck,result);
1074 if(U_FAILURE(status))
1075 {
1076 UnicodeString tmp(u_errorName(status));
1077 error("Failure on message format, pattern=" + patternToCheck +
1078 ", error = " + tmp);
1079 goto cleanupAndReturn;
1080 }
1081
1082 if(result != expected)
1083 {
1084 error("PatternFormat: \n" + showDifference(expected,result));
1085 goto cleanupAndReturn;
1086 }
1087 } /* end of for loop */
1088
1089 cleanupAndReturn:
1090 delete formatter;
1091 delete percentFormatter;
1092
1093 // while (fNum == 4) {SimpleThread::sleep(10000);} // Force a failure by preventing thread from finishing
1094 fTraceInfo = 2;
1095 }
1096
1097 private:
1098 int32_t fOffset; // where we are testing from.
1099 };
1100
1101 // ** The actual test function.
1102
1103 void MultithreadTest::TestThreadedIntl()
1104 {
1105 int i;
1106 UnicodeString theErr;
1107 UBool haveDisplayedInfo[kFormatThreadThreads];
1108 static const int32_t PATIENCE_SECONDS = 45;
1109
1110 //
1111 // Create and start the test threads
1112 //
1113 logln("Spawning: %d threads * %d iterations each.",
1114 kFormatThreadThreads, kFormatThreadIterations);
1115 FormatThreadTest *tests = new FormatThreadTest[kFormatThreadThreads];
1116 for(int32_t j = 0; j < kFormatThreadThreads; j++) {
1117 tests[j].fNum = j;
1118 int32_t threadStatus = tests[j].start();
1119 if (threadStatus != 0) {
1120 errln("System Error %d starting thread number %d.", threadStatus, j);
1121 SimpleThread::errorFunc();
1122 goto cleanupAndReturn;
1123 }
1124 haveDisplayedInfo[j] = FALSE;
1125 }
1126
1127
1128 // Spin, waiting for the test threads to finish.
1129 UBool stillRunning;
1130 UDate startTime, endTime;
1131 startTime = Calendar::getNow();
1132 do {
1133 /* Spin until the test threads complete. */
1134 stillRunning = FALSE;
1135 endTime = Calendar::getNow();
1136 if (((int32_t)(endTime - startTime)/U_MILLIS_PER_SECOND) > PATIENCE_SECONDS) {
1137 errln("Patience exceeded. Test is taking too long.");
1138 return;
1139 }
1140 /*
1141 The following sleep must be here because the *BSD operating systems
1142 have a brain dead thread scheduler. They starve the child threads from
1143 CPU time.
1144 */
1145 SimpleThread::sleep(1); // yield
1146 for(i=0;i<kFormatThreadThreads;i++) {
1147 if (tests[i].isRunning()) {
1148 stillRunning = TRUE;
1149 } else if (haveDisplayedInfo[i] == FALSE) {
1150 logln("Thread # %d is complete..", i);
1151 if(tests[i].getError(theErr)) {
1152 errln(UnicodeString("#") + i + ": " + theErr);
1153 SimpleThread::errorFunc();
1154 }
1155 haveDisplayedInfo[i] = TRUE;
1156 }
1157 }
1158 } while (stillRunning);
1159
1160 //
1161 // All threads have finished.
1162 //
1163 cleanupAndReturn:
1164 delete [] tests;
1165 }
1166 #endif /* #if !UCONFIG_NO_FORMATTING */
1167
1168
1169
1170
1171
1172 //-------------------------------------------------------------------------------------------
1173 //
1174 // Collation threading test
1175 //
1176 //-------------------------------------------------------------------------------------------
1177 #if !UCONFIG_NO_COLLATION
1178
1179 #define kCollatorThreadThreads 10 // # of threads to spawn
1180 #define kCollatorThreadPatience kCollatorThreadThreads*30
1181
1182 struct Line {
1183 UChar buff[25];
1184 int32_t buflen;
1185 } ;
1186
1187 class CollatorThreadTest : public ThreadWithStatus
1188 {
1189 private:
1190 const UCollator *coll;
1191 const Line *lines;
1192 int32_t noLines;
1193 public:
1194 CollatorThreadTest() : ThreadWithStatus(),
1195 coll(NULL),
1196 lines(NULL),
1197 noLines(0)
1198 {
1199 };
1200 void setCollator(UCollator *c, Line *l, int32_t nl)
1201 {
1202 coll = c;
1203 lines = l;
1204 noLines = nl;
1205 }
1206 virtual void run() {
1207 //sleep(10000);
1208 int32_t line = 0;
1209
1210 uint8_t sk1[1024], sk2[1024];
1211 uint8_t *oldSk = NULL, *newSk = sk1;
1212 int32_t resLen = 0, oldLen = 0;
1213 int32_t i = 0;
1214
1215 for(i = 0; i < noLines; i++) {
1216 resLen = ucol_getSortKey(coll, lines[i].buff, lines[i].buflen, newSk, 1024);
1217
1218 int32_t res = 0, cmpres = 0, cmpres2 = 0;
1219
1220 if(oldSk != NULL) {
1221 res = strcmp((char *)oldSk, (char *)newSk);
1222 cmpres = ucol_strcoll(coll, lines[i-1].buff, lines[i-1].buflen, lines[i].buff, lines[i].buflen);
1223 cmpres2 = ucol_strcoll(coll, lines[i].buff, lines[i].buflen, lines[i-1].buff, lines[i-1].buflen);
1224 //cmpres = res;
1225 //cmpres2 = -cmpres;
1226
1227 if(cmpres != -cmpres2) {
1228 error("Compare result not symmetrical on line "+ line);
1229 break;
1230 }
1231
1232 if(((res&0x80000000) != (cmpres&0x80000000)) || (res == 0 && cmpres != 0) || (res != 0 && cmpres == 0)) {
1233 error(UnicodeString("Difference between ucol_strcoll and sortkey compare on line ")+ UnicodeString(line));
1234 break;
1235 }
1236
1237 if(res > 0) {
1238 error(UnicodeString("Line %i is not greater or equal than previous line ")+ UnicodeString(i));
1239 break;
1240 } else if(res == 0) { /* equal */
1241 res = u_strcmpCodePointOrder(lines[i-1].buff, lines[i].buff);
1242 if (res == 0) {
1243 error(UnicodeString("Probable error in test file on line %i (comparing identical strings)")+ UnicodeString(i));
1244 break;
1245 } else if (res > 0) {
1246 error(UnicodeString("Sortkeys are identical, but code point comapare gives >0 on line ")+ UnicodeString(i));
1247 break;
1248 }
1249 }
1250 }
1251
1252 oldSk = newSk;
1253 oldLen = resLen;
1254
1255 newSk = (newSk == sk1)?sk2:sk1;
1256 }
1257 }
1258
1259 };
1260
1261 void MultithreadTest::TestCollators()
1262 {
1263
1264 UErrorCode status = U_ZERO_ERROR;
1265 FILE *testFile = NULL;
1266 char testDataPath[1024];
1267 strcpy(testDataPath, IntlTest::getSourceTestData(status));
1268 if (U_FAILURE(status)) {
1269 errln("ERROR: could not open test data %s", u_errorName(status));
1270 return;
1271 }
1272 strcat(testDataPath, "CollationTest_");
1273
1274 const char* type = "NON_IGNORABLE";
1275
1276 const char *ext = ".txt";
1277 if(testFile) {
1278 fclose(testFile);
1279 }
1280 char buffer[1024];
1281 strcpy(buffer, testDataPath);
1282 strcat(buffer, type);
1283 size_t bufLen = strlen(buffer);
1284
1285 // we try to open 3 files:
1286 // path/CollationTest_type.txt
1287 // path/CollationTest_type_SHORT.txt
1288 // path/CollationTest_type_STUB.txt
1289 // we are going to test with the first one that we manage to open.
1290
1291 strcpy(buffer+bufLen, ext);
1292
1293 testFile = fopen(buffer, "rb");
1294
1295 if(testFile == 0) {
1296 strcpy(buffer+bufLen, "_SHORT");
1297 strcat(buffer, ext);
1298 testFile = fopen(buffer, "rb");
1299
1300 if(testFile == 0) {
1301 strcpy(buffer+bufLen, "_STUB");
1302 strcat(buffer, ext);
1303 testFile = fopen(buffer, "rb");
1304
1305 if (testFile == 0) {
1306 *(buffer+bufLen) = 0;
1307 dataerrln("[DATA] could not open any of the conformance test files, tried opening base %s", buffer);
1308 return;
1309 } else {
1310 infoln(
1311 "INFO: Working with the stub file.\n"
1312 "If you need the full conformance test, please\n"
1313 "download the appropriate data files from:\n"
1314 "http://source.icu-project.org/repos/icu/tools/trunk/unicodetools/com/ibm/text/data/");
1315 }
1316 }
1317 }
1318
1319 Line *lines = new Line[200000];
1320 memset(lines, 0, sizeof(Line)*200000);
1321 int32_t lineNum = 0;
1322
1323 UChar bufferU[1024];
1324 int32_t buflen = 0;
1325 uint32_t first = 0;
1326 uint32_t offset = 0;
1327
1328 while (fgets(buffer, 1024, testFile) != NULL) {
1329 offset = 0;
1330 if(*buffer == 0 || strlen(buffer) < 3 || buffer[0] == '#') {
1331 continue;
1332 }
1333 offset = u_parseString(buffer, bufferU, 1024, &first, &status);
1334 buflen = offset;
1335 bufferU[offset++] = 0;
1336 lines[lineNum].buflen = buflen;
1337 //lines[lineNum].buff = new UChar[buflen+1];
1338 u_memcpy(lines[lineNum].buff, bufferU, buflen);
1339 lineNum++;
1340 }
1341 fclose(testFile);
1342 if(U_FAILURE(status)) {
1343 dataerrln("[DATA] Couldn't read the test file!");
1344 return;
1345 }
1346
1347 UCollator *coll = ucol_open("root", &status);
1348 if(U_FAILURE(status)) {
1349 errln("Couldn't open UCA collator");
1350 return;
1351 }
1352 ucol_setAttribute(coll, UCOL_NORMALIZATION_MODE, UCOL_ON, &status);
1353 ucol_setAttribute(coll, UCOL_CASE_FIRST, UCOL_OFF, &status);
1354 ucol_setAttribute(coll, UCOL_CASE_LEVEL, UCOL_OFF, &status);
1355 ucol_setAttribute(coll, UCOL_STRENGTH, UCOL_TERTIARY, &status);
1356 ucol_setAttribute(coll, UCOL_ALTERNATE_HANDLING, UCOL_NON_IGNORABLE, &status);
1357
1358 int32_t noSpawned = 0;
1359 int32_t spawnResult = 0;
1360 CollatorThreadTest *tests;
1361 tests = new CollatorThreadTest[kCollatorThreadThreads];
1362
1363 logln(UnicodeString("Spawning: ") + kCollatorThreadThreads + " threads * " + kFormatThreadIterations + " iterations each.");
1364 int32_t j = 0;
1365 for(j = 0; j < kCollatorThreadThreads; j++) {
1366 //logln("Setting collator %i", j);
1367 tests[j].setCollator(coll, lines, lineNum);
1368 }
1369 for(j = 0; j < kCollatorThreadThreads; j++) {
1370 log("%i ", j);
1371 spawnResult = tests[j].start();
1372 if(spawnResult != 0) {
1373 infoln("THREAD INFO: Couldn't spawn more than %i threads", noSpawned);
1374 break;
1375 }
1376 noSpawned++;
1377 }
1378 logln("Spawned all");
1379 if (noSpawned == 0) {
1380 errln("No threads could be spawned.");
1381 return;
1382 }
1383
1384 for(int32_t patience = kCollatorThreadPatience;patience > 0; patience --)
1385 {
1386 logln("Waiting...");
1387
1388 int32_t i;
1389 int32_t terrs = 0;
1390 int32_t completed =0;
1391
1392 for(i=0;i<kCollatorThreadThreads;i++)
1393 {
1394 if (tests[i].isRunning() == FALSE)
1395 {
1396 completed++;
1397
1398 //logln(UnicodeString("Test #") + i + " is complete.. ");
1399
1400 UnicodeString theErr;
1401 if(tests[i].getError(theErr))
1402 {
1403 terrs++;
1404 errln(UnicodeString("#") + i + ": " + theErr);
1405 }
1406 // print out the error, too, if any.
1407 }
1408 }
1409 logln("Completed %i tests", completed);
1410
1411 if(completed == noSpawned)
1412 {
1413 logln("Done! All %i tests are finished", noSpawned);
1414
1415 if(terrs)
1416 {
1417 errln("There were errors.");
1418 SimpleThread::errorFunc();
1419 }
1420 ucol_close(coll);
1421 delete[] tests;
1422 //for(i = 0; i < lineNum; i++) {
1423 //delete[] lines[i].buff;
1424 //}
1425 delete[] lines;
1426
1427 return;
1428 }
1429
1430 SimpleThread::sleep(900);
1431 }
1432 errln("patience exceeded. ");
1433 SimpleThread::errorFunc();
1434 ucol_close(coll);
1435 }
1436
1437 #endif /* #if !UCONFIG_NO_COLLATION */
1438
1439
1440
1441
1442 //-------------------------------------------------------------------------------------------
1443 //
1444 // StringThreadTest2
1445 //
1446 //-------------------------------------------------------------------------------------------
1447
1448 const int kStringThreadIterations = 2500;// # of iterations per thread
1449 const int kStringThreadThreads = 10; // # of threads to spawn
1450 const int kStringThreadPatience = 120; // time in seconds to wait for all threads
1451
1452
1453 class StringThreadTest2 : public ThreadWithStatus
1454 {
1455 public:
1456 int fNum;
1457 int fTraceInfo;
1458 const UnicodeString *fSharedString;
1459
1460 StringThreadTest2(const UnicodeString *sharedString, int num) // constructor is NOT multithread safe.
1461 : ThreadWithStatus(),
1462 fNum(num),
1463 fTraceInfo(0),
1464 fSharedString(sharedString)
1465 {
1466 };
1467
1468
1469 virtual void run()
1470 {
1471 fTraceInfo = 1;
1472 int loopCount = 0;
1473
1474 for (loopCount = 0; loopCount < kStringThreadIterations; loopCount++) {
1475 if (*fSharedString != "This is the original test string.") {
1476 error("Original string is corrupt.");
1477 break;
1478 }
1479 UnicodeString s1 = *fSharedString;
1480 s1 += "cat this";
1481 UnicodeString s2(s1);
1482 UnicodeString s3 = *fSharedString;
1483 s2 = s3;
1484 s3.truncate(12);
1485 s2.truncate(0);
1486 }
1487
1488 // while (fNum == 4) {SimpleThread::sleep(10000);} // Force a failure by preventing thread from finishing
1489 fTraceInfo = 2;
1490 }
1491
1492 };
1493
1494 // ** The actual test function.
1495
1496 void MultithreadTest::TestString()
1497 {
1498 int patience;
1499 int terrs = 0;
1500 int j;
1501
1502 UnicodeString *testString = new UnicodeString("This is the original test string.");
1503
1504 StringThreadTest2 *tests[kStringThreadThreads];
1505 for(j = 0; j < kStringThreadThreads; j++) {
1506 tests[j] = new StringThreadTest2(testString, j);
1507 }
1508
1509 logln(UnicodeString("Spawning: ") + kStringThreadThreads + " threads * " + kStringThreadIterations + " iterations each.");
1510 for(j = 0; j < kStringThreadThreads; j++) {
1511 int32_t threadStatus = tests[j]->start();
1512 if (threadStatus != 0) {
1513 errln("System Error %d starting thread number %d.", threadStatus, j);
1514 SimpleThread::errorFunc();
1515 goto cleanupAndReturn;
1516 }
1517 }
1518
1519 for(patience = kStringThreadPatience;patience > 0; patience --)
1520 {
1521 logln("Waiting...");
1522
1523 int32_t i;
1524 terrs = 0;
1525 int32_t completed =0;
1526
1527 for(i=0;i<kStringThreadThreads;i++) {
1528 if (tests[i]->isRunning() == FALSE)
1529 {
1530 completed++;
1531
1532 logln(UnicodeString("Test #") + i + " is complete.. ");
1533
1534 UnicodeString theErr;
1535 if(tests[i]->getError(theErr))
1536 {
1537 terrs++;
1538 errln(UnicodeString("#") + i + ": " + theErr);
1539 }
1540 // print out the error, too, if any.
1541 }
1542 }
1543
1544 if(completed == kStringThreadThreads)
1545 {
1546 logln("Done!");
1547 if(terrs) {
1548 errln("There were errors.");
1549 }
1550 break;
1551 }
1552
1553 SimpleThread::sleep(900);
1554 }
1555
1556 if (patience <= 0) {
1557 errln("patience exceeded. ");
1558 // while (TRUE) {SimpleThread::sleep(10000);} // TODO: for debugging. Sleep forever on failure.
1559 terrs++;
1560 }
1561
1562 if (terrs > 0) {
1563 SimpleThread::errorFunc();
1564 }
1565
1566 cleanupAndReturn:
1567 if (terrs == 0) {
1568 /*
1569 Don't clean up if there are errors. This prevents crashes if the
1570 threads are still running and using this data. This will only happen
1571 if there is an error with the test, ICU, or the machine is too slow.
1572 It's better to leak than crash.
1573 */
1574 for(j = 0; j < kStringThreadThreads; j++) {
1575 delete tests[j];
1576 }
1577 delete testString;
1578 }
1579 }
1580
1581
1582
1583
1584
1585 #endif // ICU_USE_THREADS
1586