#include "umutex.h"
#include "cmemory.h"
#include "cstring.h"
+#include "indiancal.h"
#include "uparse.h"
#include "unicode/localpointer.h"
#include "unicode/resbund.h"
#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()
{
}
#include <stdio.h>
#include <string.h>
#include <ctype.h> // tolower, toupper
+#include <memory>
#include "unicode/putil.h"
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;
}
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; i<THREADTEST_NRTHREADS; i++) {
class TestArabicShapeThreads : public SimpleThread
{
public:
- TestArabicShapeThreads() {};
- virtual void run() { doTailTest(); };
+ TestArabicShapeThreads() {}
+ virtual void run() { doTailTest(); }
private:
void doTailTest();
};
}
- //"Trying new tail
+ // Trying new tail
status = U_ZERO_ERROR;
length = u_shapeArabic(src, -1, dst, UPRV_LENGTHOF(dst),
U_SHAPE_LETTERS_SHAPE|U_SHAPE_SEEN_TWOCELL_NEAR|U_SHAPE_TAIL_NEW_UNICODE, &status);
}
-//-----------------------------------------------------------------------
-//
-// TestMutex - a simple (non-stress) test to verify that ICU mutexes
-// and condition variables are functioning. Does not test the use of
-// mutexes within ICU services, but rather that the
-// platform's mutex support is at least superficially there.
-//
-//----------------------------------------------------------------------
-static UMutex gTestMutexA = U_MUTEX_INITIALIZER;
-static UConditionVar gThreadsCountChanged = U_CONDITION_INITIALIZER;
-
-static int gThreadsStarted = 0;
-static int gThreadsInMiddle = 0;
-static int gThreadsDone = 0;
-
-static const int TESTMUTEX_THREAD_COUNT = 40;
-
-class TestMutexThread : public SimpleThread
-{
-public:
- virtual void run() {
- // This is the code that each of the spawned threads runs.
- // All threads move together throught the started - middle - done sequence together,
- // waiting for all other threads to reach each point before advancing.
- umtx_lock(&gTestMutexA);
- gThreadsStarted += 1;
- umtx_condBroadcast(&gThreadsCountChanged);
- while (gThreadsStarted < TESTMUTEX_THREAD_COUNT) {
- if (gThreadsInMiddle != 0) {
- IntlTest::gTest->errln(
- "%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; i<TESTMUTEX_THREAD_COUNT; i++) {
- if (threads[i].start() != 0) {
- errln("%s:%d Error starting thread %d", __FILE__, __LINE__, i);
- return;
- }
- }
-
- // Because we are holding gTestMutexA, all of the threads should be blocked
- // at the start of their run() function.
- if (gThreadsStarted != 0) {
- errln("%s:%d gThreadsStarted=%d. Expected 0.", __FILE__, __LINE__, gThreadsStarted);
- return;
- }
-
- while (gThreadsInMiddle < TESTMUTEX_THREAD_COUNT) {
- if (gThreadsDone != 0) {
- errln("%s:%d gThreadsDone=%d. Expected 0.", __FILE__, __LINE__, gThreadsStarted);
- return;
- }
- umtx_condWait(&gThreadsCountChanged, &gTestMutexA);
- }
-
- while (gThreadsDone < TESTMUTEX_THREAD_COUNT) {
- umtx_condWait(&gThreadsCountChanged, &gTestMutexA);
- }
- umtx_unlock(&gTestMutexA);
-
- for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) {
- threads[i].join();
- }
-}
-
-
//-------------------------------------------------------------------------------------------
//
// TestMultithreadedIntl. Test ICU Formatting in a multi-threaded environment
UnicodeString showDifference(const UnicodeString& expected, const UnicodeString& result)
{
UnicodeString res;
- res = expected + "<Expected\n";
+ res = expected + u"<Expected\n";
if(expected.length() != result.length())
- res += " [ Different lengths ] \n";
+ res += u" [ Different lengths ] \n";
else
{
for(int32_t i=0;i<expected.length();i++)
{
if(expected[i] == result[i])
{
- res += " ";
+ res += u" ";
}
else
{
- res += "|";
+ res += u"|";
}
}
- res += "<Differences";
- res += "\n";
+ res += u"<Differences";
+ res += u"\n";
}
- res += result + "<Result\n";
+ res += result + u"<Result\n";
return res;
}
// "Someone from {2} is receiving a #{0} error - {1}. Their telephone call is costing {3 number,currency}."
static void formatErrorMessage(UErrorCode &realStatus, const UnicodeString& pattern, const Locale& theLocale,
- UErrorCode inStatus0, /* statusString 1 */ const Locale &inCountry2, double currency3, // these numbers are the message arguments.
+ UErrorCode inStatus0, // statusString 1
+ const Locale &inCountry2, double currency3, // these numbers are the message arguments.
UnicodeString &result)
{
if(U_FAILURE(realStatus))
Formattable(currency3)// currency3 {3,number,currency}
};
- MessageFormat *fmt = new MessageFormat("MessageFormat's API is broken!!!!!!!!!!!",realStatus);
- fmt->setLocale(theLocale);
- fmt->applyPattern(pattern, realStatus);
-
+ LocalPointer<MessageFormat> 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;
}
/**
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)) {
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;
// 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);
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;
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;
}
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
UErrorCode threadSafeErr = U_ZERO_ERROR;
ThreadSafeFormatSharedData sharedData(threadSafeErr);
- assertSuccess("initializing ThreadSafeFormat", threadSafeErr, TRUE);
+ assertSuccess(WHERE, threadSafeErr, TRUE);
//
// Create and start the test threads
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) {
noLines(0),
isAtLeastUCA62(TRUE)
{
- };
+ }
void setCollator(Collator *c, Line *l, int32_t nl, UBool atLeastUCA62)
{
coll = c;
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) {
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;
}
// 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;
}
}
int32_t spawnResult = 0;
LocalArray<CollatorThreadTest> 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);
: SimpleThread(),
fTraceInfo(0)
{
- };
+ }
virtual void run()
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;
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) {
for(j=0; j<kStringThreadThreads; j++) {
tests[j].join();
- logln(UnicodeString("Test #") + j + " is complete.. ");
+ logln(UnicodeString(u"Test #") + j + u" is complete.. ");
}
delete StringThreadTest2::gSharedString;
Transliterator *gSharedTranslit = NULL;
class TxThread: public SimpleThread {
public:
- TxThread() {};
+ TxThread() {}
~TxThread();
void run();
};
TxThread::~TxThread() {}
void TxThread::run() {
- UnicodeString greekString("\\u03B4\\u03B9\\u03B1\\u03C6\\u03BF\\u03C1\\u03B5\\u03C4\\u03B9\\u03BA\\u03BF\\u03CD\\u03C2");
- greekString = greekString.unescape();
+ UnicodeString greekString(u"διαφορετικούς");
gSharedTranslit->transliterate(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
#if !UCONFIG_NO_TRANSLITERATION
UErrorCode status = U_ZERO_ERROR;
LocalPointer<Transliterator> 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;
}
-//
-// 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; i<NUMTHREADS; ++i) {
- threads[i] = new CondThread;
- threads[i]->start();
- }
-
- while (gStartedThreads < NUMTHREADS) {
- umtx_condWait(&gCTConditionVar, &gCTMutex);
- }
-
- while (gFinishedThreads < NUMTHREADS) {
- umtx_condWait(&gCTConditionVar, &gCTMutex);
- }
-
- umtx_unlock(&gCTMutex);
-
- for (i=0; i<NUMTHREADS; ++i) {
- if (!threads[i]->fFinished) {
- errln("File %s, Line %d: Error, threads[%d]->fFinished == false", __FILE__, __LINE__, i);
- }
- }
-
- for (i=0; i<NUMTHREADS; ++i) {
- threads[i]->join();
- delete threads[i];
- }
-}
-
//
// Unified Cache Test
U_NAMESPACE_BEGIN
+static std::mutex *gCTMutex = nullptr;
+static std::condition_variable *gCTConditionVar = nullptr;
+
template<> U_EXPORT
const UCTMultiThreadItem *LocaleCacheKey<UCTMultiThreadItem>::createObject(
const void *context, UErrorCode &status) const {
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<std::mutex> 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());
} 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<std::mutex> lock(*gCTMutex);
+ if (!firstObject) {
+ gObjectsCreated += 1;
+ }
+ gCTConditionVar->notify_all();
}
- umtx_condBroadcast(&gCTConditionVar);
- umtx_unlock(&gCTMutex);
return result;
}
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;
fCache->get(
LocaleCacheKey<UCTMultiThreadItem>(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
const UCTMultiThreadItem *item = NULL;
fCache->get(
LocaleCacheKey<UCTMultiThreadItem>(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();
}
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);
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)];
}
- assertEquals("unused values", 2, cache.unusedCount());
+ assertEquals(WHERE, 2, cache.unusedCount());
// clean up threads
for (int32_t i=0; i<CACHE_LOAD; ++i) {
delete threads[i][j];
}
}
+ delete gCTMutex;
+ delete gCTConditionVar;
}
#if !UCONFIG_NO_TRANSLITERATION
class BreakTranslitThread: public SimpleThread {
public:
- BreakTranslitThread() {};
- ~BreakTranslitThread() {};
+ BreakTranslitThread() {}
+ ~BreakTranslitThread() {}
void run();
};
void MultithreadTest::TestBreakTranslit() {
UErrorCode status = U_ZERO_ERROR;
UnicodeString input(
- "\\u0E42\\u0E14\\u0E22\\u0E1E\\u0E37\\u0E49\\u0E19\\u0E10\\u0E32\\u0E19\\u0E41\\u0E25\\u0E49\\u0E27,");
- input = input.unescape();
+ u"\u0E42\u0E14\u0E22\u0E1E\u0E37\u0E49\u0E19\u0E10\u0E32\u0E19\u0E41\u0E25\u0E49\u0E27,");
+ // Thai script, โดยพื้นฐานแล้ว
gTranslitInput = &input;
gSharedTransliterator = Transliterator::createInstance(
- UNICODE_STRING_SIMPLE("Any-Latin; Lower; NFD; [:Diacritic:]Remove; NFC; Latin-ASCII;"), UTRANS_FORWARD, status);
- if (!gSharedTransliterator) {
- return;
- }
- TSMTHREAD_ASSERT_SUCCESS(status);
+ UnicodeString(u"Any-Latin; Lower; NFD; [:Diacritic:]Remove; NFC; Latin-ASCII;"), UTRANS_FORWARD, status);
+ assertSuccess(WHERE, status);
+ if (!assertTrue(WHERE, gSharedTransliterator != nullptr)) {
+ return;
+ }
UnicodeString expected(*gTranslitInput);
gSharedTransliterator->transliterate(expected);
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 */