ICU-4065 Only use usleep from the main thread, since usleep is not thread safe on pre-Solaris 9 machines.
See if that helps, since nanosleep isn't portable among various versions of Solaris. X-SVN-Rev: 16900
This commit is contained in:
parent
13158509da
commit
67f46c57e8
@ -73,6 +73,8 @@
|
||||
|
||||
#include "tsmthred.h"
|
||||
|
||||
#define TSMTHREAD_FAIL(msg) errln("%s at file %s, line %d", msg, __FILE__, __LINE__)
|
||||
#define TSMTHREAD_ASSERT(expr) {if (!(expr)) {TSMTHREAD_FAIL("Fail");}}
|
||||
|
||||
MultithreadTest::MultithreadTest()
|
||||
{
|
||||
@ -564,7 +566,7 @@ void MultithreadTest::TestThreads()
|
||||
if (threads[i]->start() != 0) {
|
||||
errln("Error starting thread %d", i);
|
||||
}
|
||||
SimpleThread::sleep(200);
|
||||
SimpleThread::sleep(100);
|
||||
logln(" Subthread started.");
|
||||
}
|
||||
|
||||
@ -607,98 +609,121 @@ void MultithreadTest::TestThreads()
|
||||
}
|
||||
|
||||
|
||||
class TestMutexThread1 : public SimpleThread
|
||||
//-----------------------------------------------------------------------
|
||||
//
|
||||
// TestMutex - a simple (non-stress) test to verify that ICU mutexes
|
||||
// are actually mutexing. Does not test the use of
|
||||
// mutexes within ICU services, but rather that the
|
||||
// platform's mutex support is at least superficially there.
|
||||
//
|
||||
//----------------------------------------------------------------------
|
||||
static UMTX gTestMutexA = NULL;
|
||||
static UMTX gTestMutexB = NULL;
|
||||
|
||||
static int gThreadsStarted = 0;
|
||||
static int gThreadsInMiddle = 0;
|
||||
static int gThreadsDone = 0;
|
||||
|
||||
static const int TESTMUTEX_THREAD_COUNT = 4;
|
||||
|
||||
static int safeIncr(int &var, int amt) {
|
||||
// Thread safe (using global mutex) increment of a variable.
|
||||
// Return the updated value.
|
||||
// Can also be used as a safe load of a variable by incrementing it by 0.
|
||||
Mutex m;
|
||||
var += amt;
|
||||
return var;
|
||||
}
|
||||
|
||||
class TestMutexThread : public SimpleThread
|
||||
{
|
||||
public:
|
||||
TestMutexThread1() : fDone(FALSE) {}
|
||||
virtual void run()
|
||||
{
|
||||
Mutex m; // grab the lock first thing
|
||||
SimpleThread::sleep(900); // then wait
|
||||
fDone = TRUE; // finally, set our flag
|
||||
// This is the code that each of the spawned threads runs.
|
||||
// All of the spawned threads bunch up together at each of the two mutexes
|
||||
// because the main holds the mutexes until they do.
|
||||
//
|
||||
safeIncr(gThreadsStarted, 1);
|
||||
umtx_lock(&gTestMutexA);
|
||||
umtx_unlock(&gTestMutexA);
|
||||
safeIncr(gThreadsInMiddle, 1);
|
||||
umtx_lock(&gTestMutexB);
|
||||
umtx_unlock(&gTestMutexB);
|
||||
safeIncr(gThreadsDone, 1);
|
||||
}
|
||||
public:
|
||||
UBool fDone;
|
||||
};
|
||||
|
||||
class TestMutexThread2 : public SimpleThread
|
||||
{
|
||||
public:
|
||||
TestMutexThread2(TestMutexThread1& r) : fOtherThread(r), fDone(FALSE), fErr(FALSE) {}
|
||||
virtual void run()
|
||||
{
|
||||
SimpleThread::sleep(500); // wait, make sure they aquire the lock
|
||||
fElapsed = uprv_getUTCtime();
|
||||
{
|
||||
Mutex m; // wait here
|
||||
|
||||
fElapsed = uprv_getUTCtime() - fElapsed;
|
||||
|
||||
if(fOtherThread.fDone == FALSE)
|
||||
fErr = TRUE; // they didnt get to it yet
|
||||
|
||||
fDone = TRUE; // we're done.
|
||||
}
|
||||
}
|
||||
public:
|
||||
TestMutexThread1 & fOtherThread;
|
||||
UBool fDone, fErr;
|
||||
UDate fElapsed;
|
||||
private:
|
||||
/**
|
||||
* The assignment operator has no real implementation.
|
||||
* It is provided to make the compiler happy. Do not call.
|
||||
*/
|
||||
TestMutexThread2& operator=(const TestMutexThread2&) { return *this; }
|
||||
};
|
||||
|
||||
void MultithreadTest::TestMutex()
|
||||
{
|
||||
/* this test uses printf so that we don't hang by calling UnicodeString inside of a mutex. */
|
||||
//logln("Bye.");
|
||||
// printf("Warning: MultiThreadTest::Testmutex() disabled.\n");
|
||||
// return;
|
||||
|
||||
if(verbose)
|
||||
printf("Before mutex.\n");
|
||||
{
|
||||
Mutex m;
|
||||
if(verbose)
|
||||
printf(" Exited 2nd mutex\n");
|
||||
}
|
||||
if(verbose)
|
||||
printf("exited 1st mutex. Now testing with threads:");
|
||||
|
||||
TestMutexThread1 thread1;
|
||||
TestMutexThread2 thread2(thread1);
|
||||
if (thread2.start() != 0 ||
|
||||
thread1.start() != 0 ) {
|
||||
errln("Error starting threads.");
|
||||
// Start up the test threads. They should all pile up waiting on
|
||||
// gTestMutexA, which we (the main thread) hold until the test threads
|
||||
// all get there.
|
||||
gThreadsStarted = 0;
|
||||
gThreadsInMiddle = 0;
|
||||
gThreadsDone = 0;
|
||||
umtx_lock(&gTestMutexA);
|
||||
TestMutexThread *threads[TESTMUTEX_THREAD_COUNT];
|
||||
int i;
|
||||
for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) {
|
||||
threads[i] = new TestMutexThread;
|
||||
threads[i]->start();
|
||||
}
|
||||
|
||||
for(int32_t patience = 12; patience > 0;patience--)
|
||||
{
|
||||
// TODO: Possible memory coherence issue in looking at fDone values
|
||||
// that are set in another thread without the mutex here.
|
||||
if(thread1.fDone && verbose)
|
||||
printf("Thread1 done\n");
|
||||
|
||||
if(thread1.fDone && thread2.fDone)
|
||||
{
|
||||
if(thread2.fErr)
|
||||
errln("Thread 2 says: thread1 didn't run before I aquired the mutex.");
|
||||
logln("took %lu seconds for thread2 to aquire the mutex.", (int)(thread2.fElapsed/U_MILLIS_PER_DAY));
|
||||
int patience = 0;
|
||||
while (safeIncr(gThreadsStarted, 0) != TESTMUTEX_THREAD_COUNT) {
|
||||
if (patience++ > 24) {
|
||||
TSMTHREAD_FAIL("Patience Exceeded");
|
||||
return;
|
||||
}
|
||||
SimpleThread::sleep(1000);
|
||||
SimpleThread::sleep(500);
|
||||
}
|
||||
if(verbose)
|
||||
printf("patience exceeded. [WARNING mutex may still be acquired.] ");
|
||||
// None of the test threads should have advanced past the first mutex.
|
||||
TSMTHREAD_ASSERT(gThreadsInMiddle==0);
|
||||
TSMTHREAD_ASSERT(gThreadsDone==0);
|
||||
|
||||
// All of the test threads have made it to the first mutex.
|
||||
// We (the main thread) now let them advance to the second mutex,
|
||||
// where they should all pile up again.
|
||||
umtx_lock(&gTestMutexB);
|
||||
umtx_unlock(&gTestMutexA);
|
||||
|
||||
patience = 0;
|
||||
while (safeIncr(gThreadsInMiddle, 0) != TESTMUTEX_THREAD_COUNT) {
|
||||
if (patience++ > 24) {
|
||||
TSMTHREAD_FAIL("Patience Exceeded");
|
||||
return;
|
||||
}
|
||||
SimpleThread::sleep(500);
|
||||
}
|
||||
TSMTHREAD_ASSERT(gThreadsDone==0);
|
||||
|
||||
// All test threads made it to the second mutex.
|
||||
// Now let them proceed from there. They will all terminate.
|
||||
umtx_unlock(&gTestMutexB);
|
||||
patience = 0;
|
||||
while (safeIncr(gThreadsDone, 0) != TESTMUTEX_THREAD_COUNT) {
|
||||
if (patience++ > 24) {
|
||||
TSMTHREAD_FAIL("Patience Exceeded");
|
||||
return;
|
||||
}
|
||||
SimpleThread::sleep(500);
|
||||
}
|
||||
|
||||
// All threads made it by both mutexes.
|
||||
// Destroy the test mutexes.
|
||||
umtx_destroy(&gTestMutexA);
|
||||
umtx_destroy(&gTestMutexB);
|
||||
gTestMutexA=NULL;
|
||||
gTestMutexB=NULL;
|
||||
|
||||
for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) {
|
||||
delete threads[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------
|
||||
//
|
||||
// class ThreadWithStatus - a thread that we can check the status and error condition of
|
||||
|
Loading…
Reference in New Issue
Block a user