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