OLD | NEW |
1 /******************************************************************** | 1 /******************************************************************** |
2 * COPYRIGHT: | 2 * COPYRIGHT: |
3 * Copyright (c) 1999-2013, International Business Machines Corporation and | 3 * Copyright (c) 1999-2014, International Business Machines Corporation and |
4 * others. All Rights Reserved. | 4 * others. All Rights Reserved. |
5 ********************************************************************/ | 5 ********************************************************************/ |
6 | 6 |
7 #if defined(hpux) | 7 #if defined(hpux) |
8 # ifndef _INCLUDE_POSIX_SOURCE | 8 # ifndef _INCLUDE_POSIX_SOURCE |
9 # define _INCLUDE_POSIX_SOURCE | 9 # define _INCLUDE_POSIX_SOURCE |
10 # endif | 10 # endif |
11 #endif | 11 #endif |
12 | 12 |
13 #include "simplethread.h" | 13 #include "simplethread.h" |
14 | 14 |
15 #include "unicode/utypes.h" | 15 #include "unicode/utypes.h" |
16 #include "unicode/ustring.h" | 16 #include "unicode/ustring.h" |
17 #include "umutex.h" | 17 #include "umutex.h" |
18 #include "cmemory.h" | 18 #include "cmemory.h" |
19 #include "cstring.h" | 19 #include "cstring.h" |
20 #include "uparse.h" | 20 #include "uparse.h" |
21 #include "unicode/localpointer.h" | 21 #include "unicode/localpointer.h" |
22 #include "unicode/resbund.h" | 22 #include "unicode/resbund.h" |
23 #include "unicode/udata.h" | 23 #include "unicode/udata.h" |
24 #include "unicode/uloc.h" | 24 #include "unicode/uloc.h" |
25 #include "unicode/locid.h" | 25 #include "unicode/locid.h" |
26 #include "putilimp.h" | 26 #include "putilimp.h" |
27 #include "intltest.h" | 27 #include "intltest.h" |
28 #include "tsmthred.h" | 28 #include "tsmthred.h" |
29 #include "unicode/ushape.h" | 29 #include "unicode/ushape.h" |
30 | 30 #include "unicode/translit.h" |
| 31 #include "sharedobject.h" |
| 32 #include "unifiedcache.h" |
| 33 #include "uassert.h" |
31 | 34 |
32 #if U_PLATFORM_USES_ONLY_WIN32_API | 35 #if U_PLATFORM_USES_ONLY_WIN32_API |
33 /* Prefer native Windows APIs even if POSIX is implemented (i.e., on Cygwin)
. */ | 36 /* Prefer native Windows APIs even if POSIX is implemented (i.e., on Cygwin)
. */ |
34 # undef POSIX | 37 # undef POSIX |
35 #elif U_PLATFORM_IMPLEMENTS_POSIX | 38 #elif U_PLATFORM_IMPLEMENTS_POSIX |
36 # define POSIX | 39 # define POSIX |
37 #else | 40 #else |
38 # undef POSIX | 41 # undef POSIX |
39 #endif | 42 #endif |
40 | 43 |
41 | |
42 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0])) | |
43 /* Needed by z/OS to get usleep */ | 44 /* Needed by z/OS to get usleep */ |
44 #if U_PLATFORM == U_PF_OS390 | 45 #if U_PLATFORM == U_PF_OS390 |
45 #define __DOT1 1 | 46 #define __DOT1 1 |
46 #define __UU | 47 #define __UU |
47 #ifndef _XPG4_2 | 48 #ifndef _XPG4_2 |
48 #define _XPG4_2 | 49 #define _XPG4_2 |
49 #endif | 50 #endif |
50 #include <unistd.h> | 51 #include <unistd.h> |
51 #endif | 52 #endif |
52 #if defined(POSIX) | 53 #if defined(POSIX) |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
181 #endif /* #if !UCONFIG_NO_COLLATION */ | 182 #endif /* #if !UCONFIG_NO_COLLATION */ |
182 break; | 183 break; |
183 | 184 |
184 case 4: | 185 case 4: |
185 name = "TestString"; | 186 name = "TestString"; |
186 if (exec) { | 187 if (exec) { |
187 TestString(); | 188 TestString(); |
188 } | 189 } |
189 break; | 190 break; |
190 | 191 |
191 » case 5: | 192 case 5: |
192 name = "TestArabicShapingThreads"; | 193 name = "TestArabicShapingThreads"; |
193 if (exec) { | 194 if (exec) { |
194 TestArabicShapingThreads(); | 195 TestArabicShapingThreads(); |
195 } | 196 } |
196 break; | 197 break; |
197 | |
198 | 198 |
| 199 case 6: |
| 200 name = "TestAnyTranslit"; |
| 201 if (exec) { |
| 202 TestAnyTranslit(); |
| 203 } |
| 204 break; |
| 205 |
| 206 case 7: |
| 207 name = "TestConditionVariables"; |
| 208 if (exec) { |
| 209 TestConditionVariables(); |
| 210 } |
| 211 break; |
| 212 case 8: |
| 213 name = "TestUnifiedCache"; |
| 214 if (exec) { |
| 215 TestUnifiedCache(); |
| 216 } |
| 217 break; |
199 default: | 218 default: |
200 name = ""; | 219 name = ""; |
201 break; //needed to end loop | 220 break; //needed to end loop |
202 } | 221 } |
203 } | 222 } |
204 | 223 |
205 | 224 |
206 //------------------------------------------------------------------------------
----- | 225 //------------------------------------------------------------------------------
----- |
207 // | 226 // |
208 // TestThreads -- see if threads really work at all. | 227 // TestThreads -- see if threads really work at all. |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
250 UBool doTailTest(void) { | 269 UBool doTailTest(void) { |
251 static const UChar src[] = { 0x0020, 0x0633, 0 }; | 270 static const UChar src[] = { 0x0020, 0x0633, 0 }; |
252 static const UChar dst_old[] = { 0xFEB1, 0x200B,0 }; | 271 static const UChar dst_old[] = { 0xFEB1, 0x200B,0 }; |
253 static const UChar dst_new[] = { 0xFEB1, 0xFE73,0 }; | 272 static const UChar dst_new[] = { 0xFEB1, 0xFE73,0 }; |
254 UChar dst[3] = { 0x0000, 0x0000,0 }; | 273 UChar dst[3] = { 0x0000, 0x0000,0 }; |
255 int32_t length; | 274 int32_t length; |
256 UErrorCode status; | 275 UErrorCode status; |
257 IntlTest inteltst = IntlTest(); | 276 IntlTest inteltst = IntlTest(); |
258 | 277 |
259 status = U_ZERO_ERROR; | 278 status = U_ZERO_ERROR; |
260 length = u_shapeArabic(src, -1, dst, LENGTHOF(dst), | 279 length = u_shapeArabic(src, -1, dst, UPRV_LENGTHOF(dst), |
261 U_SHAPE_LETTERS_SHAPE|U_SHAPE_SEEN_TWOCELL_NEAR, &statu
s); | 280 U_SHAPE_LETTERS_SHAPE|U_SHAPE_SEEN_TWOCELL_NEAR, &statu
s); |
262 if(U_FAILURE(status)) { | 281 if(U_FAILURE(status)) { |
263 inteltst.errln("Fail: status %s\n", u_errorName(status)); | 282 inteltst.errln("Fail: status %s\n", u_errorName(status)); |
264 return FALSE; | 283 return FALSE; |
265 } else if(length!=2) { | 284 } else if(length!=2) { |
266 inteltst.errln("Fail: len %d expected 3\n", length); | 285 inteltst.errln("Fail: len %d expected 3\n", length); |
267 return FALSE; | 286 return FALSE; |
268 } else if(u_strncmp(dst,dst_old,LENGTHOF(dst))) { | 287 } else if(u_strncmp(dst,dst_old,UPRV_LENGTHOF(dst))) { |
269 inteltst.errln("Fail: got U+%04X U+%04X expected U+%04X U+%04X\n", | 288 inteltst.errln("Fail: got U+%04X U+%04X expected U+%04X U+%04X\n", |
270 dst[0],dst[1],dst_old[0],dst_old[1]); | 289 dst[0],dst[1],dst_old[0],dst_old[1]); |
271 return FALSE; | 290 return FALSE; |
272 } | 291 } |
273 | 292 |
274 | 293 |
275 //"Trying new tail | 294 //"Trying new tail |
276 status = U_ZERO_ERROR; | 295 status = U_ZERO_ERROR; |
277 length = u_shapeArabic(src, -1, dst, LENGTHOF(dst), | 296 length = u_shapeArabic(src, -1, dst, UPRV_LENGTHOF(dst), |
278 U_SHAPE_LETTERS_SHAPE|U_SHAPE_SEEN_TWOCELL_NEAR|U_SHAPE
_TAIL_NEW_UNICODE, &status); | 297 U_SHAPE_LETTERS_SHAPE|U_SHAPE_SEEN_TWOCELL_NEAR|U_SHAPE
_TAIL_NEW_UNICODE, &status); |
279 if(U_FAILURE(status)) { | 298 if(U_FAILURE(status)) { |
280 inteltst.errln("Fail: status %s\n", u_errorName(status)); | 299 inteltst.errln("Fail: status %s\n", u_errorName(status)); |
281 return FALSE; | 300 return FALSE; |
282 } else if(length!=2) { | 301 } else if(length!=2) { |
283 inteltst.errln("Fail: len %d expected 3\n", length); | 302 inteltst.errln("Fail: len %d expected 3\n", length); |
284 return FALSE; | 303 return FALSE; |
285 } else if(u_strncmp(dst,dst_new,LENGTHOF(dst))) { | 304 } else if(u_strncmp(dst,dst_new,UPRV_LENGTHOF(dst))) { |
286 inteltst.errln("Fail: got U+%04X U+%04X expected U+%04X U+%04X\n", | 305 inteltst.errln("Fail: got U+%04X U+%04X expected U+%04X U+%04X\n", |
287 dst[0],dst[1],dst_new[0],dst_new[1]); | 306 dst[0],dst[1],dst_new[0],dst_new[1]); |
288 return FALSE; | 307 return FALSE; |
289 } | 308 } |
290 | 309 |
291 | 310 |
292 return TRUE; | 311 return TRUE; |
293 | 312 |
294 } | 313 } |
295 | 314 |
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
622 | 641 |
623 | 642 |
624 //------------------------------------------------------------------------------
------------- | 643 //------------------------------------------------------------------------------
------------- |
625 // | 644 // |
626 // FormatThreadTest - a thread that tests performing a number of numberformats
. | 645 // FormatThreadTest - a thread that tests performing a number of numberformats
. |
627 // | 646 // |
628 //------------------------------------------------------------------------------
------------- | 647 //------------------------------------------------------------------------------
------------- |
629 | 648 |
630 const int kFormatThreadIterations = 100; // # of iterations per thread | 649 const int kFormatThreadIterations = 100; // # of iterations per thread |
631 const int kFormatThreadThreads = 10; // # of threads to spawn | 650 const int kFormatThreadThreads = 10; // # of threads to spawn |
632 const int kFormatThreadPatience = 60; // time in seconds to wait for all thre
ads | |
633 | 651 |
634 #if !UCONFIG_NO_FORMATTING | 652 #if !UCONFIG_NO_FORMATTING |
635 | 653 |
636 | 654 |
637 | 655 |
638 struct FormatThreadTestData | 656 struct FormatThreadTestData |
639 { | 657 { |
640 double number; | 658 double number; |
641 UnicodeString string; | 659 UnicodeString string; |
642 FormatThreadTestData(double a, const UnicodeString& b) : number(a),string(b)
{} | 660 FormatThreadTestData(double a, const UnicodeString& b) : number(a),string(b)
{} |
(...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
954 expected= "0:Someone from Croatia is receiving a #4 error - " | 972 expected= "0:Someone from Croatia is receiving a #4 error - " |
955 "U_FILE_ACCESS_ERROR. Their telephone call is costin
g $8,192.77."; | 973 "U_FILE_ACCESS_ERROR. Their telephone call is costin
g $8,192.77."; |
956 break; | 974 break; |
957 case 1: | 975 case 1: |
958 statusToCheck= U_INDEX_OUTOFBOUNDS_ERROR; | 976 statusToCheck= U_INDEX_OUTOFBOUNDS_ERROR; |
959 patternToCheck= "1:A customer in {2} is rece
iving a #{0} error - {1}. Their telephone call is costing {3,number,currency}.";
// number,currency | 977 patternToCheck= "1:A customer in {2} is rece
iving a #{0} error - {1}. Their telephone call is costing {3,number,currency}.";
// number,currency |
960 messageLocale= Locale("de","DE@currency=DEM
"); | 978 messageLocale= Locale("de","DE@currency=DEM
"); |
961 countryToCheck= Locale("","BF"); | 979 countryToCheck= Locale("","BF"); |
962 currencyToCheck= 2.32; | 980 currencyToCheck= 2.32; |
963 expected= CharsToUnicodeString( | 981 expected= CharsToUnicodeString( |
964 "1:A customer in Burkina Fas
o is receiving a #8 error - U_INDEX_OUTOFBOUNDS_ERROR. Their telephone call is c
osting 2,32\\u00A0DEM."); | 982 "1:A customer in Burkina Fas
o is receiving a #8 error - U_INDEX_OUTOFBOUNDS_ERROR. Their telephone call is c
osting 2,32\\u00A0DM."); |
965 break; | 983 break; |
966 case 2: | 984 case 2: |
967 statusToCheck= U_MEMORY_ALLOCATION_ERROR; | 985 statusToCheck= U_MEMORY_ALLOCATION_ERROR; |
968 patternToCheck= "2:user in {2} is receiving a #{0} error - {1}
. " | 986 patternToCheck= "2:user in {2} is receiving a #{0} error - {1}
. " |
969 "They insist they just spent {3,number,currenc
y} " | 987 "They insist they just spent {3,number,currenc
y} " |
970 "on memory."; // number,currency | 988 "on memory."; // number,currency |
971 messageLocale= Locale("de","AT@currency=ATS
"); // Austrian German | 989 messageLocale= Locale("de","AT@currency=ATS
"); // Austrian German |
972 countryToCheck= Locale("","US"); // hmm | 990 countryToCheck= Locale("","US"); // hmm |
973 currencyToCheck= 40193.12; | 991 currencyToCheck= 40193.12; |
974 expected= CharsToUnicodeString( | 992 expected= CharsToUnicodeString( |
(...skipping 539 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1514 if there is an error with the test, ICU, or the machine is too slow. | 1532 if there is an error with the test, ICU, or the machine is too slow. |
1515 It's better to leak than crash. | 1533 It's better to leak than crash. |
1516 */ | 1534 */ |
1517 for(j = 0; j < kStringThreadThreads; j++) { | 1535 for(j = 0; j < kStringThreadThreads; j++) { |
1518 delete tests[j]; | 1536 delete tests[j]; |
1519 } | 1537 } |
1520 delete testString; | 1538 delete testString; |
1521 } | 1539 } |
1522 } | 1540 } |
1523 | 1541 |
| 1542 |
| 1543 // Test for ticket #10673, race in cache code in AnyTransliterator. |
| 1544 // It's difficult to make the original unsafe code actually fail, but |
| 1545 // this test will fairly reliably take the code path for races in |
| 1546 // populating the cache. |
| 1547 |
| 1548 #if !UCONFIG_NO_TRANSLITERATION |
| 1549 class TxThread: public SimpleThread { |
| 1550 private: |
| 1551 Transliterator *fSharedTranslit; |
| 1552 public: |
| 1553 UBool fSuccess; |
| 1554 TxThread(Transliterator *tx) : fSharedTranslit(tx), fSuccess(FALSE) {}; |
| 1555 ~TxThread(); |
| 1556 void run(); |
| 1557 }; |
| 1558 |
| 1559 TxThread::~TxThread() {} |
| 1560 void TxThread::run() { |
| 1561 UnicodeString greekString("\\u03B4\\u03B9\\u03B1\\u03C6\\u03BF\\u03C1\\u03B5
\\u03C4\\u03B9\\u03BA\\u03BF\\u03CD\\u03C2"); |
| 1562 greekString = greekString.unescape(); |
| 1563 fSharedTranslit->transliterate(greekString); |
| 1564 fSuccess = greekString[0] == 0x64; // 'd'. The whole transliterated string i
s "diaphoretikous" (accented u). |
| 1565 } |
| 1566 #endif |
| 1567 |
| 1568 |
| 1569 void MultithreadTest::TestAnyTranslit() { |
| 1570 #if !UCONFIG_NO_TRANSLITERATION |
| 1571 UErrorCode status = U_ZERO_ERROR; |
| 1572 LocalPointer<Transliterator> tx(Transliterator::createInstance("Any-Latin",
UTRANS_FORWARD, status)); |
| 1573 if (U_FAILURE(status)) { |
| 1574 dataerrln("File %s, Line %d: Error, status = %s", __FILE__, __LINE__, u_
errorName(status)); |
| 1575 return; |
| 1576 } |
| 1577 TxThread * threads[4]; |
| 1578 int32_t i; |
| 1579 for (i=0; i<4; i++) { |
| 1580 threads[i] = new TxThread(tx.getAlias()); |
| 1581 } |
| 1582 for (i=0; i<4; i++) { |
| 1583 threads[i]->start(); |
| 1584 } |
| 1585 int32_t patience = 100; |
| 1586 UBool success; |
| 1587 UBool someThreadRunning; |
| 1588 do { |
| 1589 someThreadRunning = FALSE; |
| 1590 success = TRUE; |
| 1591 for (i=0; i<4; i++) { |
| 1592 if (threads[i]->isRunning()) { |
| 1593 someThreadRunning = TRUE; |
| 1594 SimpleThread::sleep(10); |
| 1595 break; |
| 1596 } else { |
| 1597 if (threads[i]->fSuccess == FALSE) { |
| 1598 success = FALSE; |
| 1599 } |
| 1600 } |
| 1601 } |
| 1602 } while (someThreadRunning && --patience > 0); |
| 1603 |
| 1604 if (patience <= 0) { |
| 1605 errln("File %s, Line %d: Error, one or more threads did not complete.",
__FILE__, __LINE__); |
| 1606 } |
| 1607 if (success == FALSE) { |
| 1608 errln("File %s, Line %d: Error, transliteration result incorrect.", __FI
LE__, __LINE__); |
| 1609 } |
| 1610 |
| 1611 for (i=0; i<4; i++) { |
| 1612 delete threads[i]; |
| 1613 } |
| 1614 #endif // !UCONFIG_NO_TRANSLITERATION |
| 1615 } |
| 1616 |
| 1617 |
| 1618 // Condition Variables Test |
| 1619 // Create a swarm of threads. |
| 1620 // Using a mutex and a condition variables each thread |
| 1621 // Increments a global count of started threads. |
| 1622 // Broadcasts that it has started. |
| 1623 // Waits on the condition that all threads have started. |
| 1624 // Increments a global count of finished threads. |
| 1625 // Waits on the condition that all threads have finished. |
| 1626 // Exits. |
| 1627 |
| 1628 class CondThread: public SimpleThread { |
| 1629 public: |
| 1630 CondThread() :fFinished(false) {}; |
| 1631 ~CondThread() {}; |
| 1632 void run(); |
| 1633 bool fFinished; |
| 1634 }; |
| 1635 |
| 1636 static UMutex gCTMutex = U_MUTEX_INITIALIZER; |
| 1637 static UConditionVar gCTConditionVar = U_CONDITION_INITIALIZER; |
| 1638 int gConditionTestOne = 1; // Value one. Non-const, extern linkage to inhibit |
| 1639 // compiler assuming a known value. |
| 1640 int gStartedThreads; |
| 1641 int gFinishedThreads; |
| 1642 static const int NUMTHREADS = 10; |
| 1643 |
| 1644 static MultithreadTest *gThisTest = NULL; // Make test frame work functions avai
lable to |
| 1645 // non-member functions. |
| 1646 |
| 1647 // Worker thread function. |
| 1648 void CondThread::run() { |
| 1649 umtx_lock(&gCTMutex); |
| 1650 gStartedThreads += gConditionTestOne; |
| 1651 umtx_condBroadcast(&gCTConditionVar); |
| 1652 |
| 1653 while (gStartedThreads < NUMTHREADS) { |
| 1654 if (gFinishedThreads != 0) { |
| 1655 gThisTest->errln("File %s, Line %d: Error, gStartedThreads = %d, gFi
nishedThreads = %d", |
| 1656 __FILE__, __LINE__, gStartedThreads, gFinishedThrea
ds); |
| 1657 } |
| 1658 umtx_condWait(&gCTConditionVar, &gCTMutex); |
| 1659 } |
| 1660 |
| 1661 gFinishedThreads += gConditionTestOne; |
| 1662 fFinished = true; |
| 1663 umtx_condBroadcast(&gCTConditionVar); |
| 1664 |
| 1665 while (gFinishedThreads < NUMTHREADS) { |
| 1666 umtx_condWait(&gCTConditionVar, &gCTMutex); |
| 1667 } |
| 1668 umtx_unlock(&gCTMutex); |
| 1669 } |
| 1670 |
| 1671 void MultithreadTest::TestConditionVariables() { |
| 1672 gThisTest = this; |
| 1673 gStartedThreads = 0; |
| 1674 gFinishedThreads = 0; |
| 1675 int i; |
| 1676 |
| 1677 umtx_lock(&gCTMutex); |
| 1678 CondThread *threads[NUMTHREADS]; |
| 1679 for (i=0; i<NUMTHREADS; ++i) { |
| 1680 threads[i] = new CondThread; |
| 1681 threads[i]->start(); |
| 1682 } |
| 1683 |
| 1684 while (gStartedThreads < NUMTHREADS) { |
| 1685 umtx_condWait(&gCTConditionVar, &gCTMutex); |
| 1686 } |
| 1687 |
| 1688 while (gFinishedThreads < NUMTHREADS) { |
| 1689 umtx_condWait(&gCTConditionVar, &gCTMutex); |
| 1690 } |
| 1691 |
| 1692 umtx_unlock(&gCTMutex); |
| 1693 |
| 1694 for (i=0; i<NUMTHREADS; ++i) { |
| 1695 if (!threads[i]->fFinished) { |
| 1696 errln("File %s, Line %d: Error, threads[%d]->fFinished == false", __
FILE__, __LINE__, i); |
| 1697 } |
| 1698 delete threads[i]; |
| 1699 } |
| 1700 } |
| 1701 |
| 1702 static const char *gCacheLocales[] = {"en_US", "en_GB", "fr_FR", "fr"}; |
| 1703 static int32_t gObjectsCreated = 0; |
| 1704 static const int32_t CACHE_LOAD = 3; |
| 1705 |
| 1706 class UCTMultiThreadItem : public SharedObject { |
| 1707 public: |
| 1708 char *value; |
| 1709 UCTMultiThreadItem(const char *x) : value(NULL) { |
| 1710 value = uprv_strdup(x); |
| 1711 } |
| 1712 virtual ~UCTMultiThreadItem() { |
| 1713 uprv_free(value); |
| 1714 } |
| 1715 }; |
| 1716 |
| 1717 U_NAMESPACE_BEGIN |
| 1718 |
| 1719 template<> U_EXPORT |
| 1720 const UCTMultiThreadItem *LocaleCacheKey<UCTMultiThreadItem>::createObject( |
| 1721 const void * /*unused*/, UErrorCode & /* status */) const { |
| 1722 // Since multiple threads are hitting the cache for the first time, |
| 1723 // no objects should be created yet. |
| 1724 umtx_lock(&gCTMutex); |
| 1725 if (gObjectsCreated != 0) { |
| 1726 gThisTest->errln("Expected no objects to be created yet."); |
| 1727 } |
| 1728 umtx_unlock(&gCTMutex); |
| 1729 |
| 1730 // Big, expensive object that takes 1 second to create. |
| 1731 SimpleThread::sleep(1000); |
| 1732 |
| 1733 // Log that we created an object. |
| 1734 umtx_lock(&gCTMutex); |
| 1735 ++gObjectsCreated; |
| 1736 umtx_unlock(&gCTMutex); |
| 1737 UCTMultiThreadItem *result = new UCTMultiThreadItem(fLoc.getName()); |
| 1738 result->addRef(); |
| 1739 return result; |
| 1740 } |
| 1741 |
| 1742 U_NAMESPACE_END |
| 1743 |
| 1744 class UnifiedCacheThread: public SimpleThread { |
| 1745 public: |
| 1746 UnifiedCacheThread(const char *loc) : fLoc(loc) {}; |
| 1747 ~UnifiedCacheThread() {}; |
| 1748 void run(); |
| 1749 const char *fLoc; |
| 1750 }; |
| 1751 |
| 1752 void UnifiedCacheThread::run() { |
| 1753 UErrorCode status = U_ZERO_ERROR; |
| 1754 const UnifiedCache *cache = UnifiedCache::getInstance(status); |
| 1755 U_ASSERT(status == U_ZERO_ERROR); |
| 1756 const UCTMultiThreadItem *item = NULL; |
| 1757 cache->get(LocaleCacheKey<UCTMultiThreadItem>(fLoc), item, status); |
| 1758 U_ASSERT(item != NULL); |
| 1759 if (uprv_strcmp(fLoc, item->value)) { |
| 1760 gThisTest->errln("Expected %s, got %s", fLoc, item->value); |
| 1761 } |
| 1762 item->removeRef(); |
| 1763 |
| 1764 // Mark this thread as finished |
| 1765 umtx_lock(&gCTMutex); |
| 1766 ++gFinishedThreads; |
| 1767 umtx_condBroadcast(&gCTConditionVar); |
| 1768 umtx_unlock(&gCTMutex); |
| 1769 } |
| 1770 |
| 1771 void MultithreadTest::TestUnifiedCache() { |
| 1772 UErrorCode status = U_ZERO_ERROR; |
| 1773 const UnifiedCache *cache = UnifiedCache::getInstance(status); |
| 1774 U_ASSERT(cache != NULL); |
| 1775 cache->flush(); |
| 1776 gThisTest = this; |
| 1777 gFinishedThreads = 0; |
| 1778 gObjectsCreated = 0; |
| 1779 |
| 1780 UnifiedCacheThread *threads[CACHE_LOAD][UPRV_LENGTHOF(gCacheLocales)]; |
| 1781 for (int32_t i=0; i<CACHE_LOAD; ++i) { |
| 1782 for (int32_t j=0; j<UPRV_LENGTHOF(gCacheLocales); ++j) { |
| 1783 threads[i][j] = new UnifiedCacheThread(gCacheLocales[j]); |
| 1784 threads[i][j]->start(); |
| 1785 } |
| 1786 } |
| 1787 // Wait on all the threads to complete verify that LENGTHOF(gCacheLocales) |
| 1788 // objects were created. |
| 1789 umtx_lock(&gCTMutex); |
| 1790 while (gFinishedThreads < CACHE_LOAD*UPRV_LENGTHOF(gCacheLocales)) { |
| 1791 umtx_condWait(&gCTConditionVar, &gCTMutex); |
| 1792 } |
| 1793 assertEquals("Objects created", UPRV_LENGTHOF(gCacheLocales), gObjectsCreate
d); |
| 1794 umtx_unlock(&gCTMutex); |
| 1795 |
| 1796 // clean up threads |
| 1797 for (int32_t i=0; i<CACHE_LOAD; ++i) { |
| 1798 for (int32_t j=0; j<UPRV_LENGTHOF(gCacheLocales); ++j) { |
| 1799 delete threads[i][j]; |
| 1800 } |
| 1801 } |
| 1802 } |
| 1803 |
1524 #endif // ICU_USE_THREADS | 1804 #endif // ICU_USE_THREADS |
OLD | NEW |