X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/f3c0d7a59d99c2a94c6b8822291f0e42be3773c9..340931cb2e044a2141d11567dd0f782524e32994:/icuSources/test/intltest/tsmthred.cpp?ds=sidebyside diff --git a/icuSources/test/intltest/tsmthred.cpp b/icuSources/test/intltest/tsmthred.cpp index 036d5e1d..98e04869 100644 --- a/icuSources/test/intltest/tsmthred.cpp +++ b/icuSources/test/intltest/tsmthred.cpp @@ -13,6 +13,7 @@ #include "umutex.h" #include "cmemory.h" #include "cstring.h" +#include "indiancal.h" #include "uparse.h" #include "unicode/localpointer.h" #include "unicode/resbund.h" @@ -29,11 +30,6 @@ #include "uassert.h" -#define TSMTHREAD_FAIL(msg) errln("%s at file %s, line %d", msg, __FILE__, __LINE__) -#define TSMTHREAD_ASSERT(expr) {if (!(expr)) {TSMTHREAD_FAIL("Fail");}} -#define TSMTHREAD_ASSERT_SUCCESS(status) {if (U_FAILURE(status)) { \ - errln("file: %s:%d status = %s\n", __FILE__, __LINE__, u_errorName(status));}} - MultithreadTest::MultithreadTest() { } @@ -45,6 +41,7 @@ MultithreadTest::~MultithreadTest() #include #include #include // tolower, toupper +#include #include "unicode/putil.h" @@ -62,82 +59,27 @@ void MultithreadTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ ) { if (exec) logln("TestSuite MultithreadTest: "); - switch (index) { - case 0: - name = "TestThreads"; - if (exec) - TestThreads(); - break; - - case 1: - name = "TestMutex"; - if (exec) - TestMutex(); - break; - - case 2: - name = "TestThreadedIntl"; + + TESTCASE_AUTO_BEGIN; + TESTCASE_AUTO(TestThreads); #if !UCONFIG_NO_FORMATTING - if (exec) { - TestThreadedIntl(); - } + TESTCASE_AUTO(TestThreadedIntl); #endif - break; - - case 3: - name = "TestCollators"; #if !UCONFIG_NO_COLLATION - if (exec) { - TestCollators(); - } + TESTCASE_AUTO(TestCollators); #endif /* #if !UCONFIG_NO_COLLATION */ - break; - - case 4: - name = "TestString"; - if (exec) { - TestString(); - } - break; - - case 5: - name = "TestArabicShapingThreads"; - if (exec) { - TestArabicShapingThreads(); - } - break; - - case 6: - name = "TestAnyTranslit"; - if (exec) { - TestAnyTranslit(); - } - break; - - case 7: - name = "TestConditionVariables"; - if (exec) { - TestConditionVariables(); - } - break; - case 8: - name = "TestUnifiedCache"; - if (exec) { - TestUnifiedCache(); - } - break; + TESTCASE_AUTO(TestString); + TESTCASE_AUTO(TestArabicShapingThreads); + TESTCASE_AUTO(TestAnyTranslit); + TESTCASE_AUTO(TestUnifiedCache); #if !UCONFIG_NO_TRANSLITERATION - case 9: - name = "TestBreakTranslit"; - if (exec) { - TestBreakTranslit(); - } - break; -#endif - default: - name = ""; - break; //needed to end loop - } + TESTCASE_AUTO(TestBreakTranslit); + TESTCASE_AUTO(TestIncDec); +#if !UCONFIG_NO_FORMATTING + TESTCASE_AUTO(Test20104); +#endif /* #if !UCONFIG_NO_FORMATTING */ +#endif /* #if !UCONFIG_NO_TRANSLITERATION */ + TESTCASE_AUTO_END; } @@ -189,10 +131,7 @@ void MultithreadTest::TestThreads() logln(" Subthread started."); } - if (numThreadsStarted != THREADTEST_NRTHREADS) { - errln("Not all threads could be started for testing!"); - return; - } + assertTrue(WHERE, THREADTEST_NRTHREADS == numThreadsStarted); logln("Waiting for threads to be set.."); for(i=0; ierrln( - "%s:%d gThreadsInMiddle = %d. Expected 0.", __FILE__, __LINE__, gThreadsInMiddle); - return; - } - umtx_condWait(&gThreadsCountChanged, &gTestMutexA); - } - - gThreadsInMiddle += 1; - umtx_condBroadcast(&gThreadsCountChanged); - while (gThreadsInMiddle < TESTMUTEX_THREAD_COUNT) { - if (gThreadsDone != 0) { - IntlTest::gTest->errln( - "%s:%d gThreadsDone = %d. Expected 0.", __FILE__, __LINE__, gThreadsDone); - return; - } - umtx_condWait(&gThreadsCountChanged, &gTestMutexA); - } - - gThreadsDone += 1; - umtx_condBroadcast(&gThreadsCountChanged); - while (gThreadsDone < TESTMUTEX_THREAD_COUNT) { - umtx_condWait(&gThreadsCountChanged, &gTestMutexA); - } - umtx_unlock(&gTestMutexA); - } -}; - -void MultithreadTest::TestMutex() -{ - gThreadsStarted = 0; - gThreadsInMiddle = 0; - gThreadsDone = 0; - int32_t i = 0; - TestMutexThread threads[TESTMUTEX_THREAD_COUNT]; - umtx_lock(&gTestMutexA); - for (i=0; isetLocale(theLocale); - fmt->applyPattern(pattern, realStatus); - + LocalPointer fmt(new MessageFormat(u"MessageFormat's API is broken!!!!!!!!!!!",realStatus), realStatus); if (U_FAILURE(realStatus)) { - delete fmt; return; } + fmt->setLocale(theLocale); + fmt->applyPattern(pattern, realStatus); FieldPosition ignore = 0; fmt->format(myArgs,4,result,ignore,realStatus); - - delete fmt; } /** @@ -501,8 +340,8 @@ const ThreadSafeFormatSharedData *gSharedData = NULL; ThreadSafeFormatSharedData::ThreadSafeFormatSharedData(UErrorCode &status) { fFormat.adoptInstead(NumberFormat::createCurrencyInstance(Locale::getUS(), status)); - static const UChar kYDD[] = { 0x59, 0x44, 0x44, 0x00 }; - static const UChar kBBD[] = { 0x42, 0x42, 0x44, 0x00 }; + static const UChar *kYDD = u"YDD"; + static const UChar *kBBD = u"BBD"; fYDDThing.adoptObject(new CurrencyAmount(123.456, kYDD, status)); fBBDThing.adoptObject(new CurrencyAmount(987.654, kBBD, status)); if (U_FAILURE(status)) { @@ -538,26 +377,26 @@ ThreadSafeFormat::ThreadSafeFormat(UErrorCode &status) { fFormat.adoptInstead(NumberFormat::createCurrencyInstance(Locale::getUS(), status)); } -static const UChar kUSD[] = { 0x55, 0x53, 0x44, 0x00 }; +static const UChar *kUSD = u"USD"; UBool ThreadSafeFormat::doStuff(int32_t offset, UnicodeString &appendErr, UErrorCode &status) const { UBool okay = TRUE; if(u_strcmp(fFormat->getCurrency(), kUSD)) { - appendErr.append("fFormat currency != ") + appendErr.append(u"fFormat currency != ") .append(kUSD) - .append(", =") + .append(u", =") .append(fFormat->getCurrency()) - .append("! "); + .append(u"! "); okay = FALSE; } if(u_strcmp(gSharedData->fFormat->getCurrency(), kUSD)) { - appendErr.append("gFormat currency != ") + appendErr.append(u"gFormat currency != ") .append(kUSD) - .append(", =") + .append(u", =") .append(gSharedData->fFormat->getCurrency()) - .append("! "); + .append(u"! "); okay = FALSE; } UnicodeString str; @@ -666,13 +505,13 @@ public: // Keep this data here to avoid static initialization. FormatThreadTestData kNumberFormatTestData[] = { - FormatThreadTestData((double)5.0, UnicodeString("5", "")), - FormatThreadTestData( 6.0, UnicodeString("6", "")), - FormatThreadTestData( 20.0, UnicodeString("20", "")), - FormatThreadTestData( 8.0, UnicodeString("8", "")), - FormatThreadTestData( 8.3, UnicodeString("8.3", "")), - FormatThreadTestData( 12345, UnicodeString("12,345", "")), - FormatThreadTestData( 81890.23, UnicodeString("81,890.23", "")), + FormatThreadTestData((double)5.0, UnicodeString(u"5")), + FormatThreadTestData( 6.0, UnicodeString(u"6")), + FormatThreadTestData( 20.0, UnicodeString(u"20")), + FormatThreadTestData( 8.0, UnicodeString(u"8")), + FormatThreadTestData( 8.3, UnicodeString(u"8.3")), + FormatThreadTestData( 12345, UnicodeString(u"12,345")), + FormatThreadTestData( 81890.23, UnicodeString(u"81,890.23")), }; int32_t kNumberFormatTestDataLength = UPRV_LENGTHOF(kNumberFormatTestData); @@ -683,9 +522,9 @@ public: FormatThreadTestData( 1.0, CharsToUnicodeString("100\\u00a0%")), FormatThreadTestData( 0.26, CharsToUnicodeString("26\\u00a0%")), FormatThreadTestData( - 16384.99, CharsToUnicodeString("1\\u00a0638\\u00a0499\\u00a0%")), // U+00a0 = NBSP + 16384.99, CharsToUnicodeString("1\\u202F638\\u202F499\\u00a0%")), // U+202F = NNBSP FormatThreadTestData( - 81890.23, CharsToUnicodeString("8\\u00a0189\\u00a0023\\u00a0%")), + 81890.23, CharsToUnicodeString("8\\u202F189\\u202F023\\u00a0%")), }; int32_t kPercentFormatTestDataLength = UPRV_LENGTHOF(kPercentFormatTestData); int32_t iteration; @@ -748,38 +587,36 @@ public: default: case 0: statusToCheck= U_FILE_ACCESS_ERROR; - patternToCheck= "0:Someone from {2} is receiving a #{0}" - " error - {1}. Their telephone call is costing " - "{3,number,currency}."; // number,currency + patternToCheck= u"0:Someone from {2} is receiving a #{0}" + " error - {1}. Their telephone call is costing " + "{3,number,currency}."; // number,currency messageLocale= Locale("en","US"); countryToCheck= Locale("","HR"); currencyToCheck= 8192.77; - expected= "0:Someone from Croatia is receiving a #4 error - " + expected= u"0:Someone from Croatia is receiving a #4 error - " "U_FILE_ACCESS_ERROR. Their telephone call is costing $8,192.77."; break; case 1: statusToCheck= U_INDEX_OUTOFBOUNDS_ERROR; - patternToCheck= "1:A customer in {2} is receiving a #{0} error - {1}. " - "Their telephone call is costing {3,number,currency}."; // number,currency + patternToCheck= u"1:A customer in {2} is receiving a #{0} error - {1}. " + "Their telephone call is costing {3,number,currency}."; // number,currency messageLocale= Locale("de","DE@currency=DEM"); countryToCheck= Locale("","BF"); currencyToCheck= 2.32; - expected= CharsToUnicodeString( - "1:A customer in Burkina Faso is receiving a #8 error - U_INDEX_OUTOFBOUNDS_ERROR. " - "Their telephone call is costing 2,32\\u00A0DM."); + expected= u"1:A customer in Burkina Faso is receiving a #8 error - U_INDEX_OUTOFBOUNDS_ERROR. " + u"Their telephone call is costing 2,32\u00A0DM."; break; case 2: statusToCheck= U_MEMORY_ALLOCATION_ERROR; - patternToCheck= "2:user in {2} is receiving a #{0} error - {1}. " + patternToCheck= u"2:user in {2} is receiving a #{0} error - {1}. " "They insist they just spent {3,number,currency} " "on memory."; // number,currency messageLocale= Locale("de","AT@currency=ATS"); // Austrian German countryToCheck= Locale("","US"); // hmm currencyToCheck= 40193.12; - expected= CharsToUnicodeString( - "2:user in Vereinigte Staaten is receiving a #7 error" - " - U_MEMORY_ALLOCATION_ERROR. They insist they just spent" - " \\u00f6S\\u00A040.193,12 on memory."); + expected= u"2:user in Vereinigte Staaten is receiving a #7 error" + u" - U_MEMORY_ALLOCATION_ERROR. They insist they just spent" + u" \u00f6S\u00A040.193,12 on memory."; break; } @@ -790,14 +627,14 @@ public: if(U_FAILURE(status)) { UnicodeString tmp(u_errorName(status)); - IntlTest::gTest->errln("Failure on message format, pattern=" + patternToCheck + + IntlTest::gTest->errln(u"Failure on message format, pattern=" + patternToCheck + ", error = " + tmp); goto cleanupAndReturn; } if(result != expected) { - IntlTest::gTest->errln("PatternFormat: \n" + showDifference(expected,result)); + IntlTest::gTest->errln(u"PatternFormat: \n" + showDifference(expected,result)); goto cleanupAndReturn; } // test the Thread Safe Format @@ -827,7 +664,7 @@ void MultithreadTest::TestThreadedIntl() UErrorCode threadSafeErr = U_ZERO_ERROR; ThreadSafeFormatSharedData sharedData(threadSafeErr); - assertSuccess("initializing ThreadSafeFormat", threadSafeErr, TRUE); + assertSuccess(WHERE, threadSafeErr, TRUE); // // Create and start the test threads @@ -873,17 +710,6 @@ struct Line { int32_t buflen; } ; -static UBool -skipLineBecauseOfBug(const UChar *s, int32_t length) { - // TODO: Fix ICU ticket #8052 - if(length >= 3 && - (s[0] == 0xfb2 || s[0] == 0xfb3) && - s[1] == 0x334 && - (s[2] == 0xf73 || s[2] == 0xf75 || s[2] == 0xf81)) { - return TRUE; - } - return FALSE; -} static UCollationResult normalizeResult(int32_t result) { @@ -904,7 +730,7 @@ public: noLines(0), isAtLeastUCA62(TRUE) { - }; + } void setCollator(Collator *c, Line *l, int32_t nl, UBool atLeastUCA62) { coll = c; @@ -922,8 +748,6 @@ public: for(i = 0; i < noLines; i++) { if(lines[i].buflen == 0) { continue; } - if(skipLineBecauseOfBug(lines[i].buff, lines[i].buflen)) { continue; } - int32_t resLen = coll->getSortKey(lines[i].buff, lines[i].buflen, newSk, 1024); if(oldSk != NULL) { @@ -932,12 +756,12 @@ public: int32_t cmpres2 = coll->compare(lines[i].buff, lines[i].buflen, lines[prev].buff, lines[prev].buflen); if(cmpres != -cmpres2) { - IntlTest::gTest->errln(UnicodeString("Compare result not symmetrical on line ") + (i + 1)); + IntlTest::gTest->errln(UnicodeString(u"Compare result not symmetrical on line ") + (i + 1)); break; } if(cmpres != normalizeResult(skres)) { - IntlTest::gTest->errln(UnicodeString("Difference between coll->compare and sortkey compare on line ") + (i + 1)); + IntlTest::gTest->errln(UnicodeString(u"Difference between coll->compare and sortkey compare on line ") + (i + 1)); break; } @@ -951,7 +775,7 @@ public: // which we do via setting strength=identical. } if(res > 0) { - IntlTest::gTest->errln(UnicodeString("Line is not greater or equal than previous line, for line ") + (i + 1)); + IntlTest::gTest->errln(UnicodeString(u"Line is not greater or equal than previous line, for line ") + (i + 1)); break; } } @@ -1070,7 +894,7 @@ void MultithreadTest::TestCollators() int32_t spawnResult = 0; LocalArray tests(new CollatorThreadTest[kCollatorThreadThreads]); - logln(UnicodeString("Spawning: ") + kCollatorThreadThreads + " threads * " + kFormatThreadIterations + " iterations each."); + logln(UnicodeString(u"Spawning: ") + kCollatorThreadThreads + u" threads * " + kFormatThreadIterations + u" iterations each."); int32_t j = 0; for(j = 0; j < kCollatorThreadThreads; j++) { //logln("Setting collator %i", j); @@ -1118,7 +942,7 @@ public: : SimpleThread(), fTraceInfo(0) { - }; + } virtual void run() @@ -1127,12 +951,12 @@ public: int loopCount = 0; for (loopCount = 0; loopCount < kStringThreadIterations; loopCount++) { - if (*gSharedString != "This is the original test string.") { + if (*gSharedString != u"This is the original test string.") { IntlTest::gTest->errln("%s:%d Original string is corrupt.", __FILE__, __LINE__); break; } UnicodeString s1 = *gSharedString; - s1 += "cat this"; + s1 += u"cat this"; UnicodeString s2(s1); UnicodeString s3 = *gSharedString; s2 = s3; @@ -1153,10 +977,10 @@ const UnicodeString *StringThreadTest2::gSharedString = NULL; void MultithreadTest::TestString() { int j; - StringThreadTest2::gSharedString = new UnicodeString("This is the original test string."); + StringThreadTest2::gSharedString = new UnicodeString(u"This is the original test string."); StringThreadTest2 tests[kStringThreadThreads]; - logln(UnicodeString("Spawning: ") + kStringThreadThreads + " threads * " + kStringThreadIterations + " iterations each."); + logln(UnicodeString(u"Spawning: ") + kStringThreadThreads + u" threads * " + kStringThreadIterations + u" iterations each."); for(j = 0; j < kStringThreadThreads; j++) { int32_t threadStatus = tests[j].start(); if (threadStatus != 0) { @@ -1169,7 +993,7 @@ void MultithreadTest::TestString() for(j=0; jtransliterate(greekString); - if (greekString[0] != 0x64) // 'd'. The whole transliterated string is "diaphoretikous" (accented u). - { - IntlTest::gTest->errln("%s:%d Transliteration failed.", __FILE__, __LINE__); - } + IntlTest::gTest->assertEquals(WHERE, UnicodeString(u"diaphoretikoús"), greekString); } #endif @@ -1210,10 +1030,8 @@ void MultithreadTest::TestAnyTranslit() { #if !UCONFIG_NO_TRANSLITERATION UErrorCode status = U_ZERO_ERROR; LocalPointer tx(Transliterator::createInstance("Any-Latin", UTRANS_FORWARD, status)); - if (U_FAILURE(status)) { - dataerrln("File %s, Line %d: Error, status = %s", __FILE__, __LINE__, u_errorName(status)); - return; - } + if (!assertSuccess(WHERE, status, true)) { return; } + gSharedTranslit = tx.getAlias(); TxThread threads[4]; int32_t i; @@ -1229,93 +1047,6 @@ void MultithreadTest::TestAnyTranslit() { } -// -// Condition Variables Test -// Create a swarm of threads. -// Using a mutex and a condition variables each thread -// Increments a global count of started threads. -// Broadcasts that it has started. -// Waits on the condition that all threads have started. -// Increments a global count of finished threads. -// Waits on the condition that all threads have finished. -// Exits. -// - -class CondThread: public SimpleThread { - public: - CondThread() :fFinished(false) {}; - ~CondThread() {}; - void run(); - bool fFinished; -}; - -static UMutex gCTMutex = U_MUTEX_INITIALIZER; -static UConditionVar gCTConditionVar = U_CONDITION_INITIALIZER; -int gConditionTestOne = 1; // Value one. Non-const, extern linkage to inhibit - // compiler assuming a known value. -int gStartedThreads; -int gFinishedThreads; -static const int NUMTHREADS = 10; - - -// Worker thread function. -void CondThread::run() { - umtx_lock(&gCTMutex); - gStartedThreads += gConditionTestOne; - umtx_condBroadcast(&gCTConditionVar); - - while (gStartedThreads < NUMTHREADS) { - if (gFinishedThreads != 0) { - IntlTest::gTest->errln("File %s, Line %d: Error, gStartedThreads = %d, gFinishedThreads = %d", - __FILE__, __LINE__, gStartedThreads, gFinishedThreads); - } - umtx_condWait(&gCTConditionVar, &gCTMutex); - } - - gFinishedThreads += gConditionTestOne; - fFinished = true; - umtx_condBroadcast(&gCTConditionVar); - - while (gFinishedThreads < NUMTHREADS) { - umtx_condWait(&gCTConditionVar, &gCTMutex); - } - umtx_unlock(&gCTMutex); -} - -void MultithreadTest::TestConditionVariables() { - gStartedThreads = 0; - gFinishedThreads = 0; - int i; - - umtx_lock(&gCTMutex); - CondThread *threads[NUMTHREADS]; - for (i=0; istart(); - } - - while (gStartedThreads < NUMTHREADS) { - umtx_condWait(&gCTConditionVar, &gCTMutex); - } - - while (gFinishedThreads < NUMTHREADS) { - umtx_condWait(&gCTConditionVar, &gCTMutex); - } - - umtx_unlock(&gCTMutex); - - for (i=0; ifFinished) { - errln("File %s, Line %d: Error, threads[%d]->fFinished == false", __FILE__, __LINE__, i); - } - } - - for (i=0; ijoin(); - delete threads[i]; - } -} - // // Unified Cache Test @@ -1350,6 +1081,9 @@ class UCTMultiThreadItem : public SharedObject { U_NAMESPACE_BEGIN +static std::mutex *gCTMutex = nullptr; +static std::condition_variable *gCTConditionVar = nullptr; + template<> U_EXPORT const UCTMultiThreadItem *LocaleCacheKey::createObject( const void *context, UErrorCode &status) const { @@ -1365,21 +1099,23 @@ const UCTMultiThreadItem *LocaleCacheKey::createObject( return result; } - umtx_lock(&gCTMutex); - bool firstObject = (gObjectsCreated == 0); - if (firstObject) { - // Force the first object creation that comes through to wait - // until other have completed. Verifies that cache doesn't - // deadlock when a creation is slow. - - // Note that gObjectsCreated needs to be incremeneted from 0 to 1 - // early, to keep subsequent threads from entering this path. - gObjectsCreated = 1; - while (gObjectsCreated < 3) { - umtx_condWait(&gCTConditionVar, &gCTMutex); + bool firstObject = false; + { + std::unique_lock lock(*gCTMutex); + firstObject = (gObjectsCreated == 0); + if (firstObject) { + // Force the first object creation that comes through to wait + // until other have completed. Verifies that cache doesn't + // deadlock when a creation is slow. + + // Note that gObjectsCreated needs to be incremeneted from 0 to 1 + // early, to keep subsequent threads from entering this path. + gObjectsCreated = 1; + while (gObjectsCreated < 3) { + gCTConditionVar->wait(lock); + } } } - umtx_unlock(&gCTMutex); const UCTMultiThreadItem *result = new UCTMultiThreadItem(fLoc.getLanguage()); @@ -1388,15 +1124,16 @@ const UCTMultiThreadItem *LocaleCacheKey::createObject( } else { result->addRef(); } - + // Log that we created an object. The first object was already counted, // don't do it again. - umtx_lock(&gCTMutex); - if (!firstObject) { - gObjectsCreated += 1; + { + std::unique_lock lock(*gCTMutex); + if (!firstObject) { + gObjectsCreated += 1; + } + gCTConditionVar->notify_all(); } - umtx_condBroadcast(&gCTConditionVar); - umtx_unlock(&gCTMutex); return result; } @@ -1408,8 +1145,8 @@ class UnifiedCacheThread: public SimpleThread { UnifiedCacheThread( const UnifiedCache *cache, const char *loc, - const char *loc2) : fCache(cache), fLoc(loc), fLoc2(loc2) {}; - ~UnifiedCacheThread() {}; + const char *loc2) : fCache(cache), fLoc(loc), fLoc2(loc2) {} + ~UnifiedCacheThread() {} void run(); void exerciseByLocale(const Locale &); const UnifiedCache *fCache; @@ -1423,12 +1160,7 @@ void UnifiedCacheThread::exerciseByLocale(const Locale &locale) { fCache->get( LocaleCacheKey(locale), fCache, origItem, status); U_ASSERT(U_SUCCESS(status)); - if (uprv_strcmp(locale.getLanguage(), origItem->value)) { - IntlTest::gTest->errln( - "%s:%d Expected %s, got %s", __FILE__, __LINE__, - locale.getLanguage(), - origItem->value); - } + IntlTest::gTest->assertEquals(WHERE, locale.getLanguage(), origItem->value); // Fetch the same item again many times. We should always get the same // pointer since this client is already holding onto it @@ -1436,12 +1168,7 @@ void UnifiedCacheThread::exerciseByLocale(const Locale &locale) { const UCTMultiThreadItem *item = NULL; fCache->get( LocaleCacheKey(locale), fCache, item, status); - if (item != origItem) { - IntlTest::gTest->errln( - "%s:%d Expected to get the same pointer", - __FILE__, - __LINE__); - } + IntlTest::gTest->assertTrue(WHERE, item == origItem); if (item != NULL) { item->removeRef(); } @@ -1451,7 +1178,7 @@ void UnifiedCacheThread::exerciseByLocale(const Locale &locale) { void UnifiedCacheThread::run() { // Run the exercise with 2 different locales so that we can exercise - // eviction more. If each thread exerices just one locale, then + // eviction more. If each thread exercises just one locale, then // eviction can't start until the threads end. exerciseByLocale(fLoc); exerciseByLocale(fLoc2); @@ -1468,7 +1195,9 @@ void MultithreadTest::TestUnifiedCache() { cache.setEvictionPolicy(2, 0, status); U_ASSERT(U_SUCCESS(status)); - gFinishedThreads = 0; + gCTMutex = new std::mutex(); + gCTConditionVar = new std::condition_variable(); + gObjectsCreated = 0; UnifiedCacheThread *threads[CACHE_LOAD][UPRV_LENGTHOF(gCacheLocales)]; @@ -1502,7 +1231,7 @@ void MultithreadTest::TestUnifiedCache() { } - assertEquals("unused values", 2, cache.unusedCount()); + assertEquals(WHERE, 2, cache.unusedCount()); // clean up threads for (int32_t i=0; itransliterate(expected); @@ -1571,4 +1302,67 @@ void MultithreadTest::TestBreakTranslit() { gTranslitExpected = NULL; } + +class TestIncDecThread : public SimpleThread { +public: + TestIncDecThread() {} + virtual void run(); +}; + +static u_atomic_int32_t gIncDecCounter; + +void TestIncDecThread::run() { + umtx_atomic_inc(&gIncDecCounter); + for (int32_t i=0; i<5000000; ++i) { + umtx_atomic_inc(&gIncDecCounter); + umtx_atomic_dec(&gIncDecCounter); + } +} + +void MultithreadTest::TestIncDec() +{ + static constexpr int NUM_THREADS = 4; + gIncDecCounter = 0; + TestIncDecThread threads[NUM_THREADS]; + for (auto &thread:threads) { + thread.start(); + } + for (auto &thread:threads) { + thread.join(); + } + assertEquals(WHERE, NUM_THREADS, gIncDecCounter); +} + +#if !UCONFIG_NO_FORMATTING +static Calendar *gSharedCalendar = {}; + +class Test20104Thread : public SimpleThread { +public: + Test20104Thread() {} + virtual void run(); +}; + +void Test20104Thread::run() { + gSharedCalendar->defaultCenturyStartYear(); +} + +void MultithreadTest::Test20104() { + UErrorCode status = U_ZERO_ERROR; + Locale loc("hi_IN"); + gSharedCalendar = new IndianCalendar(loc, status); + assertSuccess(WHERE, status); + + static constexpr int NUM_THREADS = 4; + Test20104Thread threads[NUM_THREADS]; + for (auto &thread:threads) { + thread.start(); + } + for (auto &thread:threads) { + thread.join(); + } + delete gSharedCalendar; + // Note: failure is reported by Thread Sanitizer. Test itself succeeds. +} +#endif /* !UCONFIG_NO_FORMATTING */ + #endif /* !UCONFIG_NO_TRANSLITERATION */