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