1 /******************************************************************** 2 * COPYRIGHT: 3 * Copyright (c) 1999-2013, International Business Machines Corporation and 4 * others. All Rights Reserved. 5 ********************************************************************/ 6 7 #if defined(hpux) 8 # ifndef _INCLUDE_POSIX_SOURCE 9 # define _INCLUDE_POSIX_SOURCE 10 # endif 11 #endif 12 13 #include "simplethread.h" 14 15 #include "unicode/utypes.h" 16 #include "unicode/ustring.h" 17 #include "umutex.h" 18 #include "cmemory.h" 19 #include "cstring.h" 20 #include "uparse.h" 21 #include "unicode/localpointer.h" 22 #include "unicode/resbund.h" 23 #include "unicode/udata.h" 24 #include "unicode/uloc.h" 25 #include "unicode/locid.h" 26 #include "putilimp.h" 27 #include "intltest.h" 28 #include "tsmthred.h" 29 #include "unicode/ushape.h" 30 31 32 #if U_PLATFORM_USES_ONLY_WIN32_API 33 /* Prefer native Windows APIs even if POSIX is implemented (i.e., on Cygwin). */ 34 # undef POSIX 35 #elif U_PLATFORM_IMPLEMENTS_POSIX 36 # define POSIX 37 #else 38 # undef POSIX 39 #endif 40 41 42 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0])) 43 /* Needed by z/OS to get usleep */ 44 #if U_PLATFORM == U_PF_OS390 45 #define __DOT1 1 46 #define __UU 47 #ifndef _XPG4_2 48 #define _XPG4_2 49 #endif 50 #include <unistd.h> 51 #endif 52 #if defined(POSIX) 53 54 #define HAVE_IMP 55 56 #if (ICU_USE_THREADS == 1) 57 #include <pthread.h> 58 #endif 59 60 #if defined(__hpux) && defined(HPUX_CMA) 61 # if defined(read) // read being defined as cma_read causes trouble with iostream::read 62 # undef read 63 # endif 64 #endif 65 66 /* Define __EXTENSIONS__ for Solaris and old friends in strict mode. */ 67 #ifndef __EXTENSIONS__ 68 #define __EXTENSIONS__ 69 #endif 70 71 #if U_PLATFORM == U_PF_OS390 72 #include <sys/types.h> 73 #endif 74 75 #if U_PLATFORM != U_PF_OS390 76 #include <signal.h> 77 #endif 78 79 /* Define _XPG4_2 for Solaris and friends. */ 80 #ifndef _XPG4_2 81 #define _XPG4_2 82 #endif 83 84 /* Define __USE_XOPEN_EXTENDED for Linux and glibc. */ 85 #ifndef __USE_XOPEN_EXTENDED 86 #define __USE_XOPEN_EXTENDED 87 #endif 88 89 /* Define _INCLUDE_XOPEN_SOURCE_EXTENDED for HP/UX (11?). */ 90 #ifndef _INCLUDE_XOPEN_SOURCE_EXTENDED 91 #define _INCLUDE_XOPEN_SOURCE_EXTENDED 92 #endif 93 94 #include <unistd.h> 95 96 #endif 97 /* HPUX */ 98 #ifdef sleep 99 #undef sleep 100 #endif 101 102 #define TSMTHREAD_FAIL(msg) errln("%s at file %s, line %d", msg, __FILE__, __LINE__) 103 #define TSMTHREAD_ASSERT(expr) {if (!(expr)) {TSMTHREAD_FAIL("Fail");}} 104 105 MultithreadTest::MultithreadTest() 106 { 107 } 108 109 MultithreadTest::~MultithreadTest() 110 { 111 } 112 113 114 115 #if (ICU_USE_THREADS==0) 116 void MultithreadTest::runIndexedTest( int32_t index, UBool exec, 117 const char* &name, char* /*par*/ ) { 118 if (exec) logln("TestSuite MultithreadTest: "); 119 120 if(index == 0) 121 name = "NO_THREADED_TESTS"; 122 else 123 name = ""; 124 125 if(exec) { logln("MultithreadTest - test DISABLED. ICU_USE_THREADS set to 0, check your configuration if this is a problem.."); 126 } 127 } 128 #else 129 130 #include <stdio.h> 131 #include <string.h> 132 #include <ctype.h> // tolower, toupper 133 134 #include "unicode/putil.h" 135 136 // for mthreadtest 137 #include "unicode/numfmt.h" 138 #include "unicode/choicfmt.h" 139 #include "unicode/msgfmt.h" 140 #include "unicode/locid.h" 141 #include "unicode/coll.h" 142 #include "unicode/calendar.h" 143 #include "ucaconf.h" 144 145 void SimpleThread::errorFunc() { 146 // *(char *)0 = 3; // Force entry into a debugger via a crash; 147 } 148 149 void MultithreadTest::runIndexedTest( int32_t index, UBool exec, 150 const char* &name, char* /*par*/ ) { 151 if (exec) 152 logln("TestSuite MultithreadTest: "); 153 switch (index) { 154 case 0: 155 name = "TestThreads"; 156 if (exec) 157 TestThreads(); 158 break; 159 160 case 1: 161 name = "TestMutex"; 162 if (exec) 163 TestMutex(); 164 break; 165 166 case 2: 167 name = "TestThreadedIntl"; 168 #if !UCONFIG_NO_FORMATTING 169 if (exec) { 170 TestThreadedIntl(); 171 } 172 #endif 173 break; 174 175 case 3: 176 name = "TestCollators"; 177 #if !UCONFIG_NO_COLLATION 178 if (exec) { 179 TestCollators(); 180 } 181 #endif /* #if !UCONFIG_NO_COLLATION */ 182 break; 183 184 case 4: 185 name = "TestString"; 186 if (exec) { 187 TestString(); 188 } 189 break; 190 191 case 5: 192 name = "TestArabicShapingThreads"; 193 if (exec) { 194 TestArabicShapingThreads(); 195 } 196 break; 197 198 199 default: 200 name = ""; 201 break; //needed to end loop 202 } 203 } 204 205 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 //----------------------------------------------------------------------------------- 215 #define THREADTEST_NRTHREADS 8 216 #define ARABICSHAPE_THREADTEST 30 217 218 class TestThreadsThread : public SimpleThread 219 { 220 public: 221 TestThreadsThread(char* whatToChange) { fWhatToChange = whatToChange; } 222 virtual void run() { SimpleThread::sleep(1000); 223 Mutex m; 224 *fWhatToChange = '*'; 225 } 226 private: 227 char *fWhatToChange; 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 //----------------------------------------------------------------------------------- 239 class TestArabicShapeThreads : public SimpleThread 240 { 241 public: 242 TestArabicShapeThreads(char* whatToChange) { fWhatToChange = whatToChange;} 243 virtual void run() { 244 if(doTailTest()==TRUE) 245 *fWhatToChange = '*'; 246 } 247 private: 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 297 }; 298 299 void MultithreadTest::TestThreads() 300 { 301 char threadTestChars[THREADTEST_NRTHREADS + 1]; 302 SimpleThread *threads[THREADTEST_NRTHREADS]; 303 int32_t numThreadsStarted = 0; 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 } 319 else { 320 numThreadsStarted++; 321 } 322 SimpleThread::sleep(100); 323 logln(" Subthread started."); 324 } 325 326 logln("Waiting for threads to be set.."); 327 if (numThreadsStarted == 0) { 328 errln("No threads could be started for testing!"); 329 return; 330 } 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 369 void 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 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 //---------------------------------------------------------------------- 449 static UMutex gTestMutexA = U_MUTEX_INITIALIZER; 450 static UMutex gTestMutexB = U_MUTEX_INITIALIZER; 451 452 static int gThreadsStarted = 0; 453 static int gThreadsInMiddle = 0; 454 static int gThreadsDone = 0; 455 456 static const int TESTMUTEX_THREAD_COUNT = 4; 457 458 static 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 } 466 467 class TestMutexThread : public SimpleThread 468 { 469 public: 470 virtual void run() 471 { 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); 483 } 484 }; 485 486 void MultithreadTest::TestMutex() 487 { 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 } 506 } 507 if (numThreadsStarted == 0) { 508 errln("No threads could be started for testing!"); 509 return; 510 } 511 512 int patience = 0; 513 while (safeIncr(gThreadsStarted, 0) != TESTMUTEX_THREAD_COUNT) { 514 if (patience++ > 24) { 515 TSMTHREAD_FAIL("Patience Exceeded"); 516 return; 517 } 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); 550 } 551 552 // All threads made it by both mutexes. 553 554 for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) { 555 delete threads[i]; 556 } 557 558 } 559 560 561 //------------------------------------------------------------------------------------------- 562 // 563 // class ThreadWithStatus - a thread that we can check the status and error condition of 564 // 565 //------------------------------------------------------------------------------------------- 566 class ThreadWithStatus : public SimpleThread 567 { 568 public: 569 UBool getError() { return (fErrors > 0); } 570 UBool getError(UnicodeString& fillinError) { fillinError = fErrorString; return (fErrors > 0); } 571 virtual ~ThreadWithStatus(){} 572 protected: 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."); } 579 private: 580 int32_t fErrors; 581 UnicodeString fErrorString; 582 }; 583 584 585 586 //------------------------------------------------------------------------------------------- 587 // 588 // TestMultithreadedIntl. Test ICU Formatting n a multi-threaded environment 589 // 590 //------------------------------------------------------------------------------------------- 591 592 593 // * Show exactly where the string's differences lie. 594 UnicodeString 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 622 623 624 //------------------------------------------------------------------------------------------- 625 // 626 // FormatThreadTest - a thread that tests performing a number of numberformats. 627 // 628 //------------------------------------------------------------------------------------------- 629 630 const int kFormatThreadIterations = 100; // # of iterations per thread 631 const int kFormatThreadThreads = 10; // # of threads to spawn 632 const int kFormatThreadPatience = 60; // time in seconds to wait for all threads 633 634 #if !UCONFIG_NO_FORMATTING 635 636 637 638 struct FormatThreadTestData 639 { 640 double number; 641 UnicodeString string; 642 FormatThreadTestData(double a, const UnicodeString& b) : number(a),string(b) {} 643 } ; 644 645 646 // "Someone from {2} is receiving a #{0} error - {1}. Their telephone call is costing {3 number,currency}." 647 648 static void 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 655 UnicodeString errString1(u_errorName(inStatus0)); 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; 680 } 681 682 /** 683 * Class for thread-safe (theoretically) format. 684 * 685 * 686 * Its constructor, destructor, and init/fini are NOT thread safe. 687 */ 688 class ThreadSafeFormat { 689 public: 690 /* give a unique offset to each thread */ 691 ThreadSafeFormat(); 692 UBool doStuff(int32_t offset, UnicodeString &appendErr, UErrorCode &status); 693 private: 694 LocalPointer<NumberFormat> fFormat; // formtter - default constructed currency 695 Formattable fYDDThing; // Formattable currency - YDD 696 Formattable fBBDThing; // Formattable currency - BBD 697 698 // statics 699 private: 700 static LocalPointer<NumberFormat> gFormat; 701 static NumberFormat *createFormat(UErrorCode &status); 702 static Formattable gYDDThing, gBBDThing; 703 public: 704 static void init(UErrorCode &status); // avoid static init. 705 static void fini(UErrorCode &status); // avoid static fini 706 }; 707 708 LocalPointer<NumberFormat> ThreadSafeFormat::gFormat; 709 Formattable ThreadSafeFormat::gYDDThing; 710 Formattable ThreadSafeFormat::gBBDThing; 711 UnicodeString gYDDStr, gBBDStr; 712 NumberFormat *ThreadSafeFormat::createFormat(UErrorCode &status) { 713 LocalPointer<NumberFormat> fmt(NumberFormat::createCurrencyInstance(Locale::getUS(), status)); 714 return fmt.orphan(); 715 } 716 717 718 static const UChar kYDD[] = { 0x59, 0x44, 0x44, 0x00 }; 719 static const UChar kBBD[] = { 0x42, 0x42, 0x44, 0x00 }; 720 static const UChar kUSD[] = { 0x55, 0x53, 0x44, 0x00 }; 721 722 void ThreadSafeFormat::init(UErrorCode &status) { 723 gFormat.adoptInstead(createFormat(status)); 724 gYDDThing.adoptObject(new CurrencyAmount(123.456, kYDD, status)); 725 gBBDThing.adoptObject(new CurrencyAmount(987.654, kBBD, status)); 726 if (U_FAILURE(status)) { 727 return; 728 } 729 gFormat->format(gYDDThing, gYDDStr, NULL, status); 730 gFormat->format(gBBDThing, gBBDStr, NULL, status); 731 } 732 733 void ThreadSafeFormat::fini(UErrorCode &/*status*/) { 734 gFormat.adoptInstead(NULL); 735 } 736 737 ThreadSafeFormat::ThreadSafeFormat() { 738 } 739 740 UBool ThreadSafeFormat::doStuff(int32_t offset, UnicodeString &appendErr, UErrorCode &status) { 741 UBool okay = TRUE; 742 if(fFormat.isNull()) { 743 fFormat.adoptInstead(createFormat(status)); 744 } 745 746 if(u_strcmp(fFormat->getCurrency(), kUSD)) { 747 appendErr.append("fFormat currency != ") 748 .append(kUSD) 749 .append(", =") 750 .append(fFormat->getCurrency()) 751 .append("! "); 752 okay = FALSE; 753 } 754 755 if(u_strcmp(gFormat->getCurrency(), kUSD)) { 756 appendErr.append("gFormat currency != ") 757 .append(kUSD) 758 .append(", =") 759 .append(gFormat->getCurrency()) 760 .append("! "); 761 okay = FALSE; 762 } 763 UnicodeString str; 764 const UnicodeString *o=NULL; 765 Formattable f; 766 const NumberFormat *nf = NULL; // only operate on it as const. 767 switch(offset%4) { 768 case 0: f = gYDDThing; o = &gYDDStr; nf = gFormat.getAlias(); break; 769 case 1: f = gBBDThing; o = &gBBDStr; nf = gFormat.getAlias(); break; 770 case 2: f = gYDDThing; o = &gYDDStr; nf = fFormat.getAlias(); break; 771 case 3: f = gBBDThing; o = &gBBDStr; nf = fFormat.getAlias(); break; 772 } 773 nf->format(f, str, NULL, status); 774 775 if(*o != str) { 776 appendErr.append(showDifference(*o, str)); 777 okay = FALSE; 778 } 779 return okay; 780 } 781 782 UBool U_CALLCONV isAcceptable(void *, const char *, const char *, const UDataInfo *) { 783 return TRUE; 784 } 785 786 //static UMTX debugMutex = NULL; 787 //static UMTX gDebugMutex; 788 789 790 class FormatThreadTest : public ThreadWithStatus 791 { 792 public: 793 int fNum; 794 int fTraceInfo; 795 796 ThreadSafeFormat fTSF; 797 798 FormatThreadTest() // constructor is NOT multithread safe. 799 : ThreadWithStatus(), 800 fNum(0), 801 fTraceInfo(0), 802 fOffset(0) 803 // the locale to use 804 { 805 static int32_t fgOffset = 0; 806 fgOffset += 3; 807 fOffset = fgOffset; 808 } 809 810 811 virtual void run() 812 { 813 fTraceInfo = 1; 814 LocalPointer<NumberFormat> percentFormatter; 815 UErrorCode status = U_ZERO_ERROR; 816 817 #if 0 818 // debugging code, 819 for (int i=0; i<4000; i++) { 820 status = U_ZERO_ERROR; 821 UDataMemory *data1 = udata_openChoice(0, "res", "en_US", isAcceptable, 0, &status); 822 UDataMemory *data2 = udata_openChoice(0, "res", "fr", isAcceptable, 0, &status); 823 udata_close(data1); 824 udata_close(data2); 825 if (U_FAILURE(status)) { 826 error("udata_openChoice failed.\n"); 827 break; 828 } 829 } 830 return; 831 #endif 832 833 #if 0 834 // debugging code, 835 int m; 836 for (m=0; m<4000; m++) { 837 status = U_ZERO_ERROR; 838 UResourceBundle *res = NULL; 839 const char *localeName = NULL; 840 841 Locale loc = Locale::getEnglish(); 842 843 localeName = loc.getName(); 844 // localeName = "en"; 845 846 // ResourceBundle bund = ResourceBundle(0, loc, status); 847 //umtx_lock(&gDebugMutex); 848 res = ures_open(NULL, localeName, &status); 849 //umtx_unlock(&gDebugMutex); 850 851 //umtx_lock(&gDebugMutex); 852 ures_close(res); 853 //umtx_unlock(&gDebugMutex); 854 855 if (U_FAILURE(status)) { 856 error("Resource bundle construction failed.\n"); 857 break; 858 } 859 } 860 return; 861 #endif 862 863 // Keep this data here to avoid static initialization. 864 FormatThreadTestData kNumberFormatTestData[] = 865 { 866 FormatThreadTestData((double)5.0, UnicodeString("5", "")), 867 FormatThreadTestData( 6.0, UnicodeString("6", "")), 868 FormatThreadTestData( 20.0, UnicodeString("20", "")), 869 FormatThreadTestData( 8.0, UnicodeString("8", "")), 870 FormatThreadTestData( 8.3, UnicodeString("8.3", "")), 871 FormatThreadTestData( 12345, UnicodeString("12,345", "")), 872 FormatThreadTestData( 81890.23, UnicodeString("81,890.23", "")), 873 }; 874 int32_t kNumberFormatTestDataLength = (int32_t)(sizeof(kNumberFormatTestData) / 875 sizeof(kNumberFormatTestData[0])); 876 877 // Keep this data here to avoid static initialization. 878 FormatThreadTestData kPercentFormatTestData[] = 879 { 880 FormatThreadTestData((double)5.0, CharsToUnicodeString("500\\u00a0%")), 881 FormatThreadTestData( 1.0, CharsToUnicodeString("100\\u00a0%")), 882 FormatThreadTestData( 0.26, CharsToUnicodeString("26\\u00a0%")), 883 FormatThreadTestData( 884 16384.99, CharsToUnicodeString("1\\u00a0638\\u00a0499\\u00a0%")), // U+00a0 = NBSP 885 FormatThreadTestData( 886 81890.23, CharsToUnicodeString("8\\u00a0189\\u00a0023\\u00a0%")), 887 }; 888 int32_t kPercentFormatTestDataLength = 889 (int32_t)(sizeof(kPercentFormatTestData) / sizeof(kPercentFormatTestData[0])); 890 int32_t iteration; 891 892 status = U_ZERO_ERROR; 893 LocalPointer<NumberFormat> formatter(NumberFormat::createInstance(Locale::getEnglish(),status)); 894 if(U_FAILURE(status)) { 895 error("Error on NumberFormat::createInstance()."); 896 goto cleanupAndReturn; 897 } 898 899 percentFormatter.adoptInstead(NumberFormat::createPercentInstance(Locale::getFrench(),status)); 900 if(U_FAILURE(status)) { 901 error("Error on NumberFormat::createPercentInstance()."); 902 goto cleanupAndReturn; 903 } 904 905 for(iteration = 0;!getError() && iteration<kFormatThreadIterations;iteration++) 906 { 907 908 int32_t whichLine = (iteration + fOffset)%kNumberFormatTestDataLength; 909 910 UnicodeString output; 911 912 formatter->format(kNumberFormatTestData[whichLine].number, output); 913 914 if(0 != output.compare(kNumberFormatTestData[whichLine].string)) { 915 error("format().. expected " + kNumberFormatTestData[whichLine].string 916 + " got " + output); 917 goto cleanupAndReturn; 918 } 919 920 // Now check percent. 921 output.remove(); 922 whichLine = (iteration + fOffset)%kPercentFormatTestDataLength; 923 924 percentFormatter->format(kPercentFormatTestData[whichLine].number, output); 925 if(0 != output.compare(kPercentFormatTestData[whichLine].string)) 926 { 927 error("percent format().. \n" + 928 showDifference(kPercentFormatTestData[whichLine].string,output)); 929 goto cleanupAndReturn; 930 } 931 932 // Test message error 933 const int kNumberOfMessageTests = 3; 934 UErrorCode statusToCheck; 935 UnicodeString patternToCheck; 936 Locale messageLocale; 937 Locale countryToCheck; 938 double currencyToCheck; 939 940 UnicodeString expected; 941 942 // load the cases. 943 switch((iteration+fOffset) % kNumberOfMessageTests) 944 { 945 default: 946 case 0: 947 statusToCheck= U_FILE_ACCESS_ERROR; 948 patternToCheck= "0:Someone from {2} is receiving a #{0}" 949 " error - {1}. Their telephone call is costing " 950 "{3,number,currency}."; // number,currency 951 messageLocale= Locale("en","US"); 952 countryToCheck= Locale("","HR"); 953 currencyToCheck= 8192.77; 954 expected= "0:Someone from Croatia is receiving a #4 error - " 955 "U_FILE_ACCESS_ERROR. Their telephone call is costing $8,192.77."; 956 break; 957 case 1: 958 statusToCheck= U_INDEX_OUTOFBOUNDS_ERROR; 959 patternToCheck= "1:A customer in {2} is receiving a #{0} error - {1}. Their telephone call is costing {3,number,currency}."; // number,currency 960 messageLocale= Locale("de","DE@currency=DEM"); 961 countryToCheck= Locale("","BF"); 962 currencyToCheck= 2.32; 963 expected= CharsToUnicodeString( 964 "1:A customer in Burkina Faso is receiving a #8 error - U_INDEX_OUTOFBOUNDS_ERROR. Their telephone call is costing 2,32\\u00A0DEM."); 965 break; 966 case 2: 967 statusToCheck= U_MEMORY_ALLOCATION_ERROR; 968 patternToCheck= "2:user in {2} is receiving a #{0} error - {1}. " 969 "They insist they just spent {3,number,currency} " 970 "on memory."; // number,currency 971 messageLocale= Locale("de","AT@currency=ATS"); // Austrian German 972 countryToCheck= Locale("","US"); // hmm 973 currencyToCheck= 40193.12; 974 expected= CharsToUnicodeString( 975 "2:user in Vereinigte Staaten is receiving a #7 error" 976 " - U_MEMORY_ALLOCATION_ERROR. They insist they just spent" 977 " \\u00f6S\\u00A040.193,12 on memory."); 978 break; 979 } 980 981 UnicodeString result; 982 UErrorCode status = U_ZERO_ERROR; 983 formatErrorMessage(status,patternToCheck,messageLocale,statusToCheck, 984 countryToCheck,currencyToCheck,result); 985 if(U_FAILURE(status)) 986 { 987 UnicodeString tmp(u_errorName(status)); 988 error("Failure on message format, pattern=" + patternToCheck + 989 ", error = " + tmp); 990 goto cleanupAndReturn; 991 } 992 993 if(result != expected) 994 { 995 error("PatternFormat: \n" + showDifference(expected,result)); 996 goto cleanupAndReturn; 997 } 998 // test the Thread Safe Format 999 UnicodeString appendErr; 1000 if(!fTSF.doStuff(fNum, appendErr, status)) { 1001 error(appendErr); 1002 goto cleanupAndReturn; 1003 } 1004 } /* end of for loop */ 1005 1006 1007 1008 cleanupAndReturn: 1009 // while (fNum == 4) {SimpleThread::sleep(10000);} // Force a failure by preventing thread from finishing 1010 fTraceInfo = 2; 1011 } 1012 1013 private: 1014 int32_t fOffset; // where we are testing from. 1015 }; 1016 1017 // ** The actual test function. 1018 1019 void MultithreadTest::TestThreadedIntl() 1020 { 1021 int i; 1022 UnicodeString theErr; 1023 UBool haveDisplayedInfo[kFormatThreadThreads]; 1024 static const int32_t PATIENCE_SECONDS = 45; 1025 1026 UErrorCode threadSafeErr = U_ZERO_ERROR; 1027 1028 ThreadSafeFormat::init(threadSafeErr); 1029 assertSuccess("initializing ThreadSafeFormat", threadSafeErr, TRUE); 1030 1031 // 1032 // Create and start the test threads 1033 // 1034 logln("Spawning: %d threads * %d iterations each.", 1035 kFormatThreadThreads, kFormatThreadIterations); 1036 LocalArray<FormatThreadTest> tests(new FormatThreadTest[kFormatThreadThreads]); 1037 for(int32_t j = 0; j < kFormatThreadThreads; j++) { 1038 tests[j].fNum = j; 1039 int32_t threadStatus = tests[j].start(); 1040 if (threadStatus != 0) { 1041 errln("System Error %d starting thread number %d.", threadStatus, j); 1042 SimpleThread::errorFunc(); 1043 return; 1044 } 1045 haveDisplayedInfo[j] = FALSE; 1046 } 1047 1048 1049 // Spin, waiting for the test threads to finish. 1050 UBool stillRunning; 1051 UDate startTime, endTime; 1052 startTime = Calendar::getNow(); 1053 double lastComplaint = 0; 1054 do { 1055 /* Spin until the test threads complete. */ 1056 stillRunning = FALSE; 1057 endTime = Calendar::getNow(); 1058 double elapsedSeconds = ((int32_t)(endTime - startTime)/U_MILLIS_PER_SECOND); 1059 if (elapsedSeconds > PATIENCE_SECONDS) { 1060 errln("Patience exceeded. Test is taking too long."); 1061 return; 1062 } else if((elapsedSeconds-lastComplaint) > 2.0) { 1063 infoln("%.1f seconds elapsed (still waiting..)", elapsedSeconds); 1064 lastComplaint = elapsedSeconds; 1065 } 1066 /* 1067 The following sleep must be here because the *BSD operating systems 1068 have a brain dead thread scheduler. They starve the child threads from 1069 CPU time. 1070 */ 1071 SimpleThread::sleep(1); // yield 1072 for(i=0;i<kFormatThreadThreads;i++) { 1073 if (tests[i].isRunning()) { 1074 stillRunning = TRUE; 1075 } else if (haveDisplayedInfo[i] == FALSE) { 1076 logln("Thread # %d is complete..", i); 1077 if(tests[i].getError(theErr)) { 1078 dataerrln(UnicodeString("#") + i + ": " + theErr); 1079 SimpleThread::errorFunc(); 1080 } 1081 haveDisplayedInfo[i] = TRUE; 1082 } 1083 } 1084 } while (stillRunning); 1085 1086 // 1087 // All threads have finished. 1088 // 1089 ThreadSafeFormat::fini(threadSafeErr); 1090 assertSuccess("finalizing ThreadSafeFormat", threadSafeErr, TRUE); 1091 } 1092 #endif /* #if !UCONFIG_NO_FORMATTING */ 1093 1094 1095 1096 1097 1098 //------------------------------------------------------------------------------------------- 1099 // 1100 // Collation threading test 1101 // 1102 //------------------------------------------------------------------------------------------- 1103 #if !UCONFIG_NO_COLLATION 1104 1105 #define kCollatorThreadThreads 10 // # of threads to spawn 1106 #define kCollatorThreadPatience kCollatorThreadThreads*30 1107 1108 struct Line { 1109 UChar buff[25]; 1110 int32_t buflen; 1111 } ; 1112 1113 static UBool 1114 skipLineBecauseOfBug(const UChar *s, int32_t length) { 1115 // TODO: Fix ICU ticket #8052 1116 if(length >= 3 && 1117 (s[0] == 0xfb2 || s[0] == 0xfb3) && 1118 s[1] == 0x334 && 1119 (s[2] == 0xf73 || s[2] == 0xf75 || s[2] == 0xf81)) { 1120 return TRUE; 1121 } 1122 return FALSE; 1123 } 1124 1125 static UCollationResult 1126 normalizeResult(int32_t result) { 1127 return result<0 ? UCOL_LESS : result==0 ? UCOL_EQUAL : UCOL_GREATER; 1128 } 1129 1130 class CollatorThreadTest : public ThreadWithStatus 1131 { 1132 private: 1133 const Collator *coll; 1134 const Line *lines; 1135 int32_t noLines; 1136 UBool isAtLeastUCA62; 1137 public: 1138 CollatorThreadTest() : ThreadWithStatus(), 1139 coll(NULL), 1140 lines(NULL), 1141 noLines(0), 1142 isAtLeastUCA62(TRUE) 1143 { 1144 }; 1145 void setCollator(Collator *c, Line *l, int32_t nl, UBool atLeastUCA62) 1146 { 1147 coll = c; 1148 lines = l; 1149 noLines = nl; 1150 isAtLeastUCA62 = atLeastUCA62; 1151 } 1152 virtual void run() { 1153 uint8_t sk1[1024], sk2[1024]; 1154 uint8_t *oldSk = NULL, *newSk = sk1; 1155 int32_t oldLen = 0; 1156 int32_t prev = 0; 1157 int32_t i = 0; 1158 1159 for(i = 0; i < noLines; i++) { 1160 if(lines[i].buflen == 0) { continue; } 1161 1162 if(skipLineBecauseOfBug(lines[i].buff, lines[i].buflen)) { continue; } 1163 1164 int32_t resLen = coll->getSortKey(lines[i].buff, lines[i].buflen, newSk, 1024); 1165 1166 if(oldSk != NULL) { 1167 int32_t skres = strcmp((char *)oldSk, (char *)newSk); 1168 int32_t cmpres = coll->compare(lines[prev].buff, lines[prev].buflen, lines[i].buff, lines[i].buflen); 1169 int32_t cmpres2 = coll->compare(lines[i].buff, lines[i].buflen, lines[prev].buff, lines[prev].buflen); 1170 1171 if(cmpres != -cmpres2) { 1172 error(UnicodeString("Compare result not symmetrical on line ") + (i + 1)); 1173 break; 1174 } 1175 1176 if(cmpres != normalizeResult(skres)) { 1177 error(UnicodeString("Difference between coll->compare and sortkey compare on line ") + (i + 1)); 1178 break; 1179 } 1180 1181 int32_t res = cmpres; 1182 if(res == 0 && !isAtLeastUCA62) { 1183 // Up to UCA 6.1, the collation test files use a custom tie-breaker, 1184 // comparing the raw input strings. 1185 res = u_strcmpCodePointOrder(lines[prev].buff, lines[i].buff); 1186 // Starting with UCA 6.2, the collation test files use the standard UCA tie-breaker, 1187 // comparing the NFD versions of the input strings, 1188 // which we do via setting strength=identical. 1189 } 1190 if(res > 0) { 1191 error(UnicodeString("Line is not greater or equal than previous line, for line ") + (i + 1)); 1192 break; 1193 } 1194 } 1195 1196 oldSk = newSk; 1197 oldLen = resLen; 1198 (void)oldLen; // Suppress set but not used warning. 1199 prev = i; 1200 1201 newSk = (newSk == sk1)?sk2:sk1; 1202 } 1203 } 1204 }; 1205 1206 void MultithreadTest::TestCollators() 1207 { 1208 1209 UErrorCode status = U_ZERO_ERROR; 1210 FILE *testFile = NULL; 1211 char testDataPath[1024]; 1212 strcpy(testDataPath, IntlTest::getSourceTestData(status)); 1213 if (U_FAILURE(status)) { 1214 errln("ERROR: could not open test data %s", u_errorName(status)); 1215 return; 1216 } 1217 strcat(testDataPath, "CollationTest_"); 1218 1219 const char* type = "NON_IGNORABLE"; 1220 1221 const char *ext = ".txt"; 1222 if(testFile) { 1223 fclose(testFile); 1224 } 1225 char buffer[1024]; 1226 strcpy(buffer, testDataPath); 1227 strcat(buffer, type); 1228 size_t bufLen = strlen(buffer); 1229 1230 // we try to open 3 files: 1231 // path/CollationTest_type.txt 1232 // path/CollationTest_type_SHORT.txt 1233 // path/CollationTest_type_STUB.txt 1234 // we are going to test with the first one that we manage to open. 1235 1236 strcpy(buffer+bufLen, ext); 1237 1238 testFile = fopen(buffer, "rb"); 1239 1240 if(testFile == 0) { 1241 strcpy(buffer+bufLen, "_SHORT"); 1242 strcat(buffer, ext); 1243 testFile = fopen(buffer, "rb"); 1244 1245 if(testFile == 0) { 1246 strcpy(buffer+bufLen, "_STUB"); 1247 strcat(buffer, ext); 1248 testFile = fopen(buffer, "rb"); 1249 1250 if (testFile == 0) { 1251 *(buffer+bufLen) = 0; 1252 dataerrln("could not open any of the conformance test files, tried opening base %s", buffer); 1253 return; 1254 } else { 1255 infoln( 1256 "INFO: Working with the stub file.\n" 1257 "If you need the full conformance test, please\n" 1258 "download the appropriate data files from:\n" 1259 "http://source.icu-project.org/repos/icu/tools/trunk/unicodetools/com/ibm/text/data/"); 1260 } 1261 } 1262 } 1263 1264 LocalArray<Line> lines(new Line[200000]); 1265 memset(lines.getAlias(), 0, sizeof(Line)*200000); 1266 int32_t lineNum = 0; 1267 1268 UChar bufferU[1024]; 1269 uint32_t first = 0; 1270 1271 while (fgets(buffer, 1024, testFile) != NULL) { 1272 if(*buffer == 0 || buffer[0] == '#') { 1273 // Store empty and comment lines so that errors are reported 1274 // for the real test file lines. 1275 lines[lineNum].buflen = 0; 1276 lines[lineNum].buff[0] = 0; 1277 } else { 1278 int32_t buflen = u_parseString(buffer, bufferU, 1024, &first, &status); 1279 lines[lineNum].buflen = buflen; 1280 u_memcpy(lines[lineNum].buff, bufferU, buflen); 1281 lines[lineNum].buff[buflen] = 0; 1282 } 1283 lineNum++; 1284 } 1285 fclose(testFile); 1286 if(U_FAILURE(status)) { 1287 dataerrln("Couldn't read the test file!"); 1288 return; 1289 } 1290 1291 UVersionInfo uniVersion; 1292 static const UVersionInfo v62 = { 6, 2, 0, 0 }; 1293 u_getUnicodeVersion(uniVersion); 1294 UBool isAtLeastUCA62 = uprv_memcmp(uniVersion, v62, 4) >= 0; 1295 1296 LocalPointer<Collator> coll(Collator::createInstance(Locale::getRoot(), status)); 1297 if(U_FAILURE(status)) { 1298 errcheckln(status, "Couldn't open UCA collator"); 1299 return; 1300 } 1301 coll->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status); 1302 coll->setAttribute(UCOL_CASE_FIRST, UCOL_OFF, status); 1303 coll->setAttribute(UCOL_CASE_LEVEL, UCOL_OFF, status); 1304 coll->setAttribute(UCOL_STRENGTH, isAtLeastUCA62 ? UCOL_IDENTICAL : UCOL_TERTIARY, status); 1305 coll->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_NON_IGNORABLE, status); 1306 1307 int32_t noSpawned = 0; 1308 int32_t spawnResult = 0; 1309 LocalArray<CollatorThreadTest> tests(new CollatorThreadTest[kCollatorThreadThreads]); 1310 1311 logln(UnicodeString("Spawning: ") + kCollatorThreadThreads + " threads * " + kFormatThreadIterations + " iterations each."); 1312 int32_t j = 0; 1313 for(j = 0; j < kCollatorThreadThreads; j++) { 1314 //logln("Setting collator %i", j); 1315 tests[j].setCollator(coll.getAlias(), lines.getAlias(), lineNum, isAtLeastUCA62); 1316 } 1317 for(j = 0; j < kCollatorThreadThreads; j++) { 1318 log("%i ", j); 1319 spawnResult = tests[j].start(); 1320 if(spawnResult != 0) { 1321 infoln("THREAD INFO: Couldn't spawn more than %i threads", noSpawned); 1322 break; 1323 } 1324 noSpawned++; 1325 } 1326 logln("Spawned all"); 1327 if (noSpawned == 0) { 1328 errln("No threads could be spawned."); 1329 return; 1330 } 1331 1332 for(int32_t patience = kCollatorThreadPatience;patience > 0; patience --) 1333 { 1334 logln("Waiting..."); 1335 1336 int32_t i; 1337 int32_t terrs = 0; 1338 int32_t completed =0; 1339 1340 for(i=0;i<kCollatorThreadThreads;i++) 1341 { 1342 if (tests[i].isRunning() == FALSE) 1343 { 1344 completed++; 1345 1346 //logln(UnicodeString("Test #") + i + " is complete.. "); 1347 1348 UnicodeString theErr; 1349 if(tests[i].getError(theErr)) 1350 { 1351 terrs++; 1352 errln(UnicodeString("#") + i + ": " + theErr); 1353 } 1354 // print out the error, too, if any. 1355 } 1356 } 1357 logln("Completed %i tests", completed); 1358 1359 if(completed == noSpawned) 1360 { 1361 logln("Done! All %i tests are finished", noSpawned); 1362 1363 if(terrs) 1364 { 1365 errln("There were errors."); 1366 SimpleThread::errorFunc(); 1367 } 1368 return; 1369 } 1370 1371 SimpleThread::sleep(900); 1372 } 1373 errln("patience exceeded. "); 1374 SimpleThread::errorFunc(); 1375 } 1376 1377 #endif /* #if !UCONFIG_NO_COLLATION */ 1378 1379 1380 1381 1382 //------------------------------------------------------------------------------------------- 1383 // 1384 // StringThreadTest2 1385 // 1386 //------------------------------------------------------------------------------------------- 1387 1388 const int kStringThreadIterations = 2500;// # of iterations per thread 1389 const int kStringThreadThreads = 10; // # of threads to spawn 1390 const int kStringThreadPatience = 120; // time in seconds to wait for all threads 1391 1392 1393 class StringThreadTest2 : public ThreadWithStatus 1394 { 1395 public: 1396 int fNum; 1397 int fTraceInfo; 1398 const UnicodeString *fSharedString; 1399 1400 StringThreadTest2(const UnicodeString *sharedString, int num) // constructor is NOT multithread safe. 1401 : ThreadWithStatus(), 1402 fNum(num), 1403 fTraceInfo(0), 1404 fSharedString(sharedString) 1405 { 1406 }; 1407 1408 1409 virtual void run() 1410 { 1411 fTraceInfo = 1; 1412 int loopCount = 0; 1413 1414 for (loopCount = 0; loopCount < kStringThreadIterations; loopCount++) { 1415 if (*fSharedString != "This is the original test string.") { 1416 error("Original string is corrupt."); 1417 break; 1418 } 1419 UnicodeString s1 = *fSharedString; 1420 s1 += "cat this"; 1421 UnicodeString s2(s1); 1422 UnicodeString s3 = *fSharedString; 1423 s2 = s3; 1424 s3.truncate(12); 1425 s2.truncate(0); 1426 } 1427 1428 // while (fNum == 4) {SimpleThread::sleep(10000);} // Force a failure by preventing thread from finishing 1429 fTraceInfo = 2; 1430 } 1431 1432 }; 1433 1434 // ** The actual test function. 1435 1436 void MultithreadTest::TestString() 1437 { 1438 int patience; 1439 int terrs = 0; 1440 int j; 1441 1442 UnicodeString *testString = new UnicodeString("This is the original test string."); 1443 1444 // Not using LocalArray<StringThreadTest2> tests[kStringThreadThreads]; 1445 // because we don't always want to delete them. 1446 // See the comments below the cleanupAndReturn label. 1447 StringThreadTest2 *tests[kStringThreadThreads]; 1448 for(j = 0; j < kStringThreadThreads; j++) { 1449 tests[j] = new StringThreadTest2(testString, j); 1450 } 1451 1452 logln(UnicodeString("Spawning: ") + kStringThreadThreads + " threads * " + kStringThreadIterations + " iterations each."); 1453 for(j = 0; j < kStringThreadThreads; j++) { 1454 int32_t threadStatus = tests[j]->start(); 1455 if (threadStatus != 0) { 1456 errln("System Error %d starting thread number %d.", threadStatus, j); 1457 SimpleThread::errorFunc(); 1458 goto cleanupAndReturn; 1459 } 1460 } 1461 1462 for(patience = kStringThreadPatience;patience > 0; patience --) 1463 { 1464 logln("Waiting..."); 1465 1466 int32_t i; 1467 terrs = 0; 1468 int32_t completed =0; 1469 1470 for(i=0;i<kStringThreadThreads;i++) { 1471 if (tests[i]->isRunning() == FALSE) 1472 { 1473 completed++; 1474 1475 logln(UnicodeString("Test #") + i + " is complete.. "); 1476 1477 UnicodeString theErr; 1478 if(tests[i]->getError(theErr)) 1479 { 1480 terrs++; 1481 errln(UnicodeString("#") + i + ": " + theErr); 1482 } 1483 // print out the error, too, if any. 1484 } 1485 } 1486 1487 if(completed == kStringThreadThreads) 1488 { 1489 logln("Done!"); 1490 if(terrs) { 1491 errln("There were errors."); 1492 } 1493 break; 1494 } 1495 1496 SimpleThread::sleep(900); 1497 } 1498 1499 if (patience <= 0) { 1500 errln("patience exceeded. "); 1501 // while (TRUE) {SimpleThread::sleep(10000);} // TODO: for debugging. Sleep forever on failure. 1502 terrs++; 1503 } 1504 1505 if (terrs > 0) { 1506 SimpleThread::errorFunc(); 1507 } 1508 1509 cleanupAndReturn: 1510 if (terrs == 0) { 1511 /* 1512 Don't clean up if there are errors. This prevents crashes if the 1513 threads are still running and using this data. This will only happen 1514 if there is an error with the test, ICU, or the machine is too slow. 1515 It's better to leak than crash. 1516 */ 1517 for(j = 0; j < kStringThreadThreads; j++) { 1518 delete tests[j]; 1519 } 1520 delete testString; 1521 } 1522 } 1523 1524 #endif // ICU_USE_THREADS 1525