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