1 /******************************************************************** 2 * COPYRIGHT: 3 * Copyright (c) 1999-2014, 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 #include "unicode/translit.h" 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 case 6: 199 name = "TestAnyTranslit"; 200 if (exec) { 201 TestAnyTranslit(); 202 } 203 break; 204 205 default: 206 name = ""; 207 break; //needed to end loop 208 } 209 } 210 211 212 //----------------------------------------------------------------------------------- 213 // 214 // TestThreads -- see if threads really work at all. 215 // 216 // Set up N threads pointing at N chars. When they are started, they will 217 // each sleep 1 second and then set their chars. At the end we make sure they 218 // are all set. 219 // 220 //----------------------------------------------------------------------------------- 221 #define THREADTEST_NRTHREADS 8 222 #define ARABICSHAPE_THREADTEST 30 223 224 class TestThreadsThread : public SimpleThread 225 { 226 public: 227 TestThreadsThread(char* whatToChange) { fWhatToChange = whatToChange; } 228 virtual void run() { SimpleThread::sleep(1000); 229 Mutex m; 230 *fWhatToChange = '*'; 231 } 232 private: 233 char *fWhatToChange; 234 }; 235 //----------------------------------------------------------------------------------- 236 // 237 // TestArabicShapeThreads -- see if calls to u_shapeArabic in many threads works successfully 238 // 239 // Set up N threads pointing at N chars. When they are started, they will make calls to doTailTest which tests 240 // u_shapeArabic, if the calls are successful it will the set * chars. 241 // At the end we make sure all threads managed to run u_shapeArabic successfully. 242 // This is a unit test for ticket 9473 243 // 244 //----------------------------------------------------------------------------------- 245 class TestArabicShapeThreads : public SimpleThread 246 { 247 public: 248 TestArabicShapeThreads(char* whatToChange) { fWhatToChange = whatToChange;} 249 virtual void run() { 250 if(doTailTest()==TRUE) 251 *fWhatToChange = '*'; 252 } 253 private: 254 char *fWhatToChange; 255 256 UBool doTailTest(void) { 257 static const UChar src[] = { 0x0020, 0x0633, 0 }; 258 static const UChar dst_old[] = { 0xFEB1, 0x200B,0 }; 259 static const UChar dst_new[] = { 0xFEB1, 0xFE73,0 }; 260 UChar dst[3] = { 0x0000, 0x0000,0 }; 261 int32_t length; 262 UErrorCode status; 263 IntlTest inteltst = IntlTest(); 264 265 status = U_ZERO_ERROR; 266 length = u_shapeArabic(src, -1, dst, LENGTHOF(dst), 267 U_SHAPE_LETTERS_SHAPE|U_SHAPE_SEEN_TWOCELL_NEAR, &status); 268 if(U_FAILURE(status)) { 269 inteltst.errln("Fail: status %s\n", u_errorName(status)); 270 return FALSE; 271 } else if(length!=2) { 272 inteltst.errln("Fail: len %d expected 3\n", length); 273 return FALSE; 274 } else if(u_strncmp(dst,dst_old,LENGTHOF(dst))) { 275 inteltst.errln("Fail: got U+%04X U+%04X expected U+%04X U+%04X\n", 276 dst[0],dst[1],dst_old[0],dst_old[1]); 277 return FALSE; 278 } 279 280 281 //"Trying new tail 282 status = U_ZERO_ERROR; 283 length = u_shapeArabic(src, -1, dst, LENGTHOF(dst), 284 U_SHAPE_LETTERS_SHAPE|U_SHAPE_SEEN_TWOCELL_NEAR|U_SHAPE_TAIL_NEW_UNICODE, &status); 285 if(U_FAILURE(status)) { 286 inteltst.errln("Fail: status %s\n", u_errorName(status)); 287 return FALSE; 288 } else if(length!=2) { 289 inteltst.errln("Fail: len %d expected 3\n", length); 290 return FALSE; 291 } else if(u_strncmp(dst,dst_new,LENGTHOF(dst))) { 292 inteltst.errln("Fail: got U+%04X U+%04X expected U+%04X U+%04X\n", 293 dst[0],dst[1],dst_new[0],dst_new[1]); 294 return FALSE; 295 } 296 297 298 return TRUE; 299 300 } 301 302 303 }; 304 305 void MultithreadTest::TestThreads() 306 { 307 char threadTestChars[THREADTEST_NRTHREADS + 1]; 308 SimpleThread *threads[THREADTEST_NRTHREADS]; 309 int32_t numThreadsStarted = 0; 310 311 int32_t i; 312 for(i=0;i<THREADTEST_NRTHREADS;i++) 313 { 314 threadTestChars[i] = ' '; 315 threads[i] = new TestThreadsThread(&threadTestChars[i]); 316 } 317 threadTestChars[THREADTEST_NRTHREADS] = '\0'; 318 319 logln("->" + UnicodeString(threadTestChars) + "<- Firing off threads.. "); 320 for(i=0;i<THREADTEST_NRTHREADS;i++) 321 { 322 if (threads[i]->start() != 0) { 323 errln("Error starting thread %d", i); 324 } 325 else { 326 numThreadsStarted++; 327 } 328 SimpleThread::sleep(100); 329 logln(" Subthread started."); 330 } 331 332 logln("Waiting for threads to be set.."); 333 if (numThreadsStarted == 0) { 334 errln("No threads could be started for testing!"); 335 return; 336 } 337 338 int32_t patience = 40; // seconds to wait 339 340 while(patience--) 341 { 342 int32_t count = 0; 343 umtx_lock(NULL); 344 for(i=0;i<THREADTEST_NRTHREADS;i++) 345 { 346 if(threadTestChars[i] == '*') 347 { 348 count++; 349 } 350 } 351 umtx_unlock(NULL); 352 353 if(count == THREADTEST_NRTHREADS) 354 { 355 logln("->" + UnicodeString(threadTestChars) + "<- Got all threads! cya"); 356 for(i=0;i<THREADTEST_NRTHREADS;i++) 357 { 358 delete threads[i]; 359 } 360 return; 361 } 362 363 logln("->" + UnicodeString(threadTestChars) + "<- Waiting.."); 364 SimpleThread::sleep(500); 365 } 366 367 errln("->" + UnicodeString(threadTestChars) + "<- PATIENCE EXCEEDED!! Still missing some."); 368 for(i=0;i<THREADTEST_NRTHREADS;i++) 369 { 370 delete threads[i]; 371 } 372 } 373 374 375 void MultithreadTest::TestArabicShapingThreads() 376 { 377 char threadTestChars[ARABICSHAPE_THREADTEST + 1]; 378 SimpleThread *threads[ARABICSHAPE_THREADTEST]; 379 int32_t numThreadsStarted = 0; 380 381 int32_t i; 382 383 for(i=0;i<ARABICSHAPE_THREADTEST;i++) 384 { 385 threadTestChars[i] = ' '; 386 threads[i] = new TestArabicShapeThreads(&threadTestChars[i]); 387 } 388 threadTestChars[ARABICSHAPE_THREADTEST] = '\0'; 389 390 logln("-> do TestArabicShapingThreads <- Firing off threads.. "); 391 for(i=0;i<ARABICSHAPE_THREADTEST;i++) 392 { 393 if (threads[i]->start() != 0) { 394 errln("Error starting thread %d", i); 395 } 396 else { 397 numThreadsStarted++; 398 } 399 //SimpleThread::sleep(100); 400 logln(" Subthread started."); 401 } 402 403 logln("Waiting for threads to be set.."); 404 if (numThreadsStarted == 0) { 405 errln("No threads could be started for testing!"); 406 return; 407 } 408 409 int32_t patience = 100; // seconds to wait 410 411 while(patience--) 412 { 413 int32_t count = 0; 414 umtx_lock(NULL); 415 for(i=0;i<ARABICSHAPE_THREADTEST;i++) 416 { 417 if(threadTestChars[i] == '*') 418 { 419 count++; 420 } 421 } 422 umtx_unlock(NULL); 423 424 if(count == ARABICSHAPE_THREADTEST) 425 { 426 logln("->TestArabicShapingThreads <- Got all threads! cya"); 427 for(i=0;i<ARABICSHAPE_THREADTEST;i++) 428 { 429 delete threads[i]; 430 } 431 return; 432 } 433 434 logln("-> TestArabicShapingThreads <- Waiting.."); 435 SimpleThread::sleep(500); 436 } 437 438 errln("-> TestArabicShapingThreads <- PATIENCE EXCEEDED!! Still missing some."); 439 for(i=0;i<ARABICSHAPE_THREADTEST;i++) 440 { 441 delete threads[i]; 442 } 443 444 } 445 446 447 //----------------------------------------------------------------------- 448 // 449 // TestMutex - a simple (non-stress) test to verify that ICU mutexes 450 // are actually mutexing. Does not test the use of 451 // mutexes within ICU services, but rather that the 452 // platform's mutex support is at least superficially there. 453 // 454 //---------------------------------------------------------------------- 455 static UMutex gTestMutexA = U_MUTEX_INITIALIZER; 456 static UMutex gTestMutexB = U_MUTEX_INITIALIZER; 457 458 static int gThreadsStarted = 0; 459 static int gThreadsInMiddle = 0; 460 static int gThreadsDone = 0; 461 462 static const int TESTMUTEX_THREAD_COUNT = 4; 463 464 static int safeIncr(int &var, int amt) { 465 // Thread safe (using global mutex) increment of a variable. 466 // Return the updated value. 467 // Can also be used as a safe load of a variable by incrementing it by 0. 468 Mutex m; 469 var += amt; 470 return var; 471 } 472 473 class TestMutexThread : public SimpleThread 474 { 475 public: 476 virtual void run() 477 { 478 // This is the code that each of the spawned threads runs. 479 // All of the spawned threads bunch up together at each of the two mutexes 480 // because the main holds the mutexes until they do. 481 // 482 safeIncr(gThreadsStarted, 1); 483 umtx_lock(&gTestMutexA); 484 umtx_unlock(&gTestMutexA); 485 safeIncr(gThreadsInMiddle, 1); 486 umtx_lock(&gTestMutexB); 487 umtx_unlock(&gTestMutexB); 488 safeIncr(gThreadsDone, 1); 489 } 490 }; 491 492 void MultithreadTest::TestMutex() 493 { 494 // Start up the test threads. They should all pile up waiting on 495 // gTestMutexA, which we (the main thread) hold until the test threads 496 // all get there. 497 gThreadsStarted = 0; 498 gThreadsInMiddle = 0; 499 gThreadsDone = 0; 500 umtx_lock(&gTestMutexA); 501 TestMutexThread *threads[TESTMUTEX_THREAD_COUNT]; 502 int i; 503 int32_t numThreadsStarted = 0; 504 for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) { 505 threads[i] = new TestMutexThread; 506 if (threads[i]->start() != 0) { 507 errln("Error starting thread %d", i); 508 } 509 else { 510 numThreadsStarted++; 511 } 512 } 513 if (numThreadsStarted == 0) { 514 errln("No threads could be started for testing!"); 515 return; 516 } 517 518 int patience = 0; 519 while (safeIncr(gThreadsStarted, 0) != TESTMUTEX_THREAD_COUNT) { 520 if (patience++ > 24) { 521 TSMTHREAD_FAIL("Patience Exceeded"); 522 return; 523 } 524 SimpleThread::sleep(500); 525 } 526 // None of the test threads should have advanced past the first mutex. 527 TSMTHREAD_ASSERT(gThreadsInMiddle==0); 528 TSMTHREAD_ASSERT(gThreadsDone==0); 529 530 // All of the test threads have made it to the first mutex. 531 // We (the main thread) now let them advance to the second mutex, 532 // where they should all pile up again. 533 umtx_lock(&gTestMutexB); 534 umtx_unlock(&gTestMutexA); 535 536 patience = 0; 537 while (safeIncr(gThreadsInMiddle, 0) != TESTMUTEX_THREAD_COUNT) { 538 if (patience++ > 24) { 539 TSMTHREAD_FAIL("Patience Exceeded"); 540 return; 541 } 542 SimpleThread::sleep(500); 543 } 544 TSMTHREAD_ASSERT(gThreadsDone==0); 545 546 // All test threads made it to the second mutex. 547 // Now let them proceed from there. They will all terminate. 548 umtx_unlock(&gTestMutexB); 549 patience = 0; 550 while (safeIncr(gThreadsDone, 0) != TESTMUTEX_THREAD_COUNT) { 551 if (patience++ > 24) { 552 TSMTHREAD_FAIL("Patience Exceeded"); 553 return; 554 } 555 SimpleThread::sleep(500); 556 } 557 558 // All threads made it by both mutexes. 559 560 for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) { 561 delete threads[i]; 562 } 563 564 } 565 566 567 //------------------------------------------------------------------------------------------- 568 // 569 // class ThreadWithStatus - a thread that we can check the status and error condition of 570 // 571 //------------------------------------------------------------------------------------------- 572 class ThreadWithStatus : public SimpleThread 573 { 574 public: 575 UBool getError() { return (fErrors > 0); } 576 UBool getError(UnicodeString& fillinError) { fillinError = fErrorString; return (fErrors > 0); } 577 virtual ~ThreadWithStatus(){} 578 protected: 579 ThreadWithStatus() : fErrors(0) {} 580 void error(const UnicodeString &error) { 581 fErrors++; fErrorString = error; 582 SimpleThread::errorFunc(); 583 } 584 void error() { error("An error occured."); } 585 private: 586 int32_t fErrors; 587 UnicodeString fErrorString; 588 }; 589 590 591 592 //------------------------------------------------------------------------------------------- 593 // 594 // TestMultithreadedIntl. Test ICU Formatting n a multi-threaded environment 595 // 596 //------------------------------------------------------------------------------------------- 597 598 599 // * Show exactly where the string's differences lie. 600 UnicodeString showDifference(const UnicodeString& expected, const UnicodeString& result) 601 { 602 UnicodeString res; 603 res = expected + "<Expected\n"; 604 if(expected.length() != result.length()) 605 res += " [ Different lengths ] \n"; 606 else 607 { 608 for(int32_t i=0;i<expected.length();i++) 609 { 610 if(expected[i] == result[i]) 611 { 612 res += " "; 613 } 614 else 615 { 616 res += "|"; 617 } 618 } 619 res += "<Differences"; 620 res += "\n"; 621 } 622 res += result + "<Result\n"; 623 624 return res; 625 } 626 627 628 629 630 //------------------------------------------------------------------------------------------- 631 // 632 // FormatThreadTest - a thread that tests performing a number of numberformats. 633 // 634 //------------------------------------------------------------------------------------------- 635 636 const int kFormatThreadIterations = 100; // # of iterations per thread 637 const int kFormatThreadThreads = 10; // # of threads to spawn 638 639 #if !UCONFIG_NO_FORMATTING 640 641 642 643 struct FormatThreadTestData 644 { 645 double number; 646 UnicodeString string; 647 FormatThreadTestData(double a, const UnicodeString& b) : number(a),string(b) {} 648 } ; 649 650 651 // "Someone from {2} is receiving a #{0} error - {1}. Their telephone call is costing {3 number,currency}." 652 653 static void formatErrorMessage(UErrorCode &realStatus, const UnicodeString& pattern, const Locale& theLocale, 654 UErrorCode inStatus0, /* statusString 1 */ const Locale &inCountry2, double currency3, // these numbers are the message arguments. 655 UnicodeString &result) 656 { 657 if(U_FAILURE(realStatus)) 658 return; // you messed up 659 660 UnicodeString errString1(u_errorName(inStatus0)); 661 662 UnicodeString countryName2; 663 inCountry2.getDisplayCountry(theLocale,countryName2); 664 665 Formattable myArgs[] = { 666 Formattable((int32_t)inStatus0), // inStatus0 {0} 667 Formattable(errString1), // statusString1 {1} 668 Formattable(countryName2), // inCountry2 {2} 669 Formattable(currency3)// currency3 {3,number,currency} 670 }; 671 672 MessageFormat *fmt = new MessageFormat("MessageFormat's API is broken!!!!!!!!!!!",realStatus); 673 fmt->setLocale(theLocale); 674 fmt->applyPattern(pattern, realStatus); 675 676 if (U_FAILURE(realStatus)) { 677 delete fmt; 678 return; 679 } 680 681 FieldPosition ignore = 0; 682 fmt->format(myArgs,4,result,ignore,realStatus); 683 684 delete fmt; 685 } 686 687 /** 688 * Class for thread-safe (theoretically) format. 689 * 690 * 691 * Its constructor, destructor, and init/fini are NOT thread safe. 692 */ 693 class ThreadSafeFormat { 694 public: 695 /* give a unique offset to each thread */ 696 ThreadSafeFormat(); 697 UBool doStuff(int32_t offset, UnicodeString &appendErr, UErrorCode &status); 698 private: 699 LocalPointer<NumberFormat> fFormat; // formtter - default constructed currency 700 Formattable fYDDThing; // Formattable currency - YDD 701 Formattable fBBDThing; // Formattable currency - BBD 702 703 // statics 704 private: 705 static LocalPointer<NumberFormat> gFormat; 706 static NumberFormat *createFormat(UErrorCode &status); 707 static Formattable gYDDThing, gBBDThing; 708 public: 709 static void init(UErrorCode &status); // avoid static init. 710 static void fini(UErrorCode &status); // avoid static fini 711 }; 712 713 LocalPointer<NumberFormat> ThreadSafeFormat::gFormat; 714 Formattable ThreadSafeFormat::gYDDThing; 715 Formattable ThreadSafeFormat::gBBDThing; 716 UnicodeString gYDDStr, gBBDStr; 717 NumberFormat *ThreadSafeFormat::createFormat(UErrorCode &status) { 718 LocalPointer<NumberFormat> fmt(NumberFormat::createCurrencyInstance(Locale::getUS(), status)); 719 return fmt.orphan(); 720 } 721 722 723 static const UChar kYDD[] = { 0x59, 0x44, 0x44, 0x00 }; 724 static const UChar kBBD[] = { 0x42, 0x42, 0x44, 0x00 }; 725 static const UChar kUSD[] = { 0x55, 0x53, 0x44, 0x00 }; 726 727 void ThreadSafeFormat::init(UErrorCode &status) { 728 gFormat.adoptInstead(createFormat(status)); 729 gYDDThing.adoptObject(new CurrencyAmount(123.456, kYDD, status)); 730 gBBDThing.adoptObject(new CurrencyAmount(987.654, kBBD, status)); 731 if (U_FAILURE(status)) { 732 return; 733 } 734 gFormat->format(gYDDThing, gYDDStr, NULL, status); 735 gFormat->format(gBBDThing, gBBDStr, NULL, status); 736 } 737 738 void ThreadSafeFormat::fini(UErrorCode &/*status*/) { 739 gFormat.adoptInstead(NULL); 740 } 741 742 ThreadSafeFormat::ThreadSafeFormat() { 743 } 744 745 UBool ThreadSafeFormat::doStuff(int32_t offset, UnicodeString &appendErr, UErrorCode &status) { 746 UBool okay = TRUE; 747 if(fFormat.isNull()) { 748 fFormat.adoptInstead(createFormat(status)); 749 } 750 751 if(u_strcmp(fFormat->getCurrency(), kUSD)) { 752 appendErr.append("fFormat currency != ") 753 .append(kUSD) 754 .append(", =") 755 .append(fFormat->getCurrency()) 756 .append("! "); 757 okay = FALSE; 758 } 759 760 if(u_strcmp(gFormat->getCurrency(), kUSD)) { 761 appendErr.append("gFormat currency != ") 762 .append(kUSD) 763 .append(", =") 764 .append(gFormat->getCurrency()) 765 .append("! "); 766 okay = FALSE; 767 } 768 UnicodeString str; 769 const UnicodeString *o=NULL; 770 Formattable f; 771 const NumberFormat *nf = NULL; // only operate on it as const. 772 switch(offset%4) { 773 case 0: f = gYDDThing; o = &gYDDStr; nf = gFormat.getAlias(); break; 774 case 1: f = gBBDThing; o = &gBBDStr; nf = gFormat.getAlias(); break; 775 case 2: f = gYDDThing; o = &gYDDStr; nf = fFormat.getAlias(); break; 776 case 3: f = gBBDThing; o = &gBBDStr; nf = fFormat.getAlias(); break; 777 } 778 nf->format(f, str, NULL, status); 779 780 if(*o != str) { 781 appendErr.append(showDifference(*o, str)); 782 okay = FALSE; 783 } 784 return okay; 785 } 786 787 UBool U_CALLCONV isAcceptable(void *, const char *, const char *, const UDataInfo *) { 788 return TRUE; 789 } 790 791 //static UMTX debugMutex = NULL; 792 //static UMTX gDebugMutex; 793 794 795 class FormatThreadTest : public ThreadWithStatus 796 { 797 public: 798 int fNum; 799 int fTraceInfo; 800 801 ThreadSafeFormat fTSF; 802 803 FormatThreadTest() // constructor is NOT multithread safe. 804 : ThreadWithStatus(), 805 fNum(0), 806 fTraceInfo(0), 807 fOffset(0) 808 // the locale to use 809 { 810 static int32_t fgOffset = 0; 811 fgOffset += 3; 812 fOffset = fgOffset; 813 } 814 815 816 virtual void run() 817 { 818 fTraceInfo = 1; 819 LocalPointer<NumberFormat> percentFormatter; 820 UErrorCode status = U_ZERO_ERROR; 821 822 #if 0 823 // debugging code, 824 for (int i=0; i<4000; i++) { 825 status = U_ZERO_ERROR; 826 UDataMemory *data1 = udata_openChoice(0, "res", "en_US", isAcceptable, 0, &status); 827 UDataMemory *data2 = udata_openChoice(0, "res", "fr", isAcceptable, 0, &status); 828 udata_close(data1); 829 udata_close(data2); 830 if (U_FAILURE(status)) { 831 error("udata_openChoice failed.\n"); 832 break; 833 } 834 } 835 return; 836 #endif 837 838 #if 0 839 // debugging code, 840 int m; 841 for (m=0; m<4000; m++) { 842 status = U_ZERO_ERROR; 843 UResourceBundle *res = NULL; 844 const char *localeName = NULL; 845 846 Locale loc = Locale::getEnglish(); 847 848 localeName = loc.getName(); 849 // localeName = "en"; 850 851 // ResourceBundle bund = ResourceBundle(0, loc, status); 852 //umtx_lock(&gDebugMutex); 853 res = ures_open(NULL, localeName, &status); 854 //umtx_unlock(&gDebugMutex); 855 856 //umtx_lock(&gDebugMutex); 857 ures_close(res); 858 //umtx_unlock(&gDebugMutex); 859 860 if (U_FAILURE(status)) { 861 error("Resource bundle construction failed.\n"); 862 break; 863 } 864 } 865 return; 866 #endif 867 868 // Keep this data here to avoid static initialization. 869 FormatThreadTestData kNumberFormatTestData[] = 870 { 871 FormatThreadTestData((double)5.0, UnicodeString("5", "")), 872 FormatThreadTestData( 6.0, UnicodeString("6", "")), 873 FormatThreadTestData( 20.0, UnicodeString("20", "")), 874 FormatThreadTestData( 8.0, UnicodeString("8", "")), 875 FormatThreadTestData( 8.3, UnicodeString("8.3", "")), 876 FormatThreadTestData( 12345, UnicodeString("12,345", "")), 877 FormatThreadTestData( 81890.23, UnicodeString("81,890.23", "")), 878 }; 879 int32_t kNumberFormatTestDataLength = (int32_t)(sizeof(kNumberFormatTestData) / 880 sizeof(kNumberFormatTestData[0])); 881 882 // Keep this data here to avoid static initialization. 883 FormatThreadTestData kPercentFormatTestData[] = 884 { 885 FormatThreadTestData((double)5.0, CharsToUnicodeString("500\\u00a0%")), 886 FormatThreadTestData( 1.0, CharsToUnicodeString("100\\u00a0%")), 887 FormatThreadTestData( 0.26, CharsToUnicodeString("26\\u00a0%")), 888 FormatThreadTestData( 889 16384.99, CharsToUnicodeString("1\\u00a0638\\u00a0499\\u00a0%")), // U+00a0 = NBSP 890 FormatThreadTestData( 891 81890.23, CharsToUnicodeString("8\\u00a0189\\u00a0023\\u00a0%")), 892 }; 893 int32_t kPercentFormatTestDataLength = 894 (int32_t)(sizeof(kPercentFormatTestData) / sizeof(kPercentFormatTestData[0])); 895 int32_t iteration; 896 897 status = U_ZERO_ERROR; 898 LocalPointer<NumberFormat> formatter(NumberFormat::createInstance(Locale::getEnglish(),status)); 899 if(U_FAILURE(status)) { 900 error("Error on NumberFormat::createInstance()."); 901 goto cleanupAndReturn; 902 } 903 904 percentFormatter.adoptInstead(NumberFormat::createPercentInstance(Locale::getFrench(),status)); 905 if(U_FAILURE(status)) { 906 error("Error on NumberFormat::createPercentInstance()."); 907 goto cleanupAndReturn; 908 } 909 910 for(iteration = 0;!getError() && iteration<kFormatThreadIterations;iteration++) 911 { 912 913 int32_t whichLine = (iteration + fOffset)%kNumberFormatTestDataLength; 914 915 UnicodeString output; 916 917 formatter->format(kNumberFormatTestData[whichLine].number, output); 918 919 if(0 != output.compare(kNumberFormatTestData[whichLine].string)) { 920 error("format().. expected " + kNumberFormatTestData[whichLine].string 921 + " got " + output); 922 goto cleanupAndReturn; 923 } 924 925 // Now check percent. 926 output.remove(); 927 whichLine = (iteration + fOffset)%kPercentFormatTestDataLength; 928 929 percentFormatter->format(kPercentFormatTestData[whichLine].number, output); 930 if(0 != output.compare(kPercentFormatTestData[whichLine].string)) 931 { 932 error("percent format().. \n" + 933 showDifference(kPercentFormatTestData[whichLine].string,output)); 934 goto cleanupAndReturn; 935 } 936 937 // Test message error 938 const int kNumberOfMessageTests = 3; 939 UErrorCode statusToCheck; 940 UnicodeString patternToCheck; 941 Locale messageLocale; 942 Locale countryToCheck; 943 double currencyToCheck; 944 945 UnicodeString expected; 946 947 // load the cases. 948 switch((iteration+fOffset) % kNumberOfMessageTests) 949 { 950 default: 951 case 0: 952 statusToCheck= U_FILE_ACCESS_ERROR; 953 patternToCheck= "0:Someone from {2} is receiving a #{0}" 954 " error - {1}. Their telephone call is costing " 955 "{3,number,currency}."; // number,currency 956 messageLocale= Locale("en","US"); 957 countryToCheck= Locale("","HR"); 958 currencyToCheck= 8192.77; 959 expected= "0:Someone from Croatia is receiving a #4 error - " 960 "U_FILE_ACCESS_ERROR. Their telephone call is costing $8,192.77."; 961 break; 962 case 1: 963 statusToCheck= U_INDEX_OUTOFBOUNDS_ERROR; 964 patternToCheck= "1:A customer in {2} is receiving a #{0} error - {1}. Their telephone call is costing {3,number,currency}."; // number,currency 965 messageLocale= Locale("de","DE@currency=DEM"); 966 countryToCheck= Locale("","BF"); 967 currencyToCheck= 2.32; 968 expected= CharsToUnicodeString( 969 "1:A customer in Burkina Faso is receiving a #8 error - U_INDEX_OUTOFBOUNDS_ERROR. Their telephone call is costing 2,32\\u00A0DEM."); 970 break; 971 case 2: 972 statusToCheck= U_MEMORY_ALLOCATION_ERROR; 973 patternToCheck= "2:user in {2} is receiving a #{0} error - {1}. " 974 "They insist they just spent {3,number,currency} " 975 "on memory."; // number,currency 976 messageLocale= Locale("de","AT@currency=ATS"); // Austrian German 977 countryToCheck= Locale("","US"); // hmm 978 currencyToCheck= 40193.12; 979 expected= CharsToUnicodeString( 980 "2:user in Vereinigte Staaten is receiving a #7 error" 981 " - U_MEMORY_ALLOCATION_ERROR. They insist they just spent" 982 " \\u00f6S\\u00A040.193,12 on memory."); 983 break; 984 } 985 986 UnicodeString result; 987 UErrorCode status = U_ZERO_ERROR; 988 formatErrorMessage(status,patternToCheck,messageLocale,statusToCheck, 989 countryToCheck,currencyToCheck,result); 990 if(U_FAILURE(status)) 991 { 992 UnicodeString tmp(u_errorName(status)); 993 error("Failure on message format, pattern=" + patternToCheck + 994 ", error = " + tmp); 995 goto cleanupAndReturn; 996 } 997 998 if(result != expected) 999 { 1000 error("PatternFormat: \n" + showDifference(expected,result)); 1001 goto cleanupAndReturn; 1002 } 1003 // test the Thread Safe Format 1004 UnicodeString appendErr; 1005 if(!fTSF.doStuff(fNum, appendErr, status)) { 1006 error(appendErr); 1007 goto cleanupAndReturn; 1008 } 1009 } /* end of for loop */ 1010 1011 1012 1013 cleanupAndReturn: 1014 // while (fNum == 4) {SimpleThread::sleep(10000);} // Force a failure by preventing thread from finishing 1015 fTraceInfo = 2; 1016 } 1017 1018 private: 1019 int32_t fOffset; // where we are testing from. 1020 }; 1021 1022 // ** The actual test function. 1023 1024 void MultithreadTest::TestThreadedIntl() 1025 { 1026 int i; 1027 UnicodeString theErr; 1028 UBool haveDisplayedInfo[kFormatThreadThreads]; 1029 static const int32_t PATIENCE_SECONDS = 45; 1030 1031 UErrorCode threadSafeErr = U_ZERO_ERROR; 1032 1033 ThreadSafeFormat::init(threadSafeErr); 1034 assertSuccess("initializing ThreadSafeFormat", threadSafeErr, TRUE); 1035 1036 // 1037 // Create and start the test threads 1038 // 1039 logln("Spawning: %d threads * %d iterations each.", 1040 kFormatThreadThreads, kFormatThreadIterations); 1041 LocalArray<FormatThreadTest> tests(new FormatThreadTest[kFormatThreadThreads]); 1042 for(int32_t j = 0; j < kFormatThreadThreads; j++) { 1043 tests[j].fNum = j; 1044 int32_t threadStatus = tests[j].start(); 1045 if (threadStatus != 0) { 1046 errln("System Error %d starting thread number %d.", threadStatus, j); 1047 SimpleThread::errorFunc(); 1048 return; 1049 } 1050 haveDisplayedInfo[j] = FALSE; 1051 } 1052 1053 1054 // Spin, waiting for the test threads to finish. 1055 UBool stillRunning; 1056 UDate startTime, endTime; 1057 startTime = Calendar::getNow(); 1058 double lastComplaint = 0; 1059 do { 1060 /* Spin until the test threads complete. */ 1061 stillRunning = FALSE; 1062 endTime = Calendar::getNow(); 1063 double elapsedSeconds = ((int32_t)(endTime - startTime)/U_MILLIS_PER_SECOND); 1064 if (elapsedSeconds > PATIENCE_SECONDS) { 1065 errln("Patience exceeded. Test is taking too long."); 1066 return; 1067 } else if((elapsedSeconds-lastComplaint) > 2.0) { 1068 infoln("%.1f seconds elapsed (still waiting..)", elapsedSeconds); 1069 lastComplaint = elapsedSeconds; 1070 } 1071 /* 1072 The following sleep must be here because the *BSD operating systems 1073 have a brain dead thread scheduler. They starve the child threads from 1074 CPU time. 1075 */ 1076 SimpleThread::sleep(1); // yield 1077 for(i=0;i<kFormatThreadThreads;i++) { 1078 if (tests[i].isRunning()) { 1079 stillRunning = TRUE; 1080 } else if (haveDisplayedInfo[i] == FALSE) { 1081 logln("Thread # %d is complete..", i); 1082 if(tests[i].getError(theErr)) { 1083 dataerrln(UnicodeString("#") + i + ": " + theErr); 1084 SimpleThread::errorFunc(); 1085 } 1086 haveDisplayedInfo[i] = TRUE; 1087 } 1088 } 1089 } while (stillRunning); 1090 1091 // 1092 // All threads have finished. 1093 // 1094 ThreadSafeFormat::fini(threadSafeErr); 1095 assertSuccess("finalizing ThreadSafeFormat", threadSafeErr, TRUE); 1096 } 1097 #endif /* #if !UCONFIG_NO_FORMATTING */ 1098 1099 1100 1101 1102 1103 //------------------------------------------------------------------------------------------- 1104 // 1105 // Collation threading test 1106 // 1107 //------------------------------------------------------------------------------------------- 1108 #if !UCONFIG_NO_COLLATION 1109 1110 #define kCollatorThreadThreads 10 // # of threads to spawn 1111 #define kCollatorThreadPatience kCollatorThreadThreads*30 1112 1113 struct Line { 1114 UChar buff[25]; 1115 int32_t buflen; 1116 } ; 1117 1118 static UBool 1119 skipLineBecauseOfBug(const UChar *s, int32_t length) { 1120 // TODO: Fix ICU ticket #8052 1121 if(length >= 3 && 1122 (s[0] == 0xfb2 || s[0] == 0xfb3) && 1123 s[1] == 0x334 && 1124 (s[2] == 0xf73 || s[2] == 0xf75 || s[2] == 0xf81)) { 1125 return TRUE; 1126 } 1127 return FALSE; 1128 } 1129 1130 static UCollationResult 1131 normalizeResult(int32_t result) { 1132 return result<0 ? UCOL_LESS : result==0 ? UCOL_EQUAL : UCOL_GREATER; 1133 } 1134 1135 class CollatorThreadTest : public ThreadWithStatus 1136 { 1137 private: 1138 const Collator *coll; 1139 const Line *lines; 1140 int32_t noLines; 1141 UBool isAtLeastUCA62; 1142 public: 1143 CollatorThreadTest() : ThreadWithStatus(), 1144 coll(NULL), 1145 lines(NULL), 1146 noLines(0), 1147 isAtLeastUCA62(TRUE) 1148 { 1149 }; 1150 void setCollator(Collator *c, Line *l, int32_t nl, UBool atLeastUCA62) 1151 { 1152 coll = c; 1153 lines = l; 1154 noLines = nl; 1155 isAtLeastUCA62 = atLeastUCA62; 1156 } 1157 virtual void run() { 1158 uint8_t sk1[1024], sk2[1024]; 1159 uint8_t *oldSk = NULL, *newSk = sk1; 1160 int32_t oldLen = 0; 1161 int32_t prev = 0; 1162 int32_t i = 0; 1163 1164 for(i = 0; i < noLines; i++) { 1165 if(lines[i].buflen == 0) { continue; } 1166 1167 if(skipLineBecauseOfBug(lines[i].buff, lines[i].buflen)) { continue; } 1168 1169 int32_t resLen = coll->getSortKey(lines[i].buff, lines[i].buflen, newSk, 1024); 1170 1171 if(oldSk != NULL) { 1172 int32_t skres = strcmp((char *)oldSk, (char *)newSk); 1173 int32_t cmpres = coll->compare(lines[prev].buff, lines[prev].buflen, lines[i].buff, lines[i].buflen); 1174 int32_t cmpres2 = coll->compare(lines[i].buff, lines[i].buflen, lines[prev].buff, lines[prev].buflen); 1175 1176 if(cmpres != -cmpres2) { 1177 error(UnicodeString("Compare result not symmetrical on line ") + (i + 1)); 1178 break; 1179 } 1180 1181 if(cmpres != normalizeResult(skres)) { 1182 error(UnicodeString("Difference between coll->compare and sortkey compare on line ") + (i + 1)); 1183 break; 1184 } 1185 1186 int32_t res = cmpres; 1187 if(res == 0 && !isAtLeastUCA62) { 1188 // Up to UCA 6.1, the collation test files use a custom tie-breaker, 1189 // comparing the raw input strings. 1190 res = u_strcmpCodePointOrder(lines[prev].buff, lines[i].buff); 1191 // Starting with UCA 6.2, the collation test files use the standard UCA tie-breaker, 1192 // comparing the NFD versions of the input strings, 1193 // which we do via setting strength=identical. 1194 } 1195 if(res > 0) { 1196 error(UnicodeString("Line is not greater or equal than previous line, for line ") + (i + 1)); 1197 break; 1198 } 1199 } 1200 1201 oldSk = newSk; 1202 oldLen = resLen; 1203 (void)oldLen; // Suppress set but not used warning. 1204 prev = i; 1205 1206 newSk = (newSk == sk1)?sk2:sk1; 1207 } 1208 } 1209 }; 1210 1211 void MultithreadTest::TestCollators() 1212 { 1213 1214 UErrorCode status = U_ZERO_ERROR; 1215 FILE *testFile = NULL; 1216 char testDataPath[1024]; 1217 strcpy(testDataPath, IntlTest::getSourceTestData(status)); 1218 if (U_FAILURE(status)) { 1219 errln("ERROR: could not open test data %s", u_errorName(status)); 1220 return; 1221 } 1222 strcat(testDataPath, "CollationTest_"); 1223 1224 const char* type = "NON_IGNORABLE"; 1225 1226 const char *ext = ".txt"; 1227 if(testFile) { 1228 fclose(testFile); 1229 } 1230 char buffer[1024]; 1231 strcpy(buffer, testDataPath); 1232 strcat(buffer, type); 1233 size_t bufLen = strlen(buffer); 1234 1235 // we try to open 3 files: 1236 // path/CollationTest_type.txt 1237 // path/CollationTest_type_SHORT.txt 1238 // path/CollationTest_type_STUB.txt 1239 // we are going to test with the first one that we manage to open. 1240 1241 strcpy(buffer+bufLen, ext); 1242 1243 testFile = fopen(buffer, "rb"); 1244 1245 if(testFile == 0) { 1246 strcpy(buffer+bufLen, "_SHORT"); 1247 strcat(buffer, ext); 1248 testFile = fopen(buffer, "rb"); 1249 1250 if(testFile == 0) { 1251 strcpy(buffer+bufLen, "_STUB"); 1252 strcat(buffer, ext); 1253 testFile = fopen(buffer, "rb"); 1254 1255 if (testFile == 0) { 1256 *(buffer+bufLen) = 0; 1257 dataerrln("could not open any of the conformance test files, tried opening base %s", buffer); 1258 return; 1259 } else { 1260 infoln( 1261 "INFO: Working with the stub file.\n" 1262 "If you need the full conformance test, please\n" 1263 "download the appropriate data files from:\n" 1264 "http://source.icu-project.org/repos/icu/tools/trunk/unicodetools/com/ibm/text/data/"); 1265 } 1266 } 1267 } 1268 1269 LocalArray<Line> lines(new Line[200000]); 1270 memset(lines.getAlias(), 0, sizeof(Line)*200000); 1271 int32_t lineNum = 0; 1272 1273 UChar bufferU[1024]; 1274 uint32_t first = 0; 1275 1276 while (fgets(buffer, 1024, testFile) != NULL) { 1277 if(*buffer == 0 || buffer[0] == '#') { 1278 // Store empty and comment lines so that errors are reported 1279 // for the real test file lines. 1280 lines[lineNum].buflen = 0; 1281 lines[lineNum].buff[0] = 0; 1282 } else { 1283 int32_t buflen = u_parseString(buffer, bufferU, 1024, &first, &status); 1284 lines[lineNum].buflen = buflen; 1285 u_memcpy(lines[lineNum].buff, bufferU, buflen); 1286 lines[lineNum].buff[buflen] = 0; 1287 } 1288 lineNum++; 1289 } 1290 fclose(testFile); 1291 if(U_FAILURE(status)) { 1292 dataerrln("Couldn't read the test file!"); 1293 return; 1294 } 1295 1296 UVersionInfo uniVersion; 1297 static const UVersionInfo v62 = { 6, 2, 0, 0 }; 1298 u_getUnicodeVersion(uniVersion); 1299 UBool isAtLeastUCA62 = uprv_memcmp(uniVersion, v62, 4) >= 0; 1300 1301 LocalPointer<Collator> coll(Collator::createInstance(Locale::getRoot(), status)); 1302 if(U_FAILURE(status)) { 1303 errcheckln(status, "Couldn't open UCA collator"); 1304 return; 1305 } 1306 coll->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status); 1307 coll->setAttribute(UCOL_CASE_FIRST, UCOL_OFF, status); 1308 coll->setAttribute(UCOL_CASE_LEVEL, UCOL_OFF, status); 1309 coll->setAttribute(UCOL_STRENGTH, isAtLeastUCA62 ? UCOL_IDENTICAL : UCOL_TERTIARY, status); 1310 coll->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_NON_IGNORABLE, status); 1311 1312 int32_t noSpawned = 0; 1313 int32_t spawnResult = 0; 1314 LocalArray<CollatorThreadTest> tests(new CollatorThreadTest[kCollatorThreadThreads]); 1315 1316 logln(UnicodeString("Spawning: ") + kCollatorThreadThreads + " threads * " + kFormatThreadIterations + " iterations each."); 1317 int32_t j = 0; 1318 for(j = 0; j < kCollatorThreadThreads; j++) { 1319 //logln("Setting collator %i", j); 1320 tests[j].setCollator(coll.getAlias(), lines.getAlias(), lineNum, isAtLeastUCA62); 1321 } 1322 for(j = 0; j < kCollatorThreadThreads; j++) { 1323 log("%i ", j); 1324 spawnResult = tests[j].start(); 1325 if(spawnResult != 0) { 1326 infoln("THREAD INFO: Couldn't spawn more than %i threads", noSpawned); 1327 break; 1328 } 1329 noSpawned++; 1330 } 1331 logln("Spawned all"); 1332 if (noSpawned == 0) { 1333 errln("No threads could be spawned."); 1334 return; 1335 } 1336 1337 for(int32_t patience = kCollatorThreadPatience;patience > 0; patience --) 1338 { 1339 logln("Waiting..."); 1340 1341 int32_t i; 1342 int32_t terrs = 0; 1343 int32_t completed =0; 1344 1345 for(i=0;i<kCollatorThreadThreads;i++) 1346 { 1347 if (tests[i].isRunning() == FALSE) 1348 { 1349 completed++; 1350 1351 //logln(UnicodeString("Test #") + i + " is complete.. "); 1352 1353 UnicodeString theErr; 1354 if(tests[i].getError(theErr)) 1355 { 1356 terrs++; 1357 errln(UnicodeString("#") + i + ": " + theErr); 1358 } 1359 // print out the error, too, if any. 1360 } 1361 } 1362 logln("Completed %i tests", completed); 1363 1364 if(completed == noSpawned) 1365 { 1366 logln("Done! All %i tests are finished", noSpawned); 1367 1368 if(terrs) 1369 { 1370 errln("There were errors."); 1371 SimpleThread::errorFunc(); 1372 } 1373 return; 1374 } 1375 1376 SimpleThread::sleep(900); 1377 } 1378 errln("patience exceeded. "); 1379 SimpleThread::errorFunc(); 1380 } 1381 1382 #endif /* #if !UCONFIG_NO_COLLATION */ 1383 1384 1385 1386 1387 //------------------------------------------------------------------------------------------- 1388 // 1389 // StringThreadTest2 1390 // 1391 //------------------------------------------------------------------------------------------- 1392 1393 const int kStringThreadIterations = 2500;// # of iterations per thread 1394 const int kStringThreadThreads = 10; // # of threads to spawn 1395 const int kStringThreadPatience = 120; // time in seconds to wait for all threads 1396 1397 1398 class StringThreadTest2 : public ThreadWithStatus 1399 { 1400 public: 1401 int fNum; 1402 int fTraceInfo; 1403 const UnicodeString *fSharedString; 1404 1405 StringThreadTest2(const UnicodeString *sharedString, int num) // constructor is NOT multithread safe. 1406 : ThreadWithStatus(), 1407 fNum(num), 1408 fTraceInfo(0), 1409 fSharedString(sharedString) 1410 { 1411 }; 1412 1413 1414 virtual void run() 1415 { 1416 fTraceInfo = 1; 1417 int loopCount = 0; 1418 1419 for (loopCount = 0; loopCount < kStringThreadIterations; loopCount++) { 1420 if (*fSharedString != "This is the original test string.") { 1421 error("Original string is corrupt."); 1422 break; 1423 } 1424 UnicodeString s1 = *fSharedString; 1425 s1 += "cat this"; 1426 UnicodeString s2(s1); 1427 UnicodeString s3 = *fSharedString; 1428 s2 = s3; 1429 s3.truncate(12); 1430 s2.truncate(0); 1431 } 1432 1433 // while (fNum == 4) {SimpleThread::sleep(10000);} // Force a failure by preventing thread from finishing 1434 fTraceInfo = 2; 1435 } 1436 1437 }; 1438 1439 // ** The actual test function. 1440 1441 void MultithreadTest::TestString() 1442 { 1443 int patience; 1444 int terrs = 0; 1445 int j; 1446 1447 UnicodeString *testString = new UnicodeString("This is the original test string."); 1448 1449 // Not using LocalArray<StringThreadTest2> tests[kStringThreadThreads]; 1450 // because we don't always want to delete them. 1451 // See the comments below the cleanupAndReturn label. 1452 StringThreadTest2 *tests[kStringThreadThreads]; 1453 for(j = 0; j < kStringThreadThreads; j++) { 1454 tests[j] = new StringThreadTest2(testString, j); 1455 } 1456 1457 logln(UnicodeString("Spawning: ") + kStringThreadThreads + " threads * " + kStringThreadIterations + " iterations each."); 1458 for(j = 0; j < kStringThreadThreads; j++) { 1459 int32_t threadStatus = tests[j]->start(); 1460 if (threadStatus != 0) { 1461 errln("System Error %d starting thread number %d.", threadStatus, j); 1462 SimpleThread::errorFunc(); 1463 goto cleanupAndReturn; 1464 } 1465 } 1466 1467 for(patience = kStringThreadPatience;patience > 0; patience --) 1468 { 1469 logln("Waiting..."); 1470 1471 int32_t i; 1472 terrs = 0; 1473 int32_t completed =0; 1474 1475 for(i=0;i<kStringThreadThreads;i++) { 1476 if (tests[i]->isRunning() == FALSE) 1477 { 1478 completed++; 1479 1480 logln(UnicodeString("Test #") + i + " is complete.. "); 1481 1482 UnicodeString theErr; 1483 if(tests[i]->getError(theErr)) 1484 { 1485 terrs++; 1486 errln(UnicodeString("#") + i + ": " + theErr); 1487 } 1488 // print out the error, too, if any. 1489 } 1490 } 1491 1492 if(completed == kStringThreadThreads) 1493 { 1494 logln("Done!"); 1495 if(terrs) { 1496 errln("There were errors."); 1497 } 1498 break; 1499 } 1500 1501 SimpleThread::sleep(900); 1502 } 1503 1504 if (patience <= 0) { 1505 errln("patience exceeded. "); 1506 // while (TRUE) {SimpleThread::sleep(10000);} // TODO: for debugging. Sleep forever on failure. 1507 terrs++; 1508 } 1509 1510 if (terrs > 0) { 1511 SimpleThread::errorFunc(); 1512 } 1513 1514 cleanupAndReturn: 1515 if (terrs == 0) { 1516 /* 1517 Don't clean up if there are errors. This prevents crashes if the 1518 threads are still running and using this data. This will only happen 1519 if there is an error with the test, ICU, or the machine is too slow. 1520 It's better to leak than crash. 1521 */ 1522 for(j = 0; j < kStringThreadThreads; j++) { 1523 delete tests[j]; 1524 } 1525 delete testString; 1526 } 1527 } 1528 1529 1530 // Test for ticket #10673, race in cache code in AnyTransliterator. 1531 // It's difficult to make the original unsafe code actually fail, but 1532 // this test will fairly reliably take the code path for races in 1533 // populating the cache. 1534 1535 #if !UCONFIG_NO_TRANSLITERATION 1536 class TxThread: public SimpleThread { 1537 private: 1538 Transliterator *fSharedTranslit; 1539 public: 1540 UBool fSuccess; 1541 TxThread(Transliterator *tx) : fSharedTranslit(tx), fSuccess(FALSE) {}; 1542 ~TxThread(); 1543 void run(); 1544 }; 1545 1546 TxThread::~TxThread() {} 1547 void TxThread::run() { 1548 UnicodeString greekString("\\u03B4\\u03B9\\u03B1\\u03C6\\u03BF\\u03C1\\u03B5\\u03C4\\u03B9\\u03BA\\u03BF\\u03CD\\u03C2"); 1549 greekString = greekString.unescape(); 1550 fSharedTranslit->transliterate(greekString); 1551 fSuccess = greekString[0] == 0x64; // 'd'. The whole transliterated string is "diaphoretikous" (accented u). 1552 } 1553 #endif 1554 1555 1556 void MultithreadTest::TestAnyTranslit() { 1557 #if !UCONFIG_NO_TRANSLITERATION 1558 UErrorCode status = U_ZERO_ERROR; 1559 LocalPointer<Transliterator> tx(Transliterator::createInstance("Any-Latin", UTRANS_FORWARD, status)); 1560 if (U_FAILURE(status)) { 1561 dataerrln("File %s, Line %d: Error, status = %s", __FILE__, __LINE__, u_errorName(status)); 1562 return; 1563 } 1564 TxThread * threads[4]; 1565 int32_t i; 1566 for (i=0; i<4; i++) { 1567 threads[i] = new TxThread(tx.getAlias()); 1568 } 1569 for (i=0; i<4; i++) { 1570 threads[i]->start(); 1571 } 1572 int32_t patience = 100; 1573 UBool success; 1574 UBool someThreadRunning; 1575 do { 1576 someThreadRunning = FALSE; 1577 success = TRUE; 1578 for (i=0; i<4; i++) { 1579 if (threads[i]->isRunning()) { 1580 someThreadRunning = TRUE; 1581 SimpleThread::sleep(10); 1582 break; 1583 } else { 1584 if (threads[i]->fSuccess == FALSE) { 1585 success = FALSE; 1586 } 1587 } 1588 } 1589 } while (someThreadRunning && --patience > 0); 1590 1591 if (patience <= 0) { 1592 errln("File %s, Line %d: Error, one or more threads did not complete.", __FILE__, __LINE__); 1593 } 1594 if (success == FALSE) { 1595 errln("File %s, Line %d: Error, transliteration result incorrect.", __FILE__, __LINE__); 1596 } 1597 1598 for (i=0; i<4; i++) { 1599 delete threads[i]; 1600 } 1601 #endif // !UCONFIG_NO_TRANSLITERATION 1602 } 1603 1604 #endif // ICU_USE_THREADS 1605