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