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