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