1/********************************************************************
2 * COPYRIGHT:
3 * Copyright (c) 1999-2010, 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#if !defined(U_WINDOWS) && !defined(XP_MAC) && !defined(U_RHAPSODY)
28#define POSIX 1
29#endif
30
31/* Needed by z/OS to get usleep */
32#if defined(OS390)
33#define __DOT1 1
34#define __UU
35#define _XOPEN_SOURCE_EXTENDED 1
36#ifndef _XPG4_2
37#define _XPG4_2
38#endif
39#include <unistd.h>
40/*#include "platform_xopen_source_extended.h"*/
41#endif
42#if defined(POSIX) || defined(U_SOLARIS) || defined(U_AIX) || defined(U_HPUX)
43
44#define HAVE_IMP
45
46#if (ICU_USE_THREADS == 1)
47#include <pthread.h>
48#endif
49
50#if defined(__hpux) && defined(HPUX_CMA)
51# if defined(read)  // read being defined as cma_read causes trouble with iostream::read
52#  undef read
53# endif
54#endif
55
56/* Define __EXTENSIONS__ for Solaris and old friends in strict mode. */
57#ifndef __EXTENSIONS__
58#define __EXTENSIONS__
59#endif
60
61#if defined(OS390)
62#include <sys/types.h>
63#endif
64
65#if !defined(OS390)
66#include <signal.h>
67#endif
68
69/* Define _XPG4_2 for Solaris and friends. */
70#ifndef _XPG4_2
71#define _XPG4_2
72#endif
73
74/* Define __USE_XOPEN_EXTENDED for Linux and glibc. */
75#ifndef __USE_XOPEN_EXTENDED
76#define __USE_XOPEN_EXTENDED
77#endif
78
79/* Define _INCLUDE_XOPEN_SOURCE_EXTENDED for HP/UX (11?). */
80#ifndef _INCLUDE_XOPEN_SOURCE_EXTENDED
81#define _INCLUDE_XOPEN_SOURCE_EXTENDED
82#endif
83
84#include <unistd.h>
85
86#endif
87/* HPUX */
88#ifdef sleep
89#undef sleep
90#endif
91
92
93
94#include "tsmthred.h"
95
96#define TSMTHREAD_FAIL(msg) errln("%s at file %s, line %d", msg, __FILE__, __LINE__)
97#define TSMTHREAD_ASSERT(expr) {if (!(expr)) {TSMTHREAD_FAIL("Fail");}}
98
99MultithreadTest::MultithreadTest()
100{
101}
102
103MultithreadTest::~MultithreadTest()
104{
105}
106
107
108
109#if (ICU_USE_THREADS==0)
110void MultithreadTest::runIndexedTest( int32_t index, UBool exec,
111                const char* &name, char* /*par*/ ) {
112  if (exec) logln("TestSuite MultithreadTest: ");
113
114  if(index == 0)
115      name = "NO_THREADED_TESTS";
116  else
117      name = "";
118
119  if(exec) { logln("MultithreadTest - test DISABLED.  ICU_USE_THREADS set to 0, check your configuration if this is a problem..");
120  }
121}
122#else
123
124#include <stdio.h>
125#include <string.h>
126#include <ctype.h>    // tolower, toupper
127
128#include "unicode/putil.h"
129
130// for mthreadtest
131#include "unicode/numfmt.h"
132#include "unicode/choicfmt.h"
133#include "unicode/msgfmt.h"
134#include "unicode/locid.h"
135#include "unicode/ucol.h"
136#include "unicode/calendar.h"
137#include "ucaconf.h"
138
139void SimpleThread::errorFunc() {
140    // *(char *)0 = 3;            // Force entry into a debugger via a crash;
141}
142
143void MultithreadTest::runIndexedTest( int32_t index, UBool exec,
144                const char* &name, char* /*par*/ ) {
145    if (exec)
146        logln("TestSuite MultithreadTest: ");
147    switch (index) {
148    case 0:
149        name = "TestThreads";
150        if (exec)
151            TestThreads();
152        break;
153
154    case 1:
155        name = "TestMutex";
156        if (exec)
157            TestMutex();
158        break;
159
160    case 2:
161        name = "TestThreadedIntl";
162#if !UCONFIG_NO_FORMATTING
163        if (exec) {
164            TestThreadedIntl();
165        }
166#endif
167        break;
168
169    case 3:
170      name = "TestCollators";
171#if !UCONFIG_NO_COLLATION
172      if (exec) {
173            TestCollators();
174      }
175#endif /* #if !UCONFIG_NO_COLLATION */
176      break;
177
178    case 4:
179        name = "TestString";
180        if (exec) {
181            TestString();
182        }
183        break;
184
185    default:
186        name = "";
187        break; //needed to end loop
188    }
189}
190
191
192//-----------------------------------------------------------------------------------
193//
194//   TestThreads -- see if threads really work at all.
195//
196//   Set up N threads pointing at N chars. When they are started, they will
197//   each sleep 1 second and then set their chars. At the end we make sure they
198//   are all set.
199//
200//-----------------------------------------------------------------------------------
201#define THREADTEST_NRTHREADS 8
202
203class TestThreadsThread : public SimpleThread
204{
205public:
206    TestThreadsThread(char* whatToChange) { fWhatToChange = whatToChange; }
207    virtual void run() { SimpleThread::sleep(1000);
208                         Mutex m;
209                         *fWhatToChange = '*';
210    }
211private:
212    char *fWhatToChange;
213};
214
215void MultithreadTest::TestThreads()
216{
217    char threadTestChars[THREADTEST_NRTHREADS + 1];
218    SimpleThread *threads[THREADTEST_NRTHREADS];
219    int32_t numThreadsStarted = 0;
220
221    int32_t i;
222    for(i=0;i<THREADTEST_NRTHREADS;i++)
223    {
224        threadTestChars[i] = ' ';
225        threads[i] = new TestThreadsThread(&threadTestChars[i]);
226    }
227    threadTestChars[THREADTEST_NRTHREADS] = '\0';
228
229    logln("->" + UnicodeString(threadTestChars) + "<- Firing off threads.. ");
230    for(i=0;i<THREADTEST_NRTHREADS;i++)
231    {
232        if (threads[i]->start() != 0) {
233            errln("Error starting thread %d", i);
234        }
235        else {
236            numThreadsStarted++;
237        }
238        SimpleThread::sleep(100);
239        logln(" Subthread started.");
240    }
241
242    logln("Waiting for threads to be set..");
243    if (numThreadsStarted == 0) {
244        errln("No threads could be started for testing!");
245        return;
246    }
247
248    int32_t patience = 40; // seconds to wait
249
250    while(patience--)
251    {
252        int32_t count = 0;
253        umtx_lock(NULL);
254        for(i=0;i<THREADTEST_NRTHREADS;i++)
255        {
256            if(threadTestChars[i] == '*')
257            {
258                count++;
259            }
260        }
261        umtx_unlock(NULL);
262
263        if(count == THREADTEST_NRTHREADS)
264        {
265            logln("->" + UnicodeString(threadTestChars) + "<- Got all threads! cya");
266            for(i=0;i<THREADTEST_NRTHREADS;i++)
267            {
268                delete threads[i];
269            }
270            return;
271        }
272
273        logln("->" + UnicodeString(threadTestChars) + "<- Waiting..");
274        SimpleThread::sleep(500);
275    }
276
277    errln("->" + UnicodeString(threadTestChars) + "<- PATIENCE EXCEEDED!! Still missing some.");
278    for(i=0;i<THREADTEST_NRTHREADS;i++)
279    {
280        delete threads[i];
281    }
282}
283
284
285//-----------------------------------------------------------------------
286//
287//  TestMutex  - a simple (non-stress) test to verify that ICU mutexes
288//               are actually mutexing.  Does not test the use of
289//               mutexes within ICU services, but rather that the
290//               platform's mutex support is at least superficially there.
291//
292//----------------------------------------------------------------------
293static UMTX    gTestMutexA = NULL;
294static UMTX    gTestMutexB = NULL;
295
296static int     gThreadsStarted = 0;
297static int     gThreadsInMiddle = 0;
298static int     gThreadsDone = 0;
299
300static const int TESTMUTEX_THREAD_COUNT = 4;
301
302static int safeIncr(int &var, int amt) {
303    // Thread safe (using global mutex) increment of a variable.
304    // Return the updated value.
305    // Can also be used as a safe load of a variable by incrementing it by 0.
306    Mutex m;
307    var += amt;
308    return var;
309}
310
311class TestMutexThread : public SimpleThread
312{
313public:
314    virtual void run()
315    {
316        // This is the code that each of the spawned threads runs.
317        // All of the spawned threads bunch up together at each of the two mutexes
318        // because the main holds the mutexes until they do.
319        //
320        safeIncr(gThreadsStarted, 1);
321        umtx_lock(&gTestMutexA);
322        umtx_unlock(&gTestMutexA);
323        safeIncr(gThreadsInMiddle, 1);
324        umtx_lock(&gTestMutexB);
325        umtx_unlock(&gTestMutexB);
326        safeIncr(gThreadsDone, 1);
327    }
328};
329
330void MultithreadTest::TestMutex()
331{
332    // Start up the test threads.  They should all pile up waiting on
333    // gTestMutexA, which we (the main thread) hold until the test threads
334    //   all get there.
335    gThreadsStarted = 0;
336    gThreadsInMiddle = 0;
337    gThreadsDone = 0;
338    umtx_lock(&gTestMutexA);
339    TestMutexThread  *threads[TESTMUTEX_THREAD_COUNT];
340    int i;
341    int32_t numThreadsStarted = 0;
342    for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) {
343        threads[i] = new TestMutexThread;
344        if (threads[i]->start() != 0) {
345            errln("Error starting thread %d", i);
346        }
347        else {
348            numThreadsStarted++;
349        }
350    }
351    if (numThreadsStarted == 0) {
352        errln("No threads could be started for testing!");
353        return;
354    }
355
356    int patience = 0;
357    while (safeIncr(gThreadsStarted, 0) != TESTMUTEX_THREAD_COUNT) {
358        if (patience++ > 24) {
359            TSMTHREAD_FAIL("Patience Exceeded");
360            return;
361        }
362        SimpleThread::sleep(500);
363    }
364    // None of the test threads should have advanced past the first mutex.
365    TSMTHREAD_ASSERT(gThreadsInMiddle==0);
366    TSMTHREAD_ASSERT(gThreadsDone==0);
367
368    //  All of the test threads have made it to the first mutex.
369    //  We (the main thread) now let them advance to the second mutex,
370    //   where they should all pile up again.
371    umtx_lock(&gTestMutexB);
372    umtx_unlock(&gTestMutexA);
373
374    patience = 0;
375    while (safeIncr(gThreadsInMiddle, 0) != TESTMUTEX_THREAD_COUNT) {
376        if (patience++ > 24) {
377            TSMTHREAD_FAIL("Patience Exceeded");
378            return;
379        }
380        SimpleThread::sleep(500);
381    }
382    TSMTHREAD_ASSERT(gThreadsDone==0);
383
384    //  All test threads made it to the second mutex.
385    //   Now let them proceed from there.  They will all terminate.
386    umtx_unlock(&gTestMutexB);
387    patience = 0;
388    while (safeIncr(gThreadsDone, 0) != TESTMUTEX_THREAD_COUNT) {
389        if (patience++ > 24) {
390            TSMTHREAD_FAIL("Patience Exceeded");
391            return;
392        }
393        SimpleThread::sleep(500);
394    }
395
396    // All threads made it by both mutexes.
397    // Destroy the test mutexes.
398    umtx_destroy(&gTestMutexA);
399    umtx_destroy(&gTestMutexB);
400    gTestMutexA=NULL;
401    gTestMutexB=NULL;
402
403    for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) {
404        delete threads[i];
405    }
406
407}
408
409
410//-------------------------------------------------------------------------------------------
411//
412// class ThreadWithStatus - a thread that we can check the status and error condition of
413//
414//-------------------------------------------------------------------------------------------
415class ThreadWithStatus : public SimpleThread
416{
417public:
418    UBool  getError() { return (fErrors > 0); }
419    UBool  getError(UnicodeString& fillinError) { fillinError = fErrorString; return (fErrors > 0); }
420    virtual ~ThreadWithStatus(){}
421protected:
422    ThreadWithStatus() :  fErrors(0) {}
423    void error(const UnicodeString &error) {
424        fErrors++; fErrorString = error;
425        SimpleThread::errorFunc();
426    }
427    void error() { error("An error occured."); }
428private:
429    int32_t fErrors;
430    UnicodeString fErrorString;
431};
432
433
434
435//-------------------------------------------------------------------------------------------
436//
437//   TestMultithreadedIntl.  Test ICU Formatting n a multi-threaded environment
438//
439//-------------------------------------------------------------------------------------------
440
441
442// * Show exactly where the string's differences lie.
443UnicodeString showDifference(const UnicodeString& expected, const UnicodeString& result)
444{
445    UnicodeString res;
446    res = expected + "<Expected\n";
447    if(expected.length() != result.length())
448        res += " [ Different lengths ] \n";
449    else
450    {
451        for(int32_t i=0;i<expected.length();i++)
452        {
453            if(expected[i] == result[i])
454            {
455                res += " ";
456            }
457            else
458            {
459                res += "|";
460            }
461        }
462        res += "<Differences";
463        res += "\n";
464    }
465    res += result + "<Result\n";
466
467    return res;
468}
469
470
471
472
473//-------------------------------------------------------------------------------------------
474//
475//   FormatThreadTest - a thread that tests performing a number of numberformats.
476//
477//-------------------------------------------------------------------------------------------
478
479const int kFormatThreadIterations = 20;  // # of iterations per thread
480const int kFormatThreadThreads    = 10;  // # of threads to spawn
481const int kFormatThreadPatience   = 60;  // time in seconds to wait for all threads
482
483#if !UCONFIG_NO_FORMATTING
484
485
486
487struct FormatThreadTestData
488{
489    double number;
490    UnicodeString string;
491    FormatThreadTestData(double a, const UnicodeString& b) : number(a),string(b) {}
492} ;
493
494
495// "Someone from {2} is receiving a #{0} error - {1}. Their telephone call is costing {3 number,currency}."
496
497void formatErrorMessage(UErrorCode &realStatus, const UnicodeString& pattern, const Locale& theLocale,
498                     UErrorCode inStatus0, /* statusString 1 */ const Locale &inCountry2, double currency3, // these numbers are the message arguments.
499                     UnicodeString &result)
500{
501    if(U_FAILURE(realStatus))
502        return; // you messed up
503
504    UnicodeString errString1(u_errorName(inStatus0));
505
506    UnicodeString countryName2;
507    inCountry2.getDisplayCountry(theLocale,countryName2);
508
509    Formattable myArgs[] = {
510        Formattable((int32_t)inStatus0),   // inStatus0      {0}
511        Formattable(errString1), // statusString1 {1}
512        Formattable(countryName2),  // inCountry2 {2}
513        Formattable(currency3)// currency3  {3,number,currency}
514    };
515
516    MessageFormat *fmt = new MessageFormat("MessageFormat's API is broken!!!!!!!!!!!",realStatus);
517    fmt->setLocale(theLocale);
518    fmt->applyPattern(pattern, realStatus);
519
520    if (U_FAILURE(realStatus)) {
521        delete fmt;
522        return;
523    }
524
525    FieldPosition ignore = 0;
526    fmt->format(myArgs,4,result,ignore,realStatus);
527
528    delete fmt;
529}
530
531
532UBool U_CALLCONV isAcceptable(void *, const char *, const char *, const UDataInfo *) {
533    return TRUE;
534}
535
536//static UMTX debugMutex = NULL;
537//static UMTX gDebugMutex;
538
539
540class FormatThreadTest : public ThreadWithStatus
541{
542public:
543    int     fNum;
544    int     fTraceInfo;
545
546    FormatThreadTest() // constructor is NOT multithread safe.
547        : ThreadWithStatus(),
548        fNum(0),
549        fTraceInfo(0),
550        fOffset(0)
551        // the locale to use
552    {
553        static int32_t fgOffset = 0;
554        fgOffset += 3;
555        fOffset = fgOffset;
556    }
557
558
559    virtual void run()
560    {
561        fTraceInfo                     = 1;
562        LocalPointer<NumberFormat> percentFormatter;
563        UErrorCode status = U_ZERO_ERROR;
564
565#if 0
566        // debugging code,
567        for (int i=0; i<4000; i++) {
568            status = U_ZERO_ERROR;
569            UDataMemory *data1 = udata_openChoice(0, "res", "en_US", isAcceptable, 0, &status);
570            UDataMemory *data2 = udata_openChoice(0, "res", "fr", isAcceptable, 0, &status);
571            udata_close(data1);
572            udata_close(data2);
573            if (U_FAILURE(status)) {
574                error("udata_openChoice failed.\n");
575                break;
576            }
577        }
578        return;
579#endif
580
581#if 0
582        // debugging code,
583        int m;
584        for (m=0; m<4000; m++) {
585            status         = U_ZERO_ERROR;
586            UResourceBundle *res   = NULL;
587            const char *localeName = NULL;
588
589            Locale  loc = Locale::getEnglish();
590
591            localeName = loc.getName();
592            // localeName = "en";
593
594            // ResourceBundle bund = ResourceBundle(0, loc, status);
595            //umtx_lock(&gDebugMutex);
596            res = ures_open(NULL, localeName, &status);
597            //umtx_unlock(&gDebugMutex);
598
599            //umtx_lock(&gDebugMutex);
600            ures_close(res);
601            //umtx_unlock(&gDebugMutex);
602
603            if (U_FAILURE(status)) {
604                error("Resource bundle construction failed.\n");
605                break;
606            }
607        }
608        return;
609#endif
610
611        // Keep this data here to avoid static initialization.
612        FormatThreadTestData kNumberFormatTestData[] =
613        {
614            FormatThreadTestData((double)5.0, UnicodeString("5", "")),
615                FormatThreadTestData( 6.0, UnicodeString("6", "")),
616                FormatThreadTestData( 20.0, UnicodeString("20", "")),
617                FormatThreadTestData( 8.0, UnicodeString("8", "")),
618                FormatThreadTestData( 8.3, UnicodeString("8.3", "")),
619                FormatThreadTestData( 12345, UnicodeString("12,345", "")),
620                FormatThreadTestData( 81890.23, UnicodeString("81,890.23", "")),
621        };
622        int32_t kNumberFormatTestDataLength = (int32_t)(sizeof(kNumberFormatTestData) /
623                                                        sizeof(kNumberFormatTestData[0]));
624
625        // Keep this data here to avoid static initialization.
626        FormatThreadTestData kPercentFormatTestData[] =
627        {
628            FormatThreadTestData((double)5.0, CharsToUnicodeString("500\\u00a0%")),
629                FormatThreadTestData( 1.0, CharsToUnicodeString("100\\u00a0%")),
630                FormatThreadTestData( 0.26, CharsToUnicodeString("26\\u00a0%")),
631                FormatThreadTestData(
632                   16384.99, CharsToUnicodeString("1\\u00a0638\\u00a0499\\u00a0%")), // U+00a0 = NBSP
633                FormatThreadTestData(
634                    81890.23, CharsToUnicodeString("8\\u00a0189\\u00a0023\\u00a0%")),
635        };
636        int32_t kPercentFormatTestDataLength =
637                (int32_t)(sizeof(kPercentFormatTestData) / sizeof(kPercentFormatTestData[0]));
638        int32_t iteration;
639
640        status = U_ZERO_ERROR;
641        LocalPointer<NumberFormat> formatter(NumberFormat::createInstance(Locale::getEnglish(),status));
642        if(U_FAILURE(status)) {
643            error("Error on NumberFormat::createInstance().");
644            goto cleanupAndReturn;
645        }
646
647        percentFormatter.adoptInstead(NumberFormat::createPercentInstance(Locale::getFrench(),status));
648        if(U_FAILURE(status))             {
649            error("Error on NumberFormat::createPercentInstance().");
650            goto cleanupAndReturn;
651        }
652
653        for(iteration = 0;!getError() && iteration<kFormatThreadIterations;iteration++)
654        {
655
656            int32_t whichLine = (iteration + fOffset)%kNumberFormatTestDataLength;
657
658            UnicodeString  output;
659
660            formatter->format(kNumberFormatTestData[whichLine].number, output);
661
662            if(0 != output.compare(kNumberFormatTestData[whichLine].string)) {
663                error("format().. expected " + kNumberFormatTestData[whichLine].string
664                        + " got " + output);
665                goto cleanupAndReturn;
666            }
667
668            // Now check percent.
669            output.remove();
670            whichLine = (iteration + fOffset)%kPercentFormatTestDataLength;
671
672            percentFormatter->format(kPercentFormatTestData[whichLine].number, output);
673            if(0 != output.compare(kPercentFormatTestData[whichLine].string))
674            {
675                error("percent format().. \n" +
676                        showDifference(kPercentFormatTestData[whichLine].string,output));
677                goto cleanupAndReturn;
678            }
679
680            // Test message error
681            const int       kNumberOfMessageTests = 3;
682            UErrorCode      statusToCheck;
683            UnicodeString   patternToCheck;
684            Locale          messageLocale;
685            Locale          countryToCheck;
686            double          currencyToCheck;
687
688            UnicodeString   expected;
689
690            // load the cases.
691            switch((iteration+fOffset) % kNumberOfMessageTests)
692            {
693            default:
694            case 0:
695                statusToCheck=                      U_FILE_ACCESS_ERROR;
696                patternToCheck=        "0:Someone from {2} is receiving a #{0}"
697                                       " error - {1}. Their telephone call is costing "
698                                       "{3,number,currency}."; // number,currency
699                messageLocale=                      Locale("en","US");
700                countryToCheck=                     Locale("","HR");
701                currencyToCheck=                    8192.77;
702                expected=  "0:Someone from Croatia is receiving a #4 error - "
703                            "U_FILE_ACCESS_ERROR. Their telephone call is costing $8,192.77.";
704                break;
705            case 1:
706                statusToCheck=                      U_INDEX_OUTOFBOUNDS_ERROR;
707                patternToCheck=                     "1:A customer in {2} is receiving a #{0} error - {1}. Their telephone call is costing {3,number,currency}."; // number,currency
708                messageLocale=                      Locale("de","DE@currency=DEM");
709                countryToCheck=                     Locale("","BF");
710                currencyToCheck=                    2.32;
711                expected=                           CharsToUnicodeString(
712                                                    "1:A customer in Burkina Faso is receiving a #8 error - U_INDEX_OUTOFBOUNDS_ERROR. Their telephone call is costing 2,32\\u00A0DM.");
713                break;
714            case 2:
715                statusToCheck=                      U_MEMORY_ALLOCATION_ERROR;
716                patternToCheck=   "2:user in {2} is receiving a #{0} error - {1}. "
717                                  "They insist they just spent {3,number,currency} "
718                                  "on memory."; // number,currency
719                messageLocale=                      Locale("de","AT@currency=ATS"); // Austrian German
720                countryToCheck=                     Locale("","US"); // hmm
721                currencyToCheck=                    40193.12;
722                expected=       CharsToUnicodeString(
723                            "2:user in Vereinigte Staaten is receiving a #7 error"
724                            " - U_MEMORY_ALLOCATION_ERROR. They insist they just spent"
725                            " \\u00f6S\\u00A040.193,12 on memory.");
726                break;
727            }
728
729            UnicodeString result;
730            UErrorCode status = U_ZERO_ERROR;
731            formatErrorMessage(status,patternToCheck,messageLocale,statusToCheck,
732                                countryToCheck,currencyToCheck,result);
733            if(U_FAILURE(status))
734            {
735                UnicodeString tmp(u_errorName(status));
736                error("Failure on message format, pattern=" + patternToCheck +
737                        ", error = " + tmp);
738                goto cleanupAndReturn;
739            }
740
741            if(result != expected)
742            {
743                error("PatternFormat: \n" + showDifference(expected,result));
744                goto cleanupAndReturn;
745            }
746        }   /*  end of for loop */
747
748cleanupAndReturn:
749        //  while (fNum == 4) {SimpleThread::sleep(10000);}   // Force a failure by preventing thread from finishing
750        fTraceInfo = 2;
751    }
752
753private:
754    int32_t fOffset; // where we are testing from.
755};
756
757// ** The actual test function.
758
759void MultithreadTest::TestThreadedIntl()
760{
761    int i;
762    UnicodeString theErr;
763    UBool   haveDisplayedInfo[kFormatThreadThreads];
764    static const int32_t PATIENCE_SECONDS = 45;
765
766    //
767    //  Create and start the test threads
768    //
769    logln("Spawning: %d threads * %d iterations each.",
770                kFormatThreadThreads, kFormatThreadIterations);
771    LocalArray<FormatThreadTest> tests(new FormatThreadTest[kFormatThreadThreads]);
772    for(int32_t j = 0; j < kFormatThreadThreads; j++) {
773        tests[j].fNum = j;
774        int32_t threadStatus = tests[j].start();
775        if (threadStatus != 0) {
776            errln("System Error %d starting thread number %d.", threadStatus, j);
777            SimpleThread::errorFunc();
778            return;
779        }
780        haveDisplayedInfo[j] = FALSE;
781    }
782
783
784    // Spin, waiting for the test threads to finish.
785    UBool   stillRunning;
786    UDate startTime, endTime;
787    startTime = Calendar::getNow();
788    do {
789        /*  Spin until the test threads  complete. */
790        stillRunning = FALSE;
791        endTime = Calendar::getNow();
792        if (((int32_t)(endTime - startTime)/U_MILLIS_PER_SECOND) > PATIENCE_SECONDS) {
793            errln("Patience exceeded. Test is taking too long.");
794            return;
795        }
796        /*
797         The following sleep must be here because the *BSD operating systems
798         have a brain dead thread scheduler. They starve the child threads from
799         CPU time.
800        */
801        SimpleThread::sleep(1); // yield
802        for(i=0;i<kFormatThreadThreads;i++) {
803            if (tests[i].isRunning()) {
804                stillRunning = TRUE;
805            } else if (haveDisplayedInfo[i] == FALSE) {
806                logln("Thread # %d is complete..", i);
807                if(tests[i].getError(theErr)) {
808                    dataerrln(UnicodeString("#") + i + ": " + theErr);
809                    SimpleThread::errorFunc();
810                }
811                haveDisplayedInfo[i] = TRUE;
812            }
813        }
814    } while (stillRunning);
815
816    //
817    //  All threads have finished.
818    //
819}
820#endif /* #if !UCONFIG_NO_FORMATTING */
821
822
823
824
825
826//-------------------------------------------------------------------------------------------
827//
828// Collation threading test
829//
830//-------------------------------------------------------------------------------------------
831#if !UCONFIG_NO_COLLATION
832
833#define kCollatorThreadThreads   10  // # of threads to spawn
834#define kCollatorThreadPatience kCollatorThreadThreads*30
835
836struct Line {
837    UChar buff[25];
838    int32_t buflen;
839} ;
840
841class CollatorThreadTest : public ThreadWithStatus
842{
843private:
844    const UCollator *coll;
845    const Line *lines;
846    int32_t noLines;
847public:
848    CollatorThreadTest()  : ThreadWithStatus(),
849        coll(NULL),
850        lines(NULL),
851        noLines(0)
852    {
853    };
854    void setCollator(UCollator *c, Line *l, int32_t nl)
855    {
856        coll = c;
857        lines = l;
858        noLines = nl;
859    }
860    virtual void run() {
861        //sleep(10000);
862        int32_t line = 0;
863
864        uint8_t sk1[1024], sk2[1024];
865        uint8_t *oldSk = NULL, *newSk = sk1;
866        int32_t resLen = 0, oldLen = 0;
867        int32_t i = 0;
868
869        for(i = 0; i < noLines; i++) {
870            resLen = ucol_getSortKey(coll, lines[i].buff, lines[i].buflen, newSk, 1024);
871
872            int32_t res = 0, cmpres = 0, cmpres2 = 0;
873
874            if(oldSk != NULL) {
875                res = strcmp((char *)oldSk, (char *)newSk);
876                cmpres = ucol_strcoll(coll, lines[i-1].buff, lines[i-1].buflen, lines[i].buff, lines[i].buflen);
877                cmpres2 = ucol_strcoll(coll, lines[i].buff, lines[i].buflen, lines[i-1].buff, lines[i-1].buflen);
878                //cmpres = res;
879                //cmpres2 = -cmpres;
880
881                if(cmpres != -cmpres2) {
882                    error("Compare result not symmetrical on line "+ line);
883                    break;
884                }
885
886                if(((res&0x80000000) != (cmpres&0x80000000)) || (res == 0 && cmpres != 0) || (res != 0 && cmpres == 0)) {
887                    error(UnicodeString("Difference between ucol_strcoll and sortkey compare on line ")+ UnicodeString(line));
888                    break;
889                }
890
891                if(res > 0) {
892                    error(UnicodeString("Line %i is not greater or equal than previous line ")+ UnicodeString(i));
893                    break;
894                } else if(res == 0) { /* equal */
895                    res = u_strcmpCodePointOrder(lines[i-1].buff, lines[i].buff);
896                    if (res == 0) {
897                        error(UnicodeString("Probable error in test file on line %i (comparing identical strings)")+ UnicodeString(i));
898                        break;
899                    }
900                    /*
901                     * UCA 6.0 test files can have lines that compare == if they are
902                     * different strings but canonically equivalent.
903                    else if (res > 0) {
904                        error(UnicodeString("Sortkeys are identical, but code point compare gives >0 on line ")+ UnicodeString(i));
905                        break;
906                    }
907                     */
908                }
909            }
910
911            oldSk = newSk;
912            oldLen = resLen;
913
914            newSk = (newSk == sk1)?sk2:sk1;
915        }
916    }
917};
918
919void MultithreadTest::TestCollators()
920{
921
922    UErrorCode status = U_ZERO_ERROR;
923    FILE *testFile = NULL;
924    char testDataPath[1024];
925    strcpy(testDataPath, IntlTest::getSourceTestData(status));
926    if (U_FAILURE(status)) {
927        errln("ERROR: could not open test data %s", u_errorName(status));
928        return;
929    }
930    strcat(testDataPath, "CollationTest_");
931
932    const char* type = "NON_IGNORABLE";
933
934    const char *ext = ".txt";
935    if(testFile) {
936        fclose(testFile);
937    }
938    char buffer[1024];
939    strcpy(buffer, testDataPath);
940    strcat(buffer, type);
941    size_t bufLen = strlen(buffer);
942
943    // we try to open 3 files:
944    // path/CollationTest_type.txt
945    // path/CollationTest_type_SHORT.txt
946    // path/CollationTest_type_STUB.txt
947    // we are going to test with the first one that we manage to open.
948
949    strcpy(buffer+bufLen, ext);
950
951    testFile = fopen(buffer, "rb");
952
953    if(testFile == 0) {
954        strcpy(buffer+bufLen, "_SHORT");
955        strcat(buffer, ext);
956        testFile = fopen(buffer, "rb");
957
958        if(testFile == 0) {
959            strcpy(buffer+bufLen, "_STUB");
960            strcat(buffer, ext);
961            testFile = fopen(buffer, "rb");
962
963            if (testFile == 0) {
964                *(buffer+bufLen) = 0;
965                dataerrln("could not open any of the conformance test files, tried opening base %s", buffer);
966                return;
967            } else {
968                infoln(
969                    "INFO: Working with the stub file.\n"
970                    "If you need the full conformance test, please\n"
971                    "download the appropriate data files from:\n"
972                    "http://source.icu-project.org/repos/icu/tools/trunk/unicodetools/com/ibm/text/data/");
973            }
974        }
975    }
976
977    Line *lines = new Line[200000];
978    memset(lines, 0, sizeof(Line)*200000);
979    int32_t lineNum = 0;
980
981    UChar bufferU[1024];
982    int32_t buflen = 0;
983    uint32_t first = 0;
984    uint32_t offset = 0;
985
986    while (fgets(buffer, 1024, testFile) != NULL) {
987        offset = 0;
988        if(*buffer == 0 || strlen(buffer) < 3 || buffer[0] == '#') {
989            continue;
990        }
991        offset = u_parseString(buffer, bufferU, 1024, &first, &status);
992        buflen = offset;
993        bufferU[offset++] = 0;
994        lines[lineNum].buflen = buflen;
995        //lines[lineNum].buff = new UChar[buflen+1];
996        u_memcpy(lines[lineNum].buff, bufferU, buflen);
997        lineNum++;
998    }
999    fclose(testFile);
1000    if(U_FAILURE(status)) {
1001      dataerrln("Couldn't read the test file!");
1002      return;
1003    }
1004
1005    UCollator *coll = ucol_open("root", &status);
1006    if(U_FAILURE(status)) {
1007        errcheckln(status, "Couldn't open UCA collator");
1008        return;
1009    }
1010    ucol_setAttribute(coll, UCOL_NORMALIZATION_MODE, UCOL_ON, &status);
1011    ucol_setAttribute(coll, UCOL_CASE_FIRST, UCOL_OFF, &status);
1012    ucol_setAttribute(coll, UCOL_CASE_LEVEL, UCOL_OFF, &status);
1013    ucol_setAttribute(coll, UCOL_STRENGTH, UCOL_TERTIARY, &status);
1014    ucol_setAttribute(coll, UCOL_ALTERNATE_HANDLING, UCOL_NON_IGNORABLE, &status);
1015
1016    int32_t noSpawned = 0;
1017    int32_t spawnResult = 0;
1018    LocalArray<CollatorThreadTest> tests(new CollatorThreadTest[kCollatorThreadThreads]);
1019
1020    logln(UnicodeString("Spawning: ") + kCollatorThreadThreads + " threads * " + kFormatThreadIterations + " iterations each.");
1021    int32_t j = 0;
1022    for(j = 0; j < kCollatorThreadThreads; j++) {
1023        //logln("Setting collator %i", j);
1024        tests[j].setCollator(coll, lines, lineNum);
1025    }
1026    for(j = 0; j < kCollatorThreadThreads; j++) {
1027        log("%i ", j);
1028        spawnResult = tests[j].start();
1029        if(spawnResult != 0) {
1030            infoln("THREAD INFO: Couldn't spawn more than %i threads", noSpawned);
1031            break;
1032        }
1033        noSpawned++;
1034    }
1035    logln("Spawned all");
1036    if (noSpawned == 0) {
1037        errln("No threads could be spawned.");
1038        return;
1039    }
1040
1041    for(int32_t patience = kCollatorThreadPatience;patience > 0; patience --)
1042    {
1043        logln("Waiting...");
1044
1045        int32_t i;
1046        int32_t terrs = 0;
1047        int32_t completed =0;
1048
1049        for(i=0;i<kCollatorThreadThreads;i++)
1050        {
1051            if (tests[i].isRunning() == FALSE)
1052            {
1053                completed++;
1054
1055                //logln(UnicodeString("Test #") + i + " is complete.. ");
1056
1057                UnicodeString theErr;
1058                if(tests[i].getError(theErr))
1059                {
1060                    terrs++;
1061                    errln(UnicodeString("#") + i + ": " + theErr);
1062                }
1063                // print out the error, too, if any.
1064            }
1065        }
1066        logln("Completed %i tests", completed);
1067
1068        if(completed == noSpawned)
1069        {
1070            logln("Done! All %i tests are finished", noSpawned);
1071
1072            if(terrs)
1073            {
1074                errln("There were errors.");
1075                SimpleThread::errorFunc();
1076            }
1077            ucol_close(coll);
1078            //for(i = 0; i < lineNum; i++) {
1079            //delete[] lines[i].buff;
1080            //}
1081            delete[] lines;
1082
1083            return;
1084        }
1085
1086        SimpleThread::sleep(900);
1087    }
1088    errln("patience exceeded. ");
1089    SimpleThread::errorFunc();
1090    ucol_close(coll);
1091}
1092
1093#endif /* #if !UCONFIG_NO_COLLATION */
1094
1095
1096
1097
1098//-------------------------------------------------------------------------------------------
1099//
1100//   StringThreadTest2
1101//
1102//-------------------------------------------------------------------------------------------
1103
1104const int kStringThreadIterations = 2500;// # of iterations per thread
1105const int kStringThreadThreads    = 10;  // # of threads to spawn
1106const int kStringThreadPatience   = 120; // time in seconds to wait for all threads
1107
1108
1109class StringThreadTest2 : public ThreadWithStatus
1110{
1111public:
1112    int                 fNum;
1113    int                 fTraceInfo;
1114    const UnicodeString *fSharedString;
1115
1116    StringThreadTest2(const UnicodeString *sharedString, int num) // constructor is NOT multithread safe.
1117        : ThreadWithStatus(),
1118        fNum(num),
1119        fTraceInfo(0),
1120        fSharedString(sharedString)
1121    {
1122    };
1123
1124
1125    virtual void run()
1126    {
1127        fTraceInfo    = 1;
1128        int loopCount = 0;
1129
1130        for (loopCount = 0; loopCount < kStringThreadIterations; loopCount++) {
1131            if (*fSharedString != "This is the original test string.") {
1132                error("Original string is corrupt.");
1133                break;
1134            }
1135            UnicodeString s1 = *fSharedString;
1136            s1 += "cat this";
1137            UnicodeString s2(s1);
1138            UnicodeString s3 = *fSharedString;
1139            s2 = s3;
1140            s3.truncate(12);
1141            s2.truncate(0);
1142        }
1143
1144        //  while (fNum == 4) {SimpleThread::sleep(10000);}   // Force a failure by preventing thread from finishing
1145        fTraceInfo = 2;
1146    }
1147
1148};
1149
1150// ** The actual test function.
1151
1152void MultithreadTest::TestString()
1153{
1154    int     patience;
1155    int     terrs = 0;
1156    int     j;
1157
1158    UnicodeString *testString = new UnicodeString("This is the original test string.");
1159
1160    // Not using LocalArray<StringThreadTest2> tests[kStringThreadThreads];
1161    // because we don't always want to delete them.
1162    // See the comments below the cleanupAndReturn label.
1163    StringThreadTest2  *tests[kStringThreadThreads];
1164    for(j = 0; j < kStringThreadThreads; j++) {
1165        tests[j] = new StringThreadTest2(testString, j);
1166    }
1167
1168    logln(UnicodeString("Spawning: ") + kStringThreadThreads + " threads * " + kStringThreadIterations + " iterations each.");
1169    for(j = 0; j < kStringThreadThreads; j++) {
1170        int32_t threadStatus = tests[j]->start();
1171        if (threadStatus != 0) {
1172            errln("System Error %d starting thread number %d.", threadStatus, j);
1173            SimpleThread::errorFunc();
1174            goto cleanupAndReturn;
1175        }
1176    }
1177
1178    for(patience = kStringThreadPatience;patience > 0; patience --)
1179    {
1180        logln("Waiting...");
1181
1182        int32_t i;
1183        terrs = 0;
1184        int32_t completed =0;
1185
1186        for(i=0;i<kStringThreadThreads;i++) {
1187            if (tests[i]->isRunning() == FALSE)
1188            {
1189                completed++;
1190
1191                logln(UnicodeString("Test #") + i + " is complete.. ");
1192
1193                UnicodeString theErr;
1194                if(tests[i]->getError(theErr))
1195                {
1196                    terrs++;
1197                    errln(UnicodeString("#") + i + ": " + theErr);
1198                }
1199                // print out the error, too, if any.
1200            }
1201        }
1202
1203        if(completed == kStringThreadThreads)
1204        {
1205            logln("Done!");
1206            if(terrs) {
1207                errln("There were errors.");
1208            }
1209            break;
1210        }
1211
1212        SimpleThread::sleep(900);
1213    }
1214
1215    if (patience <= 0) {
1216        errln("patience exceeded. ");
1217        // while (TRUE) {SimpleThread::sleep(10000);}   // TODO:   for debugging.  Sleep forever on failure.
1218        terrs++;
1219    }
1220
1221    if (terrs > 0) {
1222        SimpleThread::errorFunc();
1223    }
1224
1225cleanupAndReturn:
1226    if (terrs == 0) {
1227        /*
1228        Don't clean up if there are errors. This prevents crashes if the
1229        threads are still running and using this data. This will only happen
1230        if there is an error with the test, ICU, or the machine is too slow.
1231        It's better to leak than crash.
1232        */
1233        for(j = 0; j < kStringThreadThreads; j++) {
1234            delete tests[j];
1235        }
1236        delete testString;
1237    }
1238}
1239
1240#endif // ICU_USE_THREADS
1241