• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /********************************************************************
2  * COPYRIGHT:
3  * Copyright (c) 1999-2007, 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 
MultithreadTest()84 MultithreadTest::MultithreadTest()
85 {
86 }
87 
~MultithreadTest()88 MultithreadTest::~MultithreadTest()
89 {
90 }
91 
92 
93 
94 #if (ICU_USE_THREADS==0)
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)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 
errorFunc()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 
SimpleThreadProc(void * arg)187 extern "C" unsigned int __stdcall SimpleThreadProc(void *arg)
188 {
189     ((SimpleThread*)arg)->run();
190     return 0;
191 }
192 
SimpleThread()193 SimpleThread::SimpleThread()
194 :fImplementation(0)
195 {
196     Win32ThreadImplementation *imp = new Win32ThreadImplementation;
197     imp->fHandle = 0;
198     fImplementation = imp;
199 }
200 
~SimpleThread()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 
start()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 
isRunning()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 
sleep(int32_t millis)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 
SimpleThread()296 SimpleThread::SimpleThread()
297 {}
298 
~SimpleThread()299 SimpleThread::~SimpleThread()
300 {}
301 
302 int32_t
start()303 SimpleThread::start()
304 { return 0; }
305 
306 void
run()307 SimpleThread::run()
308 {}
309 
310 void
sleep(int32_t millis)311 SimpleThread::sleep(int32_t millis)
312 {}
313 
314 UBool
isRunning()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 
SimpleThreadProc(void * arg)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 
SimpleThread()369 SimpleThread::SimpleThread()
370 {
371     PosixThreadImplementation *imp = new PosixThreadImplementation;
372     imp->fRunning   = FALSE;
373     imp->fRan       = FALSE;
374     fImplementation = imp;
375 }
376 
~SimpleThread()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 
start()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
isRunning()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 
sleep(int32_t millis)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. */
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)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:
TestThreadsThread(char * whatToChange)546     TestThreadsThread(char* whatToChange) { fWhatToChange = whatToChange; }
run()547     virtual void run() { SimpleThread::sleep(1000);
548                          Mutex m;
549                          *fWhatToChange = '*';
550     }
551 private:
552     char *fWhatToChange;
553 };
554 
TestThreads()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 
safeIncr(int & var,int amt)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:
run()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 
TestMutex()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:
getError()758     UBool  getError() { return (fErrors > 0); }
getError(UnicodeString & fillinError)759     UBool  getError(UnicodeString& fillinError) { fillinError = fErrorString; return (fErrors > 0); }
~ThreadWithStatus()760     virtual ~ThreadWithStatus(){}
761 protected:
ThreadWithStatus()762     ThreadWithStatus() :  fErrors(0) {}
error(const UnicodeString & error)763     void error(const UnicodeString &error) {
764         fErrors++; fErrorString = error;
765         SimpleThread::errorFunc();
766     }
error()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.
showDifference(const UnicodeString & expected,const UnicodeString & result)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;
FormatThreadTestDataFormatThreadTestData831     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 
formatErrorMessage(UErrorCode & realStatus,const UnicodeString & pattern,const Locale & theLocale,UErrorCode inStatus0,const Locale & inCountry2,double currency3,UnicodeString & result)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 
isAcceptable(void *,const char *,const char *,const UDataInfo *)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 
FormatThreadTest()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 
run()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=                           "1:A customer in Burkina Faso is receiving a #8 error - U_INDEX_OUTOFBOUNDS_ERROR. Their telephone call is costing 2,32 DM.";
1053                 break;
1054             case 2:
1055                 statusToCheck=                      U_MEMORY_ALLOCATION_ERROR;
1056                 patternToCheck=   "2:user in {2} is receiving a #{0} error - {1}. "
1057                                   "They insist they just spent {3,number,currency} "
1058                                   "on memory."; // number,currency
1059                 messageLocale=                      Locale("de","AT@currency=ATS"); // Austrian German
1060                 countryToCheck=                     Locale("","US"); // hmm
1061                 currencyToCheck=                    40193.12;
1062                 expected=       CharsToUnicodeString(
1063                             "2:user in Vereinigte Staaten is receiving a #7 error"
1064                             " - U_MEMORY_ALLOCATION_ERROR. They insist they just spent"
1065                             " \\u00f6S 40.193,12 on memory.");
1066                 break;
1067             }
1068 
1069             UnicodeString result;
1070             UErrorCode status = U_ZERO_ERROR;
1071             formatErrorMessage(status,patternToCheck,messageLocale,statusToCheck,
1072                                 countryToCheck,currencyToCheck,result);
1073             if(U_FAILURE(status))
1074             {
1075                 UnicodeString tmp(u_errorName(status));
1076                 error("Failure on message format, pattern=" + patternToCheck +
1077                         ", error = " + tmp);
1078                 goto cleanupAndReturn;
1079             }
1080 
1081             if(result != expected)
1082             {
1083                 error("PatternFormat: \n" + showDifference(expected,result));
1084                 goto cleanupAndReturn;
1085             }
1086         }   /*  end of for loop */
1087 
1088 cleanupAndReturn:
1089         delete formatter;
1090         delete percentFormatter;
1091 
1092         //  while (fNum == 4) {SimpleThread::sleep(10000);}   // Force a failure by preventing thread from finishing
1093         fTraceInfo = 2;
1094     }
1095 
1096 private:
1097     int32_t fOffset; // where we are testing from.
1098 };
1099 
1100 // ** The actual test function.
1101 
TestThreadedIntl()1102 void MultithreadTest::TestThreadedIntl()
1103 {
1104     int i;
1105     UnicodeString theErr;
1106     UBool   haveDisplayedInfo[kFormatThreadThreads];
1107     static const int32_t PATIENCE_SECONDS = 45;
1108 
1109     //
1110     //  Create and start the test threads
1111     //
1112     logln("Spawning: %d threads * %d iterations each.",
1113                 kFormatThreadThreads, kFormatThreadIterations);
1114     FormatThreadTest  *tests = new FormatThreadTest[kFormatThreadThreads];
1115     for(int32_t j = 0; j < kFormatThreadThreads; j++) {
1116         tests[j].fNum = j;
1117         int32_t threadStatus = tests[j].start();
1118         if (threadStatus != 0) {
1119             errln("System Error %d starting thread number %d.", threadStatus, j);
1120             SimpleThread::errorFunc();
1121             goto cleanupAndReturn;
1122         }
1123         haveDisplayedInfo[j] = FALSE;
1124     }
1125 
1126 
1127     // Spin, waiting for the test threads to finish.
1128     UBool   stillRunning;
1129     UDate startTime, endTime;
1130     startTime = Calendar::getNow();
1131     do {
1132         /*  Spin until the test threads  complete. */
1133         stillRunning = FALSE;
1134         endTime = Calendar::getNow();
1135         if (((int32_t)(endTime - startTime)/U_MILLIS_PER_SECOND) > PATIENCE_SECONDS) {
1136             errln("Patience exceeded. Test is taking too long.");
1137             return;
1138         }
1139         /*
1140          The following sleep must be here because the *BSD operating systems
1141          have a brain dead thread scheduler. They starve the child threads from
1142          CPU time.
1143         */
1144         SimpleThread::sleep(1); // yield
1145         for(i=0;i<kFormatThreadThreads;i++) {
1146             if (tests[i].isRunning()) {
1147                 stillRunning = TRUE;
1148             } else if (haveDisplayedInfo[i] == FALSE) {
1149                 logln("Thread # %d is complete..", i);
1150                 if(tests[i].getError(theErr)) {
1151                     errln(UnicodeString("#") + i + ": " + theErr);
1152                     SimpleThread::errorFunc();
1153                 }
1154                 haveDisplayedInfo[i] = TRUE;
1155             }
1156         }
1157     } while (stillRunning);
1158 
1159     //
1160     //  All threads have finished.
1161     //
1162 cleanupAndReturn:
1163     delete [] tests;
1164 }
1165 #endif /* #if !UCONFIG_NO_FORMATTING */
1166 
1167 
1168 
1169 
1170 
1171 //-------------------------------------------------------------------------------------------
1172 //
1173 // Collation threading test
1174 //
1175 //-------------------------------------------------------------------------------------------
1176 #if !UCONFIG_NO_COLLATION
1177 
1178 #define kCollatorThreadThreads   10  // # of threads to spawn
1179 #define kCollatorThreadPatience kCollatorThreadThreads*30
1180 
1181 struct Line {
1182     UChar buff[25];
1183     int32_t buflen;
1184 } ;
1185 
1186 class CollatorThreadTest : public ThreadWithStatus
1187 {
1188 private:
1189     const UCollator *coll;
1190     const Line *lines;
1191     int32_t noLines;
1192 public:
CollatorThreadTest()1193     CollatorThreadTest()  : ThreadWithStatus(),
1194         coll(NULL),
1195         lines(NULL),
1196         noLines(0)
1197     {
1198     };
setCollator(UCollator * c,Line * l,int32_t nl)1199     void setCollator(UCollator *c, Line *l, int32_t nl)
1200     {
1201         coll = c;
1202         lines = l;
1203         noLines = nl;
1204     }
run()1205     virtual void run() {
1206         //sleep(10000);
1207         int32_t line = 0;
1208 
1209         uint8_t sk1[1024], sk2[1024];
1210         uint8_t *oldSk = NULL, *newSk = sk1;
1211         int32_t resLen = 0, oldLen = 0;
1212         int32_t i = 0;
1213 
1214         for(i = 0; i < noLines; i++) {
1215             resLen = ucol_getSortKey(coll, lines[i].buff, lines[i].buflen, newSk, 1024);
1216 
1217             int32_t res = 0, cmpres = 0, cmpres2 = 0;
1218 
1219             if(oldSk != NULL) {
1220                 res = strcmp((char *)oldSk, (char *)newSk);
1221                 cmpres = ucol_strcoll(coll, lines[i-1].buff, lines[i-1].buflen, lines[i].buff, lines[i].buflen);
1222                 cmpres2 = ucol_strcoll(coll, lines[i].buff, lines[i].buflen, lines[i-1].buff, lines[i-1].buflen);
1223                 //cmpres = res;
1224                 //cmpres2 = -cmpres;
1225 
1226                 if(cmpres != -cmpres2) {
1227                     error("Compare result not symmetrical on line "+ line);
1228                     break;
1229                 }
1230 
1231                 if(((res&0x80000000) != (cmpres&0x80000000)) || (res == 0 && cmpres != 0) || (res != 0 && cmpres == 0)) {
1232                     error(UnicodeString("Difference between ucol_strcoll and sortkey compare on line ")+ UnicodeString(line));
1233                     break;
1234                 }
1235 
1236                 if(res > 0) {
1237                     error(UnicodeString("Line %i is not greater or equal than previous line ")+ UnicodeString(i));
1238                     break;
1239                 } else if(res == 0) { /* equal */
1240                     res = u_strcmpCodePointOrder(lines[i-1].buff, lines[i].buff);
1241                     if (res == 0) {
1242                         error(UnicodeString("Probable error in test file on line %i (comparing identical strings)")+ UnicodeString(i));
1243                         break;
1244                     } else if (res > 0) {
1245                         error(UnicodeString("Sortkeys are identical, but code point comapare gives >0 on line ")+ UnicodeString(i));
1246                         break;
1247                     }
1248                 }
1249             }
1250 
1251             oldSk = newSk;
1252             oldLen = resLen;
1253 
1254             newSk = (newSk == sk1)?sk2:sk1;
1255         }
1256     }
1257 
1258 };
1259 
TestCollators()1260 void MultithreadTest::TestCollators()
1261 {
1262 
1263     UErrorCode status = U_ZERO_ERROR;
1264     FILE *testFile = NULL;
1265     char testDataPath[1024];
1266     strcpy(testDataPath, IntlTest::getSourceTestData(status));
1267     if (U_FAILURE(status)) {
1268         errln("ERROR: could not open test data %s", u_errorName(status));
1269         return;
1270     }
1271     strcat(testDataPath, "CollationTest_");
1272 
1273     const char* type = "NON_IGNORABLE";
1274 
1275     const char *ext = ".txt";
1276     if(testFile) {
1277         fclose(testFile);
1278     }
1279     char buffer[1024];
1280     strcpy(buffer, testDataPath);
1281     strcat(buffer, type);
1282     size_t bufLen = strlen(buffer);
1283 
1284     // we try to open 3 files:
1285     // path/CollationTest_type.txt
1286     // path/CollationTest_type_SHORT.txt
1287     // path/CollationTest_type_STUB.txt
1288     // we are going to test with the first one that we manage to open.
1289 
1290     strcpy(buffer+bufLen, ext);
1291 
1292     testFile = fopen(buffer, "rb");
1293 
1294     if(testFile == 0) {
1295         strcpy(buffer+bufLen, "_SHORT");
1296         strcat(buffer, ext);
1297         testFile = fopen(buffer, "rb");
1298 
1299         if(testFile == 0) {
1300             strcpy(buffer+bufLen, "_STUB");
1301             strcat(buffer, ext);
1302             testFile = fopen(buffer, "rb");
1303 
1304             if (testFile == 0) {
1305                 *(buffer+bufLen) = 0;
1306                 errln("ERROR: could not open any of the conformance test files, tried opening base %s", buffer);
1307                 return;
1308             } else {
1309                 infoln(
1310                     "INFO: Working with the stub file.\n"
1311                     "If you need the full conformance test, please\n"
1312                     "download the appropriate data files from:\n"
1313                     "http://source.icu-project.org/repos/icu/tools/trunk/unicodetools/com/ibm/text/data/");
1314             }
1315         }
1316     }
1317 
1318     Line *lines = new Line[200000];
1319     memset(lines, 0, sizeof(Line)*200000);
1320     int32_t lineNum = 0;
1321 
1322     UChar bufferU[1024];
1323     int32_t buflen = 0;
1324     uint32_t first = 0;
1325     uint32_t offset = 0;
1326 
1327     while (fgets(buffer, 1024, testFile) != NULL) {
1328         offset = 0;
1329         if(*buffer == 0 || strlen(buffer) < 3 || buffer[0] == '#') {
1330             continue;
1331         }
1332         offset = u_parseString(buffer, bufferU, 1024, &first, &status);
1333         buflen = offset;
1334         bufferU[offset++] = 0;
1335         lines[lineNum].buflen = buflen;
1336         //lines[lineNum].buff = new UChar[buflen+1];
1337         u_memcpy(lines[lineNum].buff, bufferU, buflen);
1338         lineNum++;
1339     }
1340     fclose(testFile);
1341     if(U_FAILURE(status)) {
1342       errln("Couldn't read the test file!");
1343       return;
1344     }
1345 
1346     UCollator *coll = ucol_open("root", &status);
1347     if(U_FAILURE(status)) {
1348         errln("Couldn't open UCA collator");
1349         return;
1350     }
1351     ucol_setAttribute(coll, UCOL_NORMALIZATION_MODE, UCOL_ON, &status);
1352     ucol_setAttribute(coll, UCOL_CASE_FIRST, UCOL_OFF, &status);
1353     ucol_setAttribute(coll, UCOL_CASE_LEVEL, UCOL_OFF, &status);
1354     ucol_setAttribute(coll, UCOL_STRENGTH, UCOL_TERTIARY, &status);
1355     ucol_setAttribute(coll, UCOL_ALTERNATE_HANDLING, UCOL_NON_IGNORABLE, &status);
1356 
1357     int32_t noSpawned = 0;
1358     int32_t spawnResult = 0;
1359     CollatorThreadTest *tests;
1360     tests = new CollatorThreadTest[kCollatorThreadThreads];
1361 
1362     logln(UnicodeString("Spawning: ") + kCollatorThreadThreads + " threads * " + kFormatThreadIterations + " iterations each.");
1363     int32_t j = 0;
1364     for(j = 0; j < kCollatorThreadThreads; j++) {
1365         //logln("Setting collator %i", j);
1366         tests[j].setCollator(coll, lines, lineNum);
1367     }
1368     for(j = 0; j < kCollatorThreadThreads; j++) {
1369         log("%i ", j);
1370         spawnResult = tests[j].start();
1371         if(spawnResult != 0) {
1372             infoln("THREAD INFO: Couldn't spawn more than %i threads", noSpawned);
1373             break;
1374         }
1375         noSpawned++;
1376     }
1377     logln("Spawned all");
1378     if (noSpawned == 0) {
1379         errln("No threads could be spawned.");
1380         return;
1381     }
1382 
1383     for(int32_t patience = kCollatorThreadPatience;patience > 0; patience --)
1384     {
1385         logln("Waiting...");
1386 
1387         int32_t i;
1388         int32_t terrs = 0;
1389         int32_t completed =0;
1390 
1391         for(i=0;i<kCollatorThreadThreads;i++)
1392         {
1393             if (tests[i].isRunning() == FALSE)
1394             {
1395                 completed++;
1396 
1397                 //logln(UnicodeString("Test #") + i + " is complete.. ");
1398 
1399                 UnicodeString theErr;
1400                 if(tests[i].getError(theErr))
1401                 {
1402                     terrs++;
1403                     errln(UnicodeString("#") + i + ": " + theErr);
1404                 }
1405                 // print out the error, too, if any.
1406             }
1407         }
1408         logln("Completed %i tests", completed);
1409 
1410         if(completed == noSpawned)
1411         {
1412             logln("Done! All %i tests are finished", noSpawned);
1413 
1414             if(terrs)
1415             {
1416                 errln("There were errors.");
1417                 SimpleThread::errorFunc();
1418             }
1419             ucol_close(coll);
1420             delete[] tests;
1421             //for(i = 0; i < lineNum; i++) {
1422             //delete[] lines[i].buff;
1423             //}
1424             delete[] lines;
1425 
1426             return;
1427         }
1428 
1429         SimpleThread::sleep(900);
1430     }
1431     errln("patience exceeded. ");
1432     SimpleThread::errorFunc();
1433     ucol_close(coll);
1434 }
1435 
1436 #endif /* #if !UCONFIG_NO_COLLATION */
1437 
1438 
1439 
1440 
1441 //-------------------------------------------------------------------------------------------
1442 //
1443 //   StringThreadTest2
1444 //
1445 //-------------------------------------------------------------------------------------------
1446 
1447 const int kStringThreadIterations = 2500;// # of iterations per thread
1448 const int kStringThreadThreads    = 10;  // # of threads to spawn
1449 const int kStringThreadPatience   = 120; // time in seconds to wait for all threads
1450 
1451 
1452 class StringThreadTest2 : public ThreadWithStatus
1453 {
1454 public:
1455     int                 fNum;
1456     int                 fTraceInfo;
1457     const UnicodeString *fSharedString;
1458 
StringThreadTest2(const UnicodeString * sharedString,int num)1459     StringThreadTest2(const UnicodeString *sharedString, int num) // constructor is NOT multithread safe.
1460         : ThreadWithStatus(),
1461         fNum(num),
1462         fTraceInfo(0),
1463         fSharedString(sharedString)
1464     {
1465     };
1466 
1467 
run()1468     virtual void run()
1469     {
1470         fTraceInfo    = 1;
1471         int loopCount = 0;
1472 
1473         for (loopCount = 0; loopCount < kStringThreadIterations; loopCount++) {
1474             if (*fSharedString != "This is the original test string.") {
1475                 error("Original string is corrupt.");
1476                 break;
1477             }
1478             UnicodeString s1 = *fSharedString;
1479             s1 += "cat this";
1480             UnicodeString s2(s1);
1481             UnicodeString s3 = *fSharedString;
1482             s2 = s3;
1483             s3.truncate(12);
1484             s2.truncate(0);
1485         }
1486 
1487         //  while (fNum == 4) {SimpleThread::sleep(10000);}   // Force a failure by preventing thread from finishing
1488         fTraceInfo = 2;
1489     }
1490 
1491 };
1492 
1493 // ** The actual test function.
1494 
TestString()1495 void MultithreadTest::TestString()
1496 {
1497     int     patience;
1498     int     terrs = 0;
1499     int     j;
1500 
1501     UnicodeString *testString = new UnicodeString("This is the original test string.");
1502 
1503     StringThreadTest2  *tests[kStringThreadThreads];
1504     for(j = 0; j < kStringThreadThreads; j++) {
1505         tests[j] = new StringThreadTest2(testString, j);
1506     }
1507 
1508     logln(UnicodeString("Spawning: ") + kStringThreadThreads + " threads * " + kStringThreadIterations + " iterations each.");
1509     for(j = 0; j < kStringThreadThreads; j++) {
1510         int32_t threadStatus = tests[j]->start();
1511         if (threadStatus != 0) {
1512             errln("System Error %d starting thread number %d.", threadStatus, j);
1513             SimpleThread::errorFunc();
1514             goto cleanupAndReturn;
1515         }
1516     }
1517 
1518     for(patience = kStringThreadPatience;patience > 0; patience --)
1519     {
1520         logln("Waiting...");
1521 
1522         int32_t i;
1523         terrs = 0;
1524         int32_t completed =0;
1525 
1526         for(i=0;i<kStringThreadThreads;i++) {
1527             if (tests[i]->isRunning() == FALSE)
1528             {
1529                 completed++;
1530 
1531                 logln(UnicodeString("Test #") + i + " is complete.. ");
1532 
1533                 UnicodeString theErr;
1534                 if(tests[i]->getError(theErr))
1535                 {
1536                     terrs++;
1537                     errln(UnicodeString("#") + i + ": " + theErr);
1538                 }
1539                 // print out the error, too, if any.
1540             }
1541         }
1542 
1543         if(completed == kStringThreadThreads)
1544         {
1545             logln("Done!");
1546             if(terrs) {
1547                 errln("There were errors.");
1548             }
1549             break;
1550         }
1551 
1552         SimpleThread::sleep(900);
1553     }
1554 
1555     if (patience <= 0) {
1556         errln("patience exceeded. ");
1557         // while (TRUE) {SimpleThread::sleep(10000);}   // TODO:   for debugging.  Sleep forever on failure.
1558         terrs++;
1559     }
1560 
1561     if (terrs > 0) {
1562         SimpleThread::errorFunc();
1563     }
1564 
1565 cleanupAndReturn:
1566     if (terrs == 0) {
1567         /*
1568         Don't clean up if there are errors. This prevents crashes if the
1569         threads are still running and using this data. This will only happen
1570         if there is an error with the test, ICU, or the machine is too slow.
1571         It's better to leak than crash.
1572         */
1573         for(j = 0; j < kStringThreadThreads; j++) {
1574             delete tests[j];
1575         }
1576         delete testString;
1577     }
1578 }
1579 
1580 
1581 
1582 
1583 
1584 #endif // ICU_USE_THREADS
1585 
1586