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