1 /******************************************************************** 2 * COPYRIGHT: 3 * Copyright (c) 1999-2009, 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 14 #include "unicode/utypes.h" 15 #include "unicode/ustring.h" 16 #include "umutex.h" 17 #include "cmemory.h" 18 #include "cstring.h" 19 #include "uparse.h" 20 #include "unicode/resbund.h" 21 #include "unicode/udata.h" 22 #include "unicode/uloc.h" 23 #include "unicode/locid.h" 24 #include "putilimp.h" 25 #if !defined(U_WINDOWS) && !defined(XP_MAC) && !defined(U_RHAPSODY) 26 #define POSIX 1 27 #endif 28 29 /* Needed by z/OS to get usleep */ 30 #if defined(OS390) 31 #define __DOT1 1 32 #define __UU 33 #define _XOPEN_SOURCE_EXTENDED 1 34 #ifndef _XPG4_2 35 #define _XPG4_2 36 #endif 37 #include <unistd.h> 38 /*#include "platform_xopen_source_extended.h"*/ 39 #endif 40 #if defined(POSIX) || defined(U_SOLARIS) || defined(U_AIX) || defined(U_HPUX) 41 42 #define HAVE_IMP 43 44 #if (ICU_USE_THREADS == 1) 45 #include <pthread.h> 46 #endif 47 48 #if defined(__hpux) && defined(HPUX_CMA) 49 # if defined(read) // read being defined as cma_read causes trouble with iostream::read 50 # undef read 51 # endif 52 #endif 53 54 /* Define __EXTENSIONS__ for Solaris and old friends in strict mode. */ 55 #ifndef __EXTENSIONS__ 56 #define __EXTENSIONS__ 57 #endif 58 59 #if defined(OS390) 60 #include <sys/types.h> 61 #endif 62 63 #if !defined(OS390) 64 #include <signal.h> 65 #endif 66 67 /* Define _XPG4_2 for Solaris and friends. */ 68 #ifndef _XPG4_2 69 #define _XPG4_2 70 #endif 71 72 /* Define __USE_XOPEN_EXTENDED for Linux and glibc. */ 73 #ifndef __USE_XOPEN_EXTENDED 74 #define __USE_XOPEN_EXTENDED 75 #endif 76 77 /* Define _INCLUDE_XOPEN_SOURCE_EXTENDED for HP/UX (11?). */ 78 #ifndef _INCLUDE_XOPEN_SOURCE_EXTENDED 79 #define _INCLUDE_XOPEN_SOURCE_EXTENDED 80 #endif 81 82 #include <unistd.h> 83 84 #endif 85 /* HPUX */ 86 #ifdef sleep 87 #undef sleep 88 #endif 89 90 91 92 #include "tsmthred.h" 93 94 #define TSMTHREAD_FAIL(msg) errln("%s at file %s, line %d", msg, __FILE__, __LINE__) 95 #define TSMTHREAD_ASSERT(expr) {if (!(expr)) {TSMTHREAD_FAIL("Fail");}} 96 97 MultithreadTest::MultithreadTest() 98 { 99 } 100 101 MultithreadTest::~MultithreadTest() 102 { 103 } 104 105 106 107 #if (ICU_USE_THREADS==0) 108 void MultithreadTest::runIndexedTest( int32_t index, UBool exec, 109 const char* &name, char* /*par*/ ) { 110 if (exec) logln("TestSuite MultithreadTest: "); 111 112 if(index == 0) 113 name = "NO_THREADED_TESTS"; 114 else 115 name = ""; 116 117 if(exec) { logln("MultithreadTest - test DISABLED. ICU_USE_THREADS set to 0, check your configuration if this is a problem.."); 118 } 119 } 120 #else 121 122 123 124 // Note: A LOT OF THE FUNCTIONS IN THIS FILE SHOULD LIVE ELSEWHERE!!!!! 125 // Note: A LOT OF THE FUNCTIONS IN THIS FILE SHOULD LIVE ELSEWHERE!!!!! 126 // -srl 127 128 #include <stdio.h> 129 #include <string.h> 130 #include <ctype.h> // tolower, toupper 131 132 #include "unicode/putil.h" 133 134 /* for mthreadtest*/ 135 #include "unicode/numfmt.h" 136 #include "unicode/choicfmt.h" 137 #include "unicode/msgfmt.h" 138 #include "unicode/locid.h" 139 #include "unicode/ucol.h" 140 #include "unicode/calendar.h" 141 #include "ucaconf.h" 142 143 //----------------------------------------------------------------------------------- 144 // 145 // class SimpleThread Of course we need a thread class first.. 146 // This wrapper has a ported implementation. 147 // 148 //----------------------------------------------------------------------------------- 149 class SimpleThread 150 { 151 public: 152 SimpleThread(); 153 virtual ~SimpleThread(); 154 int32_t start(void); // start the thread 155 UBool isRunning(); // return true if a started thread has exited. 156 157 virtual void run(void) = 0; // Override this to provide the code to run 158 // in the thread. 159 void *fImplementation; 160 161 public: 162 static void sleep(int32_t millis); // probably shouldn't go here but oh well. 163 static void errorFunc(); // Empty function, provides a single convenient place 164 // to break on errors. 165 }; 166 167 void SimpleThread::errorFunc() { 168 // *(char *)0 = 3; // Force entry into a debugger via a crash; 169 } 170 171 172 173 174 #ifdef U_WINDOWS 175 #define HAVE_IMP 176 177 # define VC_EXTRALEAN 178 # define WIN32_LEAN_AND_MEAN 179 # define NOUSER 180 # define NOSERVICE 181 # define NOIME 182 # define NOMCX 183 #include <windows.h> 184 #include <process.h> 185 186 187 188 //----------------------------------------------------------------------------------- 189 // 190 // class SimpleThread Windows Implementation 191 // 192 //----------------------------------------------------------------------------------- 193 struct Win32ThreadImplementation 194 { 195 HANDLE fHandle; 196 unsigned int fThreadID; 197 }; 198 199 200 extern "C" unsigned int __stdcall SimpleThreadProc(void *arg) 201 { 202 ((SimpleThread*)arg)->run(); 203 return 0; 204 } 205 206 SimpleThread::SimpleThread() 207 :fImplementation(0) 208 { 209 Win32ThreadImplementation *imp = new Win32ThreadImplementation; 210 imp->fHandle = 0; 211 fImplementation = imp; 212 } 213 214 SimpleThread::~SimpleThread() 215 { 216 // Destructor. Because we start the thread running with _beginthreadex(), 217 // we own the Windows HANDLE for the thread and must 218 // close it here. 219 Win32ThreadImplementation *imp = (Win32ThreadImplementation*)fImplementation; 220 if (imp != 0) { 221 if (imp->fHandle != 0) { 222 CloseHandle(imp->fHandle); 223 imp->fHandle = 0; 224 } 225 } 226 delete (Win32ThreadImplementation*)fImplementation; 227 } 228 229 int32_t SimpleThread::start() 230 { 231 Win32ThreadImplementation *imp = (Win32ThreadImplementation*)fImplementation; 232 if(imp->fHandle != NULL) { 233 // The thread appears to have already been started. 234 // This is probably an error on the part of our caller. 235 return -1; 236 } 237 238 imp->fHandle = (HANDLE) _beginthreadex( 239 NULL, // Security 240 0x20000, // Stack Size 241 SimpleThreadProc, // Function to Run 242 (void *)this, // Arg List 243 0, // initflag. Start running, not suspended 244 &imp->fThreadID // thraddr 245 ); 246 247 if (imp->fHandle == 0) { 248 // An error occured 249 int err = errno; 250 if (err == 0) { 251 err = -1; 252 } 253 return err; 254 } 255 return 0; 256 } 257 258 259 UBool SimpleThread::isRunning() { 260 // 261 // Test whether the thread associated with the SimpleThread object is 262 // still actually running. 263 // 264 // NOTE: on Win64 on Itanium processors, a crashes 265 // occur if the main thread of a process exits concurrently with some 266 // other thread(s) exiting. To avoid the possibility, we wait until the 267 // OS indicates that all threads have terminated, rather than waiting 268 // only until the end of the user's Run function has been reached. 269 // 270 // I don't know whether the crashes represent a Windows bug, or whether 271 // main() programs are supposed to have to wait for their threads. 272 // 273 Win32ThreadImplementation *imp = (Win32ThreadImplementation*)fImplementation; 274 275 bool success; 276 DWORD threadExitCode; 277 278 if (imp->fHandle == 0) { 279 // No handle, thread must not be running. 280 return FALSE; 281 } 282 success = GetExitCodeThread(imp->fHandle, &threadExitCode) != 0; 283 if (! success) { 284 // Can't get status, thread must not be running. 285 return FALSE; 286 } 287 return (threadExitCode == STILL_ACTIVE); 288 } 289 290 291 void SimpleThread::sleep(int32_t millis) 292 { 293 ::Sleep(millis); 294 } 295 296 //----------------------------------------------------------------------------------- 297 // 298 // class SimpleThread NULL Implementation 299 // 300 //----------------------------------------------------------------------------------- 301 #elif defined XP_MAC 302 303 // since the Mac has no preemptive threading (at least on MacOS 8), only 304 // cooperative threading, threads are a no-op. We have no yield() calls 305 // anywhere in the ICU, so we are guaranteed to be thread-safe. 306 307 #define HAVE_IMP 308 309 SimpleThread::SimpleThread() 310 {} 311 312 SimpleThread::~SimpleThread() 313 {} 314 315 int32_t 316 SimpleThread::start() 317 { return 0; } 318 319 void 320 SimpleThread::run() 321 {} 322 323 void 324 SimpleThread::sleep(int32_t millis) 325 {} 326 327 UBool 328 SimpleThread::isRunning() { 329 return FALSE; 330 } 331 332 #endif 333 334 335 //----------------------------------------------------------------------------------- 336 // 337 // class SimpleThread POSIX implementation 338 // 339 // A note on the POSIX vs the Windows implementations of this class.. 340 // On Windows, the main thread must verify that other threads have finished 341 // before exiting, or crashes occasionally occur. (Seen on Itanium Win64 only) 342 // The function SimpleThread::isRunning() is used for this purpose. 343 // 344 // On POSIX, there is NO reliable non-blocking mechanism to determine 345 // whether a thread has exited. pthread_kill(thread, 0) almost works, 346 // but the system can recycle thread ids immediately, so seeing that a 347 // thread exists with this call could mean that the original thread has 348 // finished and a new one started with the same ID. Useless. 349 // 350 // So we need to do the check with user code, by setting a flag just before 351 // the thread function returns. A technique that is guaranteed to fail 352 // on Windows, because it indicates that the thread is done before all 353 // system level cleanup has happened. 354 // 355 //----------------------------------------------------------------------------------- 356 #if defined(POSIX)||defined(U_SOLARIS)||defined(U_AIX)||defined(U_HPUX) 357 #define HAVE_IMP 358 359 struct PosixThreadImplementation 360 { 361 pthread_t fThread; 362 UBool fRunning; 363 UBool fRan; /* True if the thread was successfully started */ 364 }; 365 366 extern "C" void* SimpleThreadProc(void *arg) 367 { 368 // This is the code that is run in the new separate thread. 369 SimpleThread *This = (SimpleThread *)arg; 370 This->run(); // Run the user code. 371 372 // The user function has returned. Set the flag indicating that this thread 373 // is done. Need a mutex for memory barrier purposes only, so that other thread 374 // will reliably see that the flag has changed. 375 PosixThreadImplementation *imp = (PosixThreadImplementation*)This->fImplementation; 376 umtx_lock(NULL); 377 imp->fRunning = FALSE; 378 umtx_unlock(NULL); 379 return 0; 380 } 381 382 SimpleThread::SimpleThread() 383 { 384 PosixThreadImplementation *imp = new PosixThreadImplementation; 385 imp->fRunning = FALSE; 386 imp->fRan = FALSE; 387 fImplementation = imp; 388 } 389 390 SimpleThread::~SimpleThread() 391 { 392 PosixThreadImplementation *imp = (PosixThreadImplementation*)fImplementation; 393 if (imp->fRan) { 394 pthread_join(imp->fThread, NULL); 395 } 396 delete imp; 397 fImplementation = (void *)0xdeadbeef; 398 } 399 400 int32_t SimpleThread::start() 401 { 402 int32_t rc; 403 static pthread_attr_t attr; 404 static UBool attrIsInitialized = FALSE; 405 406 PosixThreadImplementation *imp = (PosixThreadImplementation*)fImplementation; 407 imp->fRunning = TRUE; 408 imp->fRan = TRUE; 409 410 #ifdef HPUX_CMA 411 if (attrIsInitialized == FALSE) { 412 rc = pthread_attr_create(&attr); 413 attrIsInitialized = TRUE; 414 } 415 rc = pthread_create(&(imp->fThread),attr,&SimpleThreadProc,(void*)this); 416 #else 417 if (attrIsInitialized == FALSE) { 418 rc = pthread_attr_init(&attr); 419 #if defined(OS390) 420 { 421 int detachstate = 0; /* jdc30: detach state of zero causes 422 threads created with this attr to be in 423 an undetached state. An undetached 424 thread will keep its resources after 425 termination. */ 426 pthread_attr_setdetachstate(&attr, &detachstate); 427 } 428 #else 429 // pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 430 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 431 #endif 432 attrIsInitialized = TRUE; 433 } 434 rc = pthread_create(&(imp->fThread),&attr,&SimpleThreadProc,(void*)this); 435 #endif 436 437 if (rc != 0) { 438 // some kind of error occured, the thread did not start. 439 imp->fRan = FALSE; 440 imp->fRunning = FALSE; 441 } 442 443 return rc; 444 } 445 446 447 UBool 448 SimpleThread::isRunning() { 449 // Note: Mutex functions are used here not for synchronization, 450 // but to force memory barriors to exist, to ensure that one thread 451 // can see changes made by another when running on processors 452 // with memory models having weak coherency. 453 PosixThreadImplementation *imp = (PosixThreadImplementation*)fImplementation; 454 umtx_lock(NULL); 455 UBool retVal = imp->fRunning; 456 umtx_unlock(NULL); 457 return retVal; 458 } 459 460 461 void SimpleThread::sleep(int32_t millis) 462 { 463 #ifdef U_SOLARIS 464 sigignore(SIGALRM); 465 #endif 466 467 #ifdef HPUX_CMA 468 cma_sleep(millis/100); 469 #elif defined(U_HPUX) || defined(OS390) 470 millis *= 1000; 471 while(millis >= 1000000) { 472 usleep(999999); 473 millis -= 1000000; 474 } 475 if(millis > 0) { 476 usleep(millis); 477 } 478 #else 479 usleep(millis * 1000); 480 #endif 481 } 482 483 #endif 484 // end POSIX 485 486 487 #ifndef HAVE_IMP 488 #error No implementation for threads! Cannot test. 489 0 = 216; //die 490 #endif 491 492 493 // *************** end fluff ****************** 494 495 /* now begins the real test. */ 496 void MultithreadTest::runIndexedTest( int32_t index, UBool exec, 497 const char* &name, char* /*par*/ ) { 498 if (exec) 499 logln("TestSuite MultithreadTest: "); 500 switch (index) { 501 case 0: 502 name = "TestThreads"; 503 if (exec) 504 TestThreads(); 505 break; 506 507 case 1: 508 name = "TestMutex"; 509 if (exec) 510 TestMutex(); 511 break; 512 513 case 2: 514 name = "TestThreadedIntl"; 515 #if !UCONFIG_NO_FORMATTING 516 if (exec) { 517 TestThreadedIntl(); 518 } 519 #endif 520 break; 521 522 case 3: 523 name = "TestCollators"; 524 #if !UCONFIG_NO_COLLATION 525 if (exec) { 526 TestCollators(); 527 } 528 #endif /* #if !UCONFIG_NO_COLLATION */ 529 break; 530 531 case 4: 532 name = "TestString"; 533 if (exec) { 534 TestString(); 535 } 536 break; 537 538 default: 539 name = ""; 540 break; //needed to end loop 541 } 542 } 543 544 545 //----------------------------------------------------------------------------------- 546 // 547 // TestThreads -- see if threads really work at all. 548 // 549 // Set up N threads pointing at N chars. When they are started, they will 550 // each sleep 1 second and then set their chars. At the end we make sure they 551 // are all set. 552 // 553 //----------------------------------------------------------------------------------- 554 #define THREADTEST_NRTHREADS 8 555 556 class TestThreadsThread : public SimpleThread 557 { 558 public: 559 TestThreadsThread(char* whatToChange) { fWhatToChange = whatToChange; } 560 virtual void run() { SimpleThread::sleep(1000); 561 Mutex m; 562 *fWhatToChange = '*'; 563 } 564 private: 565 char *fWhatToChange; 566 }; 567 568 void MultithreadTest::TestThreads() 569 { 570 char threadTestChars[THREADTEST_NRTHREADS + 1]; 571 SimpleThread *threads[THREADTEST_NRTHREADS]; 572 int32_t numThreadsStarted = 0; 573 574 int32_t i; 575 for(i=0;i<THREADTEST_NRTHREADS;i++) 576 { 577 threadTestChars[i] = ' '; 578 threads[i] = new TestThreadsThread(&threadTestChars[i]); 579 } 580 threadTestChars[THREADTEST_NRTHREADS] = '\0'; 581 582 logln("->" + UnicodeString(threadTestChars) + "<- Firing off threads.. "); 583 for(i=0;i<THREADTEST_NRTHREADS;i++) 584 { 585 if (threads[i]->start() != 0) { 586 errln("Error starting thread %d", i); 587 } 588 else { 589 numThreadsStarted++; 590 } 591 SimpleThread::sleep(100); 592 logln(" Subthread started."); 593 } 594 595 logln("Waiting for threads to be set.."); 596 if (numThreadsStarted == 0) { 597 errln("No threads could be started for testing!"); 598 return; 599 } 600 601 int32_t patience = 40; // seconds to wait 602 603 while(patience--) 604 { 605 int32_t count = 0; 606 umtx_lock(NULL); 607 for(i=0;i<THREADTEST_NRTHREADS;i++) 608 { 609 if(threadTestChars[i] == '*') 610 { 611 count++; 612 } 613 } 614 umtx_unlock(NULL); 615 616 if(count == THREADTEST_NRTHREADS) 617 { 618 logln("->" + UnicodeString(threadTestChars) + "<- Got all threads! cya"); 619 for(i=0;i<THREADTEST_NRTHREADS;i++) 620 { 621 delete threads[i]; 622 } 623 return; 624 } 625 626 logln("->" + UnicodeString(threadTestChars) + "<- Waiting.."); 627 SimpleThread::sleep(500); 628 } 629 630 errln("->" + UnicodeString(threadTestChars) + "<- PATIENCE EXCEEDED!! Still missing some."); 631 for(i=0;i<THREADTEST_NRTHREADS;i++) 632 { 633 delete threads[i]; 634 } 635 } 636 637 638 //----------------------------------------------------------------------- 639 // 640 // TestMutex - a simple (non-stress) test to verify that ICU mutexes 641 // are actually mutexing. Does not test the use of 642 // mutexes within ICU services, but rather that the 643 // platform's mutex support is at least superficially there. 644 // 645 //---------------------------------------------------------------------- 646 static UMTX gTestMutexA = NULL; 647 static UMTX gTestMutexB = NULL; 648 649 static int gThreadsStarted = 0; 650 static int gThreadsInMiddle = 0; 651 static int gThreadsDone = 0; 652 653 static const int TESTMUTEX_THREAD_COUNT = 4; 654 655 static int safeIncr(int &var, int amt) { 656 // Thread safe (using global mutex) increment of a variable. 657 // Return the updated value. 658 // Can also be used as a safe load of a variable by incrementing it by 0. 659 Mutex m; 660 var += amt; 661 return var; 662 } 663 664 class TestMutexThread : public SimpleThread 665 { 666 public: 667 virtual void run() 668 { 669 // This is the code that each of the spawned threads runs. 670 // All of the spawned threads bunch up together at each of the two mutexes 671 // because the main holds the mutexes until they do. 672 // 673 safeIncr(gThreadsStarted, 1); 674 umtx_lock(&gTestMutexA); 675 umtx_unlock(&gTestMutexA); 676 safeIncr(gThreadsInMiddle, 1); 677 umtx_lock(&gTestMutexB); 678 umtx_unlock(&gTestMutexB); 679 safeIncr(gThreadsDone, 1); 680 } 681 }; 682 683 void MultithreadTest::TestMutex() 684 { 685 // Start up the test threads. They should all pile up waiting on 686 // gTestMutexA, which we (the main thread) hold until the test threads 687 // all get there. 688 gThreadsStarted = 0; 689 gThreadsInMiddle = 0; 690 gThreadsDone = 0; 691 umtx_lock(&gTestMutexA); 692 TestMutexThread *threads[TESTMUTEX_THREAD_COUNT]; 693 int i; 694 int32_t numThreadsStarted = 0; 695 for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) { 696 threads[i] = new TestMutexThread; 697 if (threads[i]->start() != 0) { 698 errln("Error starting thread %d", i); 699 } 700 else { 701 numThreadsStarted++; 702 } 703 } 704 if (numThreadsStarted == 0) { 705 errln("No threads could be started for testing!"); 706 return; 707 } 708 709 int patience = 0; 710 while (safeIncr(gThreadsStarted, 0) != TESTMUTEX_THREAD_COUNT) { 711 if (patience++ > 24) { 712 TSMTHREAD_FAIL("Patience Exceeded"); 713 return; 714 } 715 SimpleThread::sleep(500); 716 } 717 // None of the test threads should have advanced past the first mutex. 718 TSMTHREAD_ASSERT(gThreadsInMiddle==0); 719 TSMTHREAD_ASSERT(gThreadsDone==0); 720 721 // All of the test threads have made it to the first mutex. 722 // We (the main thread) now let them advance to the second mutex, 723 // where they should all pile up again. 724 umtx_lock(&gTestMutexB); 725 umtx_unlock(&gTestMutexA); 726 727 patience = 0; 728 while (safeIncr(gThreadsInMiddle, 0) != TESTMUTEX_THREAD_COUNT) { 729 if (patience++ > 24) { 730 TSMTHREAD_FAIL("Patience Exceeded"); 731 return; 732 } 733 SimpleThread::sleep(500); 734 } 735 TSMTHREAD_ASSERT(gThreadsDone==0); 736 737 // All test threads made it to the second mutex. 738 // Now let them proceed from there. They will all terminate. 739 umtx_unlock(&gTestMutexB); 740 patience = 0; 741 while (safeIncr(gThreadsDone, 0) != TESTMUTEX_THREAD_COUNT) { 742 if (patience++ > 24) { 743 TSMTHREAD_FAIL("Patience Exceeded"); 744 return; 745 } 746 SimpleThread::sleep(500); 747 } 748 749 // All threads made it by both mutexes. 750 // Destroy the test mutexes. 751 umtx_destroy(&gTestMutexA); 752 umtx_destroy(&gTestMutexB); 753 gTestMutexA=NULL; 754 gTestMutexB=NULL; 755 756 for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) { 757 delete threads[i]; 758 } 759 760 } 761 762 763 //------------------------------------------------------------------------------------------- 764 // 765 // class ThreadWithStatus - a thread that we can check the status and error condition of 766 // 767 //------------------------------------------------------------------------------------------- 768 class ThreadWithStatus : public SimpleThread 769 { 770 public: 771 UBool getError() { return (fErrors > 0); } 772 UBool getError(UnicodeString& fillinError) { fillinError = fErrorString; return (fErrors > 0); } 773 virtual ~ThreadWithStatus(){} 774 protected: 775 ThreadWithStatus() : fErrors(0) {} 776 void error(const UnicodeString &error) { 777 fErrors++; fErrorString = error; 778 SimpleThread::errorFunc(); 779 } 780 void error() { error("An error occured."); } 781 private: 782 int32_t fErrors; 783 UnicodeString fErrorString; 784 }; 785 786 787 788 //------------------------------------------------------------------------------------------- 789 // 790 // TestMultithreadedIntl. Test ICU Formatting n a multi-threaded environment 791 // 792 //------------------------------------------------------------------------------------------- 793 794 795 // * Show exactly where the string's differences lie. 796 UnicodeString showDifference(const UnicodeString& expected, const UnicodeString& result) 797 { 798 UnicodeString res; 799 res = expected + "<Expected\n"; 800 if(expected.length() != result.length()) 801 res += " [ Different lengths ] \n"; 802 else 803 { 804 for(int32_t i=0;i<expected.length();i++) 805 { 806 if(expected[i] == result[i]) 807 { 808 res += " "; 809 } 810 else 811 { 812 res += "|"; 813 } 814 } 815 res += "<Differences"; 816 res += "\n"; 817 } 818 res += result + "<Result\n"; 819 820 return res; 821 } 822 823 824 825 826 //------------------------------------------------------------------------------------------- 827 // 828 // FormatThreadTest - a thread that tests performing a number of numberformats. 829 // 830 //------------------------------------------------------------------------------------------- 831 832 const int kFormatThreadIterations = 20; // # of iterations per thread 833 const int kFormatThreadThreads = 10; // # of threads to spawn 834 const int kFormatThreadPatience = 60; // time in seconds to wait for all threads 835 836 #if !UCONFIG_NO_FORMATTING 837 838 839 840 struct FormatThreadTestData 841 { 842 double number; 843 UnicodeString string; 844 FormatThreadTestData(double a, const UnicodeString& b) : number(a),string(b) {} 845 } ; 846 847 848 // "Someone from {2} is receiving a #{0} error - {1}. Their telephone call is costing {3 number,currency}." 849 850 void formatErrorMessage(UErrorCode &realStatus, const UnicodeString& pattern, const Locale& theLocale, 851 UErrorCode inStatus0, /* statusString 1 */ const Locale &inCountry2, double currency3, // these numbers are the message arguments. 852 UnicodeString &result) 853 { 854 if(U_FAILURE(realStatus)) 855 return; // you messed up 856 857 UnicodeString errString1(u_errorName(inStatus0)); 858 859 UnicodeString countryName2; 860 inCountry2.getDisplayCountry(theLocale,countryName2); 861 862 Formattable myArgs[] = { 863 Formattable((int32_t)inStatus0), // inStatus0 {0} 864 Formattable(errString1), // statusString1 {1} 865 Formattable(countryName2), // inCountry2 {2} 866 Formattable(currency3)// currency3 {3,number,currency} 867 }; 868 869 MessageFormat *fmt = new MessageFormat("MessageFormat's API is broken!!!!!!!!!!!",realStatus); 870 fmt->setLocale(theLocale); 871 fmt->applyPattern(pattern, realStatus); 872 873 if (U_FAILURE(realStatus)) { 874 delete fmt; 875 return; 876 } 877 878 FieldPosition ignore = 0; 879 fmt->format(myArgs,4,result,ignore,realStatus); 880 881 delete fmt; 882 } 883 884 885 UBool U_CALLCONV isAcceptable(void *, const char *, const char *, const UDataInfo *) { 886 return TRUE; 887 } 888 889 //static UMTX debugMutex = NULL; 890 //static UMTX gDebugMutex; 891 892 893 class FormatThreadTest : public ThreadWithStatus 894 { 895 public: 896 int fNum; 897 int fTraceInfo; 898 899 FormatThreadTest() // constructor is NOT multithread safe. 900 : ThreadWithStatus(), 901 fNum(0), 902 fTraceInfo(0), 903 fOffset(0) 904 // the locale to use 905 { 906 static int32_t fgOffset = 0; 907 fgOffset += 3; 908 fOffset = fgOffset; 909 } 910 911 912 virtual void run() 913 { 914 fTraceInfo = 1; 915 NumberFormat *formatter = NULL; 916 NumberFormat *percentFormatter = NULL; 917 UErrorCode status = U_ZERO_ERROR; 918 919 #if 0 920 // debugging code, 921 for (int i=0; i<4000; i++) { 922 status = U_ZERO_ERROR; 923 UDataMemory *data1 = udata_openChoice(0, "res", "en_US", isAcceptable, 0, &status); 924 UDataMemory *data2 = udata_openChoice(0, "res", "fr", isAcceptable, 0, &status); 925 udata_close(data1); 926 udata_close(data2); 927 if (U_FAILURE(status)) { 928 error("udata_openChoice failed.\n"); 929 break; 930 } 931 } 932 return; 933 #endif 934 935 #if 0 936 // debugging code, 937 int m; 938 for (m=0; m<4000; m++) { 939 status = U_ZERO_ERROR; 940 UResourceBundle *res = NULL; 941 const char *localeName = NULL; 942 943 Locale loc = Locale::getEnglish(); 944 945 localeName = loc.getName(); 946 // localeName = "en"; 947 948 // ResourceBundle bund = ResourceBundle(0, loc, status); 949 //umtx_lock(&gDebugMutex); 950 res = ures_open(NULL, localeName, &status); 951 //umtx_unlock(&gDebugMutex); 952 953 //umtx_lock(&gDebugMutex); 954 ures_close(res); 955 //umtx_unlock(&gDebugMutex); 956 957 if (U_FAILURE(status)) { 958 error("Resource bundle construction failed.\n"); 959 break; 960 } 961 } 962 return; 963 #endif 964 965 // Keep this data here to avoid static initialization. 966 FormatThreadTestData kNumberFormatTestData[] = 967 { 968 FormatThreadTestData((double)5.0, UnicodeString("5", "")), 969 FormatThreadTestData( 6.0, UnicodeString("6", "")), 970 FormatThreadTestData( 20.0, UnicodeString("20", "")), 971 FormatThreadTestData( 8.0, UnicodeString("8", "")), 972 FormatThreadTestData( 8.3, UnicodeString("8.3", "")), 973 FormatThreadTestData( 12345, UnicodeString("12,345", "")), 974 FormatThreadTestData( 81890.23, UnicodeString("81,890.23", "")), 975 }; 976 int32_t kNumberFormatTestDataLength = (int32_t)(sizeof(kNumberFormatTestData) / 977 sizeof(kNumberFormatTestData[0])); 978 979 // Keep this data here to avoid static initialization. 980 FormatThreadTestData kPercentFormatTestData[] = 981 { 982 FormatThreadTestData((double)5.0, CharsToUnicodeString("500\\u00a0%")), 983 FormatThreadTestData( 1.0, CharsToUnicodeString("100\\u00a0%")), 984 FormatThreadTestData( 0.26, CharsToUnicodeString("26\\u00a0%")), 985 FormatThreadTestData( 986 16384.99, CharsToUnicodeString("1\\u00a0638\\u00a0499\\u00a0%")), // U+00a0 = NBSP 987 FormatThreadTestData( 988 81890.23, CharsToUnicodeString("8\\u00a0189\\u00a0023\\u00a0%")), 989 }; 990 int32_t kPercentFormatTestDataLength = 991 (int32_t)(sizeof(kPercentFormatTestData) / sizeof(kPercentFormatTestData[0])); 992 int32_t iteration; 993 994 status = U_ZERO_ERROR; 995 formatter = NumberFormat::createInstance(Locale::getEnglish(),status); 996 if(U_FAILURE(status)) { 997 error("Error on NumberFormat::createInstance()."); 998 goto cleanupAndReturn; 999 } 1000 1001 percentFormatter = NumberFormat::createPercentInstance(Locale::getFrench(),status); 1002 if(U_FAILURE(status)) { 1003 error("Error on NumberFormat::createPercentInstance()."); 1004 goto cleanupAndReturn; 1005 } 1006 1007 for(iteration = 0;!getError() && iteration<kFormatThreadIterations;iteration++) 1008 { 1009 1010 int32_t whichLine = (iteration + fOffset)%kNumberFormatTestDataLength; 1011 1012 UnicodeString output; 1013 1014 formatter->format(kNumberFormatTestData[whichLine].number, output); 1015 1016 if(0 != output.compare(kNumberFormatTestData[whichLine].string)) { 1017 error("format().. expected " + kNumberFormatTestData[whichLine].string 1018 + " got " + output); 1019 goto cleanupAndReturn; 1020 } 1021 1022 // Now check percent. 1023 output.remove(); 1024 whichLine = (iteration + fOffset)%kPercentFormatTestDataLength; 1025 1026 percentFormatter->format(kPercentFormatTestData[whichLine].number, output); 1027 if(0 != output.compare(kPercentFormatTestData[whichLine].string)) 1028 { 1029 error("percent format().. \n" + 1030 showDifference(kPercentFormatTestData[whichLine].string,output)); 1031 goto cleanupAndReturn; 1032 } 1033 1034 // Test message error 1035 const int kNumberOfMessageTests = 3; 1036 UErrorCode statusToCheck; 1037 UnicodeString patternToCheck; 1038 Locale messageLocale; 1039 Locale countryToCheck; 1040 double currencyToCheck; 1041 1042 UnicodeString expected; 1043 1044 // load the cases. 1045 switch((iteration+fOffset) % kNumberOfMessageTests) 1046 { 1047 default: 1048 case 0: 1049 statusToCheck= U_FILE_ACCESS_ERROR; 1050 patternToCheck= "0:Someone from {2} is receiving a #{0}" 1051 " error - {1}. Their telephone call is costing " 1052 "{3,number,currency}."; // number,currency 1053 messageLocale= Locale("en","US"); 1054 countryToCheck= Locale("","HR"); 1055 currencyToCheck= 8192.77; 1056 expected= "0:Someone from Croatia is receiving a #4 error - " 1057 "U_FILE_ACCESS_ERROR. Their telephone call is costing $8,192.77."; 1058 break; 1059 case 1: 1060 statusToCheck= U_INDEX_OUTOFBOUNDS_ERROR; 1061 patternToCheck= "1:A customer in {2} is receiving a #{0} error - {1}. Their telephone call is costing {3,number,currency}."; // number,currency 1062 messageLocale= Locale("de","DE@currency=DEM"); 1063 countryToCheck= Locale("","BF"); 1064 currencyToCheck= 2.32; 1065 expected= CharsToUnicodeString( 1066 "1:A customer in Burkina Faso is receiving a #8 error - U_INDEX_OUTOFBOUNDS_ERROR. Their telephone call is costing 2,32\\u00A0DM."); 1067 break; 1068 case 2: 1069 statusToCheck= U_MEMORY_ALLOCATION_ERROR; 1070 patternToCheck= "2:user in {2} is receiving a #{0} error - {1}. " 1071 "They insist they just spent {3,number,currency} " 1072 "on memory."; // number,currency 1073 messageLocale= Locale("de","AT@currency=ATS"); // Austrian German 1074 countryToCheck= Locale("","US"); // hmm 1075 currencyToCheck= 40193.12; 1076 expected= CharsToUnicodeString( 1077 "2:user in Vereinigte Staaten is receiving a #7 error" 1078 " - U_MEMORY_ALLOCATION_ERROR. They insist they just spent" 1079 " \\u00f6S\\u00A040.193,12 on memory."); 1080 break; 1081 } 1082 1083 UnicodeString result; 1084 UErrorCode status = U_ZERO_ERROR; 1085 formatErrorMessage(status,patternToCheck,messageLocale,statusToCheck, 1086 countryToCheck,currencyToCheck,result); 1087 if(U_FAILURE(status)) 1088 { 1089 UnicodeString tmp(u_errorName(status)); 1090 error("Failure on message format, pattern=" + patternToCheck + 1091 ", error = " + tmp); 1092 goto cleanupAndReturn; 1093 } 1094 1095 if(result != expected) 1096 { 1097 error("PatternFormat: \n" + showDifference(expected,result)); 1098 goto cleanupAndReturn; 1099 } 1100 } /* end of for loop */ 1101 1102 cleanupAndReturn: 1103 delete formatter; 1104 delete percentFormatter; 1105 1106 // while (fNum == 4) {SimpleThread::sleep(10000);} // Force a failure by preventing thread from finishing 1107 fTraceInfo = 2; 1108 } 1109 1110 private: 1111 int32_t fOffset; // where we are testing from. 1112 }; 1113 1114 // ** The actual test function. 1115 1116 void MultithreadTest::TestThreadedIntl() 1117 { 1118 int i; 1119 UnicodeString theErr; 1120 UBool haveDisplayedInfo[kFormatThreadThreads]; 1121 static const int32_t PATIENCE_SECONDS = 45; 1122 1123 // 1124 // Create and start the test threads 1125 // 1126 logln("Spawning: %d threads * %d iterations each.", 1127 kFormatThreadThreads, kFormatThreadIterations); 1128 FormatThreadTest *tests = new FormatThreadTest[kFormatThreadThreads]; 1129 for(int32_t j = 0; j < kFormatThreadThreads; j++) { 1130 tests[j].fNum = j; 1131 int32_t threadStatus = tests[j].start(); 1132 if (threadStatus != 0) { 1133 errln("System Error %d starting thread number %d.", threadStatus, j); 1134 SimpleThread::errorFunc(); 1135 goto cleanupAndReturn; 1136 } 1137 haveDisplayedInfo[j] = FALSE; 1138 } 1139 1140 1141 // Spin, waiting for the test threads to finish. 1142 UBool stillRunning; 1143 UDate startTime, endTime; 1144 startTime = Calendar::getNow(); 1145 do { 1146 /* Spin until the test threads complete. */ 1147 stillRunning = FALSE; 1148 endTime = Calendar::getNow(); 1149 if (((int32_t)(endTime - startTime)/U_MILLIS_PER_SECOND) > PATIENCE_SECONDS) { 1150 errln("Patience exceeded. Test is taking too long."); 1151 return; 1152 } 1153 /* 1154 The following sleep must be here because the *BSD operating systems 1155 have a brain dead thread scheduler. They starve the child threads from 1156 CPU time. 1157 */ 1158 SimpleThread::sleep(1); // yield 1159 for(i=0;i<kFormatThreadThreads;i++) { 1160 if (tests[i].isRunning()) { 1161 stillRunning = TRUE; 1162 } else if (haveDisplayedInfo[i] == FALSE) { 1163 logln("Thread # %d is complete..", i); 1164 if(tests[i].getError(theErr)) { 1165 dataerrln(UnicodeString("#") + i + ": " + theErr); 1166 SimpleThread::errorFunc(); 1167 } 1168 haveDisplayedInfo[i] = TRUE; 1169 } 1170 } 1171 } while (stillRunning); 1172 1173 // 1174 // All threads have finished. 1175 // 1176 cleanupAndReturn: 1177 delete [] tests; 1178 } 1179 #endif /* #if !UCONFIG_NO_FORMATTING */ 1180 1181 1182 1183 1184 1185 //------------------------------------------------------------------------------------------- 1186 // 1187 // Collation threading test 1188 // 1189 //------------------------------------------------------------------------------------------- 1190 #if !UCONFIG_NO_COLLATION 1191 1192 #define kCollatorThreadThreads 10 // # of threads to spawn 1193 #define kCollatorThreadPatience kCollatorThreadThreads*30 1194 1195 struct Line { 1196 UChar buff[25]; 1197 int32_t buflen; 1198 } ; 1199 1200 class CollatorThreadTest : public ThreadWithStatus 1201 { 1202 private: 1203 const UCollator *coll; 1204 const Line *lines; 1205 int32_t noLines; 1206 public: 1207 CollatorThreadTest() : ThreadWithStatus(), 1208 coll(NULL), 1209 lines(NULL), 1210 noLines(0) 1211 { 1212 }; 1213 void setCollator(UCollator *c, Line *l, int32_t nl) 1214 { 1215 coll = c; 1216 lines = l; 1217 noLines = nl; 1218 } 1219 virtual void run() { 1220 //sleep(10000); 1221 int32_t line = 0; 1222 1223 uint8_t sk1[1024], sk2[1024]; 1224 uint8_t *oldSk = NULL, *newSk = sk1; 1225 int32_t resLen = 0, oldLen = 0; 1226 int32_t i = 0; 1227 1228 for(i = 0; i < noLines; i++) { 1229 resLen = ucol_getSortKey(coll, lines[i].buff, lines[i].buflen, newSk, 1024); 1230 1231 int32_t res = 0, cmpres = 0, cmpres2 = 0; 1232 1233 if(oldSk != NULL) { 1234 res = strcmp((char *)oldSk, (char *)newSk); 1235 cmpres = ucol_strcoll(coll, lines[i-1].buff, lines[i-1].buflen, lines[i].buff, lines[i].buflen); 1236 cmpres2 = ucol_strcoll(coll, lines[i].buff, lines[i].buflen, lines[i-1].buff, lines[i-1].buflen); 1237 //cmpres = res; 1238 //cmpres2 = -cmpres; 1239 1240 if(cmpres != -cmpres2) { 1241 error("Compare result not symmetrical on line "+ line); 1242 break; 1243 } 1244 1245 if(((res&0x80000000) != (cmpres&0x80000000)) || (res == 0 && cmpres != 0) || (res != 0 && cmpres == 0)) { 1246 error(UnicodeString("Difference between ucol_strcoll and sortkey compare on line ")+ UnicodeString(line)); 1247 break; 1248 } 1249 1250 if(res > 0) { 1251 error(UnicodeString("Line %i is not greater or equal than previous line ")+ UnicodeString(i)); 1252 break; 1253 } else if(res == 0) { /* equal */ 1254 res = u_strcmpCodePointOrder(lines[i-1].buff, lines[i].buff); 1255 if (res == 0) { 1256 error(UnicodeString("Probable error in test file on line %i (comparing identical strings)")+ UnicodeString(i)); 1257 break; 1258 } else if (res > 0) { 1259 error(UnicodeString("Sortkeys are identical, but code point comapare gives >0 on line ")+ UnicodeString(i)); 1260 break; 1261 } 1262 } 1263 } 1264 1265 oldSk = newSk; 1266 oldLen = resLen; 1267 1268 newSk = (newSk == sk1)?sk2:sk1; 1269 } 1270 } 1271 1272 }; 1273 1274 void MultithreadTest::TestCollators() 1275 { 1276 1277 UErrorCode status = U_ZERO_ERROR; 1278 FILE *testFile = NULL; 1279 char testDataPath[1024]; 1280 strcpy(testDataPath, IntlTest::getSourceTestData(status)); 1281 if (U_FAILURE(status)) { 1282 errln("ERROR: could not open test data %s", u_errorName(status)); 1283 return; 1284 } 1285 strcat(testDataPath, "CollationTest_"); 1286 1287 const char* type = "NON_IGNORABLE"; 1288 1289 const char *ext = ".txt"; 1290 if(testFile) { 1291 fclose(testFile); 1292 } 1293 char buffer[1024]; 1294 strcpy(buffer, testDataPath); 1295 strcat(buffer, type); 1296 size_t bufLen = strlen(buffer); 1297 1298 // we try to open 3 files: 1299 // path/CollationTest_type.txt 1300 // path/CollationTest_type_SHORT.txt 1301 // path/CollationTest_type_STUB.txt 1302 // we are going to test with the first one that we manage to open. 1303 1304 strcpy(buffer+bufLen, ext); 1305 1306 testFile = fopen(buffer, "rb"); 1307 1308 if(testFile == 0) { 1309 strcpy(buffer+bufLen, "_SHORT"); 1310 strcat(buffer, ext); 1311 testFile = fopen(buffer, "rb"); 1312 1313 if(testFile == 0) { 1314 strcpy(buffer+bufLen, "_STUB"); 1315 strcat(buffer, ext); 1316 testFile = fopen(buffer, "rb"); 1317 1318 if (testFile == 0) { 1319 *(buffer+bufLen) = 0; 1320 dataerrln("could not open any of the conformance test files, tried opening base %s", buffer); 1321 return; 1322 } else { 1323 infoln( 1324 "INFO: Working with the stub file.\n" 1325 "If you need the full conformance test, please\n" 1326 "download the appropriate data files from:\n" 1327 "http://source.icu-project.org/repos/icu/tools/trunk/unicodetools/com/ibm/text/data/"); 1328 } 1329 } 1330 } 1331 1332 Line *lines = new Line[200000]; 1333 memset(lines, 0, sizeof(Line)*200000); 1334 int32_t lineNum = 0; 1335 1336 UChar bufferU[1024]; 1337 int32_t buflen = 0; 1338 uint32_t first = 0; 1339 uint32_t offset = 0; 1340 1341 while (fgets(buffer, 1024, testFile) != NULL) { 1342 offset = 0; 1343 if(*buffer == 0 || strlen(buffer) < 3 || buffer[0] == '#') { 1344 continue; 1345 } 1346 offset = u_parseString(buffer, bufferU, 1024, &first, &status); 1347 buflen = offset; 1348 bufferU[offset++] = 0; 1349 lines[lineNum].buflen = buflen; 1350 //lines[lineNum].buff = new UChar[buflen+1]; 1351 u_memcpy(lines[lineNum].buff, bufferU, buflen); 1352 lineNum++; 1353 } 1354 fclose(testFile); 1355 if(U_FAILURE(status)) { 1356 dataerrln("Couldn't read the test file!"); 1357 return; 1358 } 1359 1360 UCollator *coll = ucol_open("root", &status); 1361 if(U_FAILURE(status)) { 1362 errcheckln(status, "Couldn't open UCA collator"); 1363 return; 1364 } 1365 ucol_setAttribute(coll, UCOL_NORMALIZATION_MODE, UCOL_ON, &status); 1366 ucol_setAttribute(coll, UCOL_CASE_FIRST, UCOL_OFF, &status); 1367 ucol_setAttribute(coll, UCOL_CASE_LEVEL, UCOL_OFF, &status); 1368 ucol_setAttribute(coll, UCOL_STRENGTH, UCOL_TERTIARY, &status); 1369 ucol_setAttribute(coll, UCOL_ALTERNATE_HANDLING, UCOL_NON_IGNORABLE, &status); 1370 1371 int32_t noSpawned = 0; 1372 int32_t spawnResult = 0; 1373 CollatorThreadTest *tests; 1374 tests = new CollatorThreadTest[kCollatorThreadThreads]; 1375 1376 logln(UnicodeString("Spawning: ") + kCollatorThreadThreads + " threads * " + kFormatThreadIterations + " iterations each."); 1377 int32_t j = 0; 1378 for(j = 0; j < kCollatorThreadThreads; j++) { 1379 //logln("Setting collator %i", j); 1380 tests[j].setCollator(coll, lines, lineNum); 1381 } 1382 for(j = 0; j < kCollatorThreadThreads; j++) { 1383 log("%i ", j); 1384 spawnResult = tests[j].start(); 1385 if(spawnResult != 0) { 1386 infoln("THREAD INFO: Couldn't spawn more than %i threads", noSpawned); 1387 break; 1388 } 1389 noSpawned++; 1390 } 1391 logln("Spawned all"); 1392 if (noSpawned == 0) { 1393 errln("No threads could be spawned."); 1394 return; 1395 } 1396 1397 for(int32_t patience = kCollatorThreadPatience;patience > 0; patience --) 1398 { 1399 logln("Waiting..."); 1400 1401 int32_t i; 1402 int32_t terrs = 0; 1403 int32_t completed =0; 1404 1405 for(i=0;i<kCollatorThreadThreads;i++) 1406 { 1407 if (tests[i].isRunning() == FALSE) 1408 { 1409 completed++; 1410 1411 //logln(UnicodeString("Test #") + i + " is complete.. "); 1412 1413 UnicodeString theErr; 1414 if(tests[i].getError(theErr)) 1415 { 1416 terrs++; 1417 errln(UnicodeString("#") + i + ": " + theErr); 1418 } 1419 // print out the error, too, if any. 1420 } 1421 } 1422 logln("Completed %i tests", completed); 1423 1424 if(completed == noSpawned) 1425 { 1426 logln("Done! All %i tests are finished", noSpawned); 1427 1428 if(terrs) 1429 { 1430 errln("There were errors."); 1431 SimpleThread::errorFunc(); 1432 } 1433 ucol_close(coll); 1434 delete[] tests; 1435 //for(i = 0; i < lineNum; i++) { 1436 //delete[] lines[i].buff; 1437 //} 1438 delete[] lines; 1439 1440 return; 1441 } 1442 1443 SimpleThread::sleep(900); 1444 } 1445 errln("patience exceeded. "); 1446 SimpleThread::errorFunc(); 1447 ucol_close(coll); 1448 } 1449 1450 #endif /* #if !UCONFIG_NO_COLLATION */ 1451 1452 1453 1454 1455 //------------------------------------------------------------------------------------------- 1456 // 1457 // StringThreadTest2 1458 // 1459 //------------------------------------------------------------------------------------------- 1460 1461 const int kStringThreadIterations = 2500;// # of iterations per thread 1462 const int kStringThreadThreads = 10; // # of threads to spawn 1463 const int kStringThreadPatience = 120; // time in seconds to wait for all threads 1464 1465 1466 class StringThreadTest2 : public ThreadWithStatus 1467 { 1468 public: 1469 int fNum; 1470 int fTraceInfo; 1471 const UnicodeString *fSharedString; 1472 1473 StringThreadTest2(const UnicodeString *sharedString, int num) // constructor is NOT multithread safe. 1474 : ThreadWithStatus(), 1475 fNum(num), 1476 fTraceInfo(0), 1477 fSharedString(sharedString) 1478 { 1479 }; 1480 1481 1482 virtual void run() 1483 { 1484 fTraceInfo = 1; 1485 int loopCount = 0; 1486 1487 for (loopCount = 0; loopCount < kStringThreadIterations; loopCount++) { 1488 if (*fSharedString != "This is the original test string.") { 1489 error("Original string is corrupt."); 1490 break; 1491 } 1492 UnicodeString s1 = *fSharedString; 1493 s1 += "cat this"; 1494 UnicodeString s2(s1); 1495 UnicodeString s3 = *fSharedString; 1496 s2 = s3; 1497 s3.truncate(12); 1498 s2.truncate(0); 1499 } 1500 1501 // while (fNum == 4) {SimpleThread::sleep(10000);} // Force a failure by preventing thread from finishing 1502 fTraceInfo = 2; 1503 } 1504 1505 }; 1506 1507 // ** The actual test function. 1508 1509 void MultithreadTest::TestString() 1510 { 1511 int patience; 1512 int terrs = 0; 1513 int j; 1514 1515 UnicodeString *testString = new UnicodeString("This is the original test string."); 1516 1517 StringThreadTest2 *tests[kStringThreadThreads]; 1518 for(j = 0; j < kStringThreadThreads; j++) { 1519 tests[j] = new StringThreadTest2(testString, j); 1520 } 1521 1522 logln(UnicodeString("Spawning: ") + kStringThreadThreads + " threads * " + kStringThreadIterations + " iterations each."); 1523 for(j = 0; j < kStringThreadThreads; j++) { 1524 int32_t threadStatus = tests[j]->start(); 1525 if (threadStatus != 0) { 1526 errln("System Error %d starting thread number %d.", threadStatus, j); 1527 SimpleThread::errorFunc(); 1528 goto cleanupAndReturn; 1529 } 1530 } 1531 1532 for(patience = kStringThreadPatience;patience > 0; patience --) 1533 { 1534 logln("Waiting..."); 1535 1536 int32_t i; 1537 terrs = 0; 1538 int32_t completed =0; 1539 1540 for(i=0;i<kStringThreadThreads;i++) { 1541 if (tests[i]->isRunning() == FALSE) 1542 { 1543 completed++; 1544 1545 logln(UnicodeString("Test #") + i + " is complete.. "); 1546 1547 UnicodeString theErr; 1548 if(tests[i]->getError(theErr)) 1549 { 1550 terrs++; 1551 errln(UnicodeString("#") + i + ": " + theErr); 1552 } 1553 // print out the error, too, if any. 1554 } 1555 } 1556 1557 if(completed == kStringThreadThreads) 1558 { 1559 logln("Done!"); 1560 if(terrs) { 1561 errln("There were errors."); 1562 } 1563 break; 1564 } 1565 1566 SimpleThread::sleep(900); 1567 } 1568 1569 if (patience <= 0) { 1570 errln("patience exceeded. "); 1571 // while (TRUE) {SimpleThread::sleep(10000);} // TODO: for debugging. Sleep forever on failure. 1572 terrs++; 1573 } 1574 1575 if (terrs > 0) { 1576 SimpleThread::errorFunc(); 1577 } 1578 1579 cleanupAndReturn: 1580 if (terrs == 0) { 1581 /* 1582 Don't clean up if there are errors. This prevents crashes if the 1583 threads are still running and using this data. This will only happen 1584 if there is an error with the test, ICU, or the machine is too slow. 1585 It's better to leak than crash. 1586 */ 1587 for(j = 0; j < kStringThreadThreads; j++) { 1588 delete tests[j]; 1589 } 1590 delete testString; 1591 } 1592 } 1593 1594 1595 1596 1597 1598 #endif // ICU_USE_THREADS 1599 1600