initial commit
Signed-off-by: Peter Siegmund <mars3142@noreply.mars3142.dev>
This commit is contained in:
172
libs/wxWidgets-3.3.1/tests/thread/atomic.cpp
Normal file
172
libs/wxWidgets-3.3.1/tests/thread/atomic.cpp
Normal file
@@ -0,0 +1,172 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: tests/thread/atomic.cpp
|
||||
// Purpose: wxAtomic??? unit test
|
||||
// Author: Armel Asselin
|
||||
// Created: 2006-12-14
|
||||
// Copyright: (c) 2006 Armel Asselin
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "testprec.h"
|
||||
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#endif // WX_PRECOMP
|
||||
|
||||
#include "wx/atomic.h"
|
||||
#include "wx/thread.h"
|
||||
#include "wx/dynarray.h"
|
||||
#include "wx/log.h"
|
||||
#include "wx/vector.h"
|
||||
|
||||
typedef wxVector<wxThread*> wxArrayThread;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// constants
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static const wxInt32 ITERATIONS_NUM = 10000;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// test helper thread
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
namespace
|
||||
{
|
||||
enum ETestType
|
||||
{
|
||||
IncAndDecMixed,
|
||||
IncOnly,
|
||||
DecOnly
|
||||
};
|
||||
|
||||
class MyThread : public wxThread
|
||||
{
|
||||
public:
|
||||
MyThread(wxAtomicInt &operateOn, ETestType testType) : wxThread(wxTHREAD_JOINABLE),
|
||||
m_operateOn(operateOn), m_testType(testType) {}
|
||||
|
||||
// thread execution starts here
|
||||
virtual void *Entry() override;
|
||||
|
||||
public:
|
||||
wxAtomicInt &m_operateOn;
|
||||
ETestType m_testType;
|
||||
};
|
||||
} // anonymous namespace
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// the tests themselves
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
TEST_CASE("Atomic::NoThread", "[atomic]")
|
||||
{
|
||||
wxAtomicInt int1 = 0,
|
||||
int2 = 0;
|
||||
|
||||
for ( wxInt32 i = 0; i < ITERATIONS_NUM; ++i )
|
||||
{
|
||||
wxAtomicInc(int1);
|
||||
wxAtomicDec(int2);
|
||||
}
|
||||
|
||||
CHECK( int1 == ITERATIONS_NUM );
|
||||
CHECK( int2 == -ITERATIONS_NUM );
|
||||
}
|
||||
|
||||
TEST_CASE("Atomic::ReturnValue", "[atomic]")
|
||||
{
|
||||
wxAtomicInt i(0);
|
||||
REQUIRE( wxAtomicInc(i) == 1 );
|
||||
REQUIRE( wxAtomicInc(i) == 2 );
|
||||
|
||||
REQUIRE( wxAtomicDec(i) == 1 );
|
||||
REQUIRE( wxAtomicDec(i) == 0 );
|
||||
}
|
||||
|
||||
TEST_CASE("Atomic::WithThreads", "[atomic]")
|
||||
{
|
||||
int count wxDUMMY_INITIALIZE(0);
|
||||
ETestType testType wxDUMMY_INITIALIZE(DecOnly);
|
||||
|
||||
SECTION( "2 threads using inc and dec") { count = 2; testType = IncAndDecMixed; }
|
||||
SECTION("10 threads using inc and dec") { count = 10; testType = IncAndDecMixed; }
|
||||
SECTION( "2 threads using inc or dec" ) { count = 2; testType = IncOnly; }
|
||||
SECTION("10 threads using inc or dec" ) { count = 10; testType = IncOnly; }
|
||||
|
||||
wxAtomicInt int1=0;
|
||||
|
||||
wxArrayThread threads;
|
||||
|
||||
int i;
|
||||
for ( i = 0; i < count; ++i )
|
||||
{
|
||||
ETestType actualThreadType;
|
||||
switch(testType)
|
||||
{
|
||||
default:
|
||||
actualThreadType = testType;
|
||||
break;
|
||||
case IncOnly:
|
||||
actualThreadType = (i&1)==0 ? IncOnly : DecOnly;
|
||||
break;
|
||||
}
|
||||
|
||||
MyThread *thread = new MyThread(int1, actualThreadType);
|
||||
|
||||
if ( thread->Create() != wxTHREAD_NO_ERROR )
|
||||
{
|
||||
wxLogError(wxT("Can't create thread!"));
|
||||
delete thread;
|
||||
}
|
||||
else
|
||||
threads.push_back(thread);
|
||||
}
|
||||
|
||||
for ( i = 0; i < count; ++i )
|
||||
{
|
||||
threads[i]->Run();
|
||||
}
|
||||
|
||||
|
||||
for ( i = 0; i < count; ++i )
|
||||
{
|
||||
// each thread should return 0, else it detected some problem
|
||||
CHECK (threads[i]->Wait() == (wxThread::ExitCode)nullptr);
|
||||
delete threads[i];
|
||||
}
|
||||
|
||||
CHECK( int1 == 0 );
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void *MyThread::Entry()
|
||||
{
|
||||
wxInt32 negativeValuesSeen = 0;
|
||||
|
||||
for ( wxInt32 i = 0; i < ITERATIONS_NUM; ++i )
|
||||
{
|
||||
switch ( m_testType )
|
||||
{
|
||||
case IncAndDecMixed:
|
||||
wxAtomicInc(m_operateOn);
|
||||
if ( wxAtomicDec(m_operateOn) < 0 )
|
||||
++negativeValuesSeen;
|
||||
break;
|
||||
|
||||
case IncOnly:
|
||||
wxAtomicInc(m_operateOn);
|
||||
break;
|
||||
|
||||
case DecOnly:
|
||||
wxAtomicDec(m_operateOn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return wxUIntToPtr(negativeValuesSeen);
|
||||
}
|
||||
420
libs/wxWidgets-3.3.1/tests/thread/misc.cpp
Normal file
420
libs/wxWidgets-3.3.1/tests/thread/misc.cpp
Normal file
@@ -0,0 +1,420 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: tests/thread/misc.cpp
|
||||
// Purpose: Miscellaneous wxThread test cases
|
||||
// Author: Francesco Montorsi (extracted from console sample)
|
||||
// Created: 2010-05-10
|
||||
// Copyright: (c) 2010 wxWidgets team
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "testprec.h"
|
||||
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#endif // WX_PRECOMP
|
||||
|
||||
#include "wx/thread.h"
|
||||
#include "wx/utils.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// globals
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static size_t gs_counter = (size_t)-1;
|
||||
static wxCriticalSection gs_critsect;
|
||||
static wxSemaphore gs_cond;
|
||||
|
||||
class MyJoinableThread : public wxThread
|
||||
{
|
||||
public:
|
||||
MyJoinableThread(size_t n) : wxThread(wxTHREAD_JOINABLE)
|
||||
{ m_n = n; Create(); }
|
||||
|
||||
// thread execution starts here
|
||||
virtual ExitCode Entry() override;
|
||||
|
||||
private:
|
||||
size_t m_n;
|
||||
};
|
||||
|
||||
wxThread::ExitCode MyJoinableThread::Entry()
|
||||
{
|
||||
wxUIntPtr res = 1;
|
||||
for ( size_t n = 1; n < m_n; n++ )
|
||||
{
|
||||
res *= n;
|
||||
|
||||
// it's a loooong calculation :-)
|
||||
wxMilliSleep(100);
|
||||
}
|
||||
|
||||
return (ExitCode)res;
|
||||
}
|
||||
|
||||
class MyDetachedThread : public wxThread
|
||||
{
|
||||
public:
|
||||
// If n == 0, thread must be cancelled to exit.
|
||||
MyDetachedThread(size_t n, wxChar ch)
|
||||
{
|
||||
m_n = n;
|
||||
m_ch = ch;
|
||||
m_cancelled = false;
|
||||
|
||||
Create();
|
||||
}
|
||||
|
||||
// thread execution starts here
|
||||
virtual ExitCode Entry() override;
|
||||
|
||||
// and stops here
|
||||
virtual void OnExit() override;
|
||||
|
||||
private:
|
||||
size_t m_n; // number of characters to write
|
||||
wxChar m_ch; // character to write
|
||||
|
||||
bool m_cancelled; // false if we exit normally
|
||||
};
|
||||
|
||||
wxThread::ExitCode MyDetachedThread::Entry()
|
||||
{
|
||||
{
|
||||
wxCriticalSectionLocker lock(gs_critsect);
|
||||
if ( gs_counter == (size_t)-1 )
|
||||
gs_counter = 1;
|
||||
else
|
||||
gs_counter++;
|
||||
}
|
||||
|
||||
for ( size_t n = 0;; n++ )
|
||||
{
|
||||
if ( m_n && n == m_n )
|
||||
break;
|
||||
|
||||
if ( TestDestroy() )
|
||||
{
|
||||
m_cancelled = true;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//wxPutchar(m_ch);
|
||||
//fflush(stdout);
|
||||
|
||||
wxMilliSleep(100);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void MyDetachedThread::OnExit()
|
||||
{
|
||||
//wxLogTrace(wxT("thread"), wxT("Thread %ld is in OnExit"), GetId());
|
||||
|
||||
wxCriticalSectionLocker lock(gs_critsect);
|
||||
if ( !--gs_counter && !m_cancelled )
|
||||
gs_cond.Post();
|
||||
}
|
||||
|
||||
class MyWaitingThread : public wxThread
|
||||
{
|
||||
public:
|
||||
MyWaitingThread( wxMutex *mutex, wxCondition *condition )
|
||||
{
|
||||
m_mutex = mutex;
|
||||
m_condition = condition;
|
||||
|
||||
Create();
|
||||
}
|
||||
|
||||
virtual ExitCode Entry() override
|
||||
{
|
||||
//wxPrintf(wxT("Thread %lu has started running.\n"), GetId());
|
||||
gs_cond.Post();
|
||||
|
||||
//wxPrintf(wxT("Thread %lu starts to wait...\n"), GetId());
|
||||
|
||||
m_mutex->Lock();
|
||||
m_condition->Wait();
|
||||
m_mutex->Unlock();
|
||||
|
||||
//wxPrintf(wxT("Thread %lu finished to wait, exiting.\n"), GetId());
|
||||
gs_cond.Post();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
wxMutex *m_mutex;
|
||||
wxCondition *m_condition;
|
||||
};
|
||||
|
||||
// semaphore tests
|
||||
#include "wx/datetime.h"
|
||||
|
||||
class MySemaphoreThread : public wxThread
|
||||
{
|
||||
public:
|
||||
MySemaphoreThread(int i, wxSemaphore *sem)
|
||||
: wxThread(wxTHREAD_JOINABLE),
|
||||
m_sem(sem),
|
||||
m_i(i)
|
||||
{
|
||||
Create();
|
||||
}
|
||||
|
||||
virtual ExitCode Entry() override
|
||||
{
|
||||
wxUnusedVar(m_i);
|
||||
|
||||
//wxPrintf(wxT("%s: Thread #%d (%ld) starting to wait for semaphore...\n"),
|
||||
// wxDateTime::Now().FormatTime().c_str(), m_i, (long)GetId());
|
||||
|
||||
m_sem->Wait();
|
||||
|
||||
//wxPrintf(wxT("%s: Thread #%d (%ld) acquired the semaphore.\n"),
|
||||
// wxDateTime::Now().FormatTime().c_str(), m_i, (long)GetId());
|
||||
|
||||
Sleep(1000);
|
||||
|
||||
//wxPrintf(wxT("%s: Thread #%d (%ld) releasing the semaphore.\n"),
|
||||
// wxDateTime::Now().FormatTime().c_str(), m_i, (long)GetId());
|
||||
|
||||
m_sem->Post();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
wxSemaphore *m_sem;
|
||||
int m_i;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// test class
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class MiscThreadTestCase : public CppUnit::TestCase
|
||||
{
|
||||
public:
|
||||
MiscThreadTestCase();
|
||||
|
||||
private:
|
||||
CPPUNIT_TEST_SUITE( MiscThreadTestCase );
|
||||
CPPUNIT_TEST( TestJoinable );
|
||||
CPPUNIT_TEST( TestDetached );
|
||||
CPPUNIT_TEST( TestThreadSuspend );
|
||||
CPPUNIT_TEST( TestThreadDelete );
|
||||
CPPUNIT_TEST( TestThreadRun );
|
||||
CPPUNIT_TEST( TestThreadConditions );
|
||||
CPPUNIT_TEST( TestSemaphore );
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
void TestJoinable();
|
||||
void TestDetached();
|
||||
void TestSemaphore();
|
||||
|
||||
void TestThreadSuspend();
|
||||
void TestThreadDelete();
|
||||
void TestThreadRun();
|
||||
void TestThreadConditions();
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(MiscThreadTestCase);
|
||||
};
|
||||
|
||||
// register in the unnamed registry so that these tests are run by default
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION( MiscThreadTestCase );
|
||||
|
||||
// also include in its own registry so that these tests can be run alone
|
||||
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( MiscThreadTestCase, "MiscThreadTestCase" );
|
||||
|
||||
MiscThreadTestCase::MiscThreadTestCase()
|
||||
{
|
||||
int nCPUs = wxThread::GetCPUCount();
|
||||
if ( nCPUs != -1 )
|
||||
wxThread::SetConcurrency(nCPUs);
|
||||
}
|
||||
|
||||
void MiscThreadTestCase::TestJoinable()
|
||||
{
|
||||
// calc 10! in the background
|
||||
MyJoinableThread thread(10);
|
||||
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread.Run() );
|
||||
CPPUNIT_ASSERT_EQUAL( 362880, (wxUIntPtr)thread.Wait() );
|
||||
}
|
||||
|
||||
void MiscThreadTestCase::TestDetached()
|
||||
{
|
||||
static const size_t nThreads = 3;
|
||||
MyDetachedThread *threads[nThreads];
|
||||
|
||||
size_t n;
|
||||
for ( n = 0; n < nThreads; n++ )
|
||||
{
|
||||
threads[n] = new MyDetachedThread(10, 'A' + n);
|
||||
}
|
||||
|
||||
threads[0]->SetPriority(wxPRIORITY_MIN);
|
||||
threads[1]->SetPriority(wxPRIORITY_MAX);
|
||||
|
||||
for ( n = 0; n < nThreads; n++ )
|
||||
{
|
||||
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, threads[n]->Run() );
|
||||
}
|
||||
|
||||
// wait until all threads terminate
|
||||
CPPUNIT_ASSERT_EQUAL( wxSEMA_NO_ERROR, gs_cond.Wait() );
|
||||
}
|
||||
|
||||
void MiscThreadTestCase::TestSemaphore()
|
||||
{
|
||||
static const int SEM_LIMIT = 3;
|
||||
|
||||
wxSemaphore sem(SEM_LIMIT, SEM_LIMIT);
|
||||
std::vector<std::unique_ptr<MySemaphoreThread>> threads;
|
||||
|
||||
for ( int i = 0; i < 3*SEM_LIMIT; i++ )
|
||||
{
|
||||
std::unique_ptr<MySemaphoreThread> t{new MySemaphoreThread(i, &sem)};
|
||||
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, t->Run() );
|
||||
|
||||
threads.push_back(std::move(t));
|
||||
}
|
||||
|
||||
for ( auto& t : threads )
|
||||
{
|
||||
CPPUNIT_ASSERT_EQUAL( 0, (wxUIntPtr)t->Wait() );
|
||||
}
|
||||
}
|
||||
|
||||
void MiscThreadTestCase::TestThreadSuspend()
|
||||
{
|
||||
MyDetachedThread *thread = new MyDetachedThread(15, 'X');
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread->Run() );
|
||||
|
||||
// this is for this demo only, in a real life program we'd use another
|
||||
// condition variable which would be signaled from wxThread::Entry() to
|
||||
// tell us that the thread really started running - but here just wait a
|
||||
// bit and hope that it will be enough (the problem is, of course, that
|
||||
// the thread might still not run when we call Pause() which will result
|
||||
// in an error)
|
||||
wxMilliSleep(300);
|
||||
|
||||
for ( size_t n = 0; n < 3; n++ )
|
||||
{
|
||||
thread->Pause();
|
||||
|
||||
if ( n > 0 )
|
||||
{
|
||||
// don't sleep but resume immediately the first time
|
||||
wxMilliSleep(300);
|
||||
}
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread->Resume() );
|
||||
}
|
||||
|
||||
// wait until the thread terminates
|
||||
CPPUNIT_ASSERT_EQUAL( wxSEMA_NO_ERROR, gs_cond.Wait() );
|
||||
}
|
||||
|
||||
void MiscThreadTestCase::TestThreadDelete()
|
||||
{
|
||||
// Check that deleting a thread which didn't start to run yet returns an
|
||||
// error.
|
||||
MyDetachedThread *thread0 = new MyDetachedThread(0, 'W');
|
||||
CPPUNIT_ASSERT_EQUAL( wxTHREAD_MISC_ERROR, thread0->Delete() );
|
||||
|
||||
// Check that deleting a running thread works.
|
||||
MyDetachedThread *thread1 = new MyDetachedThread(0, 'X');
|
||||
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread1->Run() );
|
||||
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread1->Delete() );
|
||||
|
||||
|
||||
// Create another thread and pause it before deleting.
|
||||
MyDetachedThread *thread2 = new MyDetachedThread(0, 'Z');
|
||||
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread2->Run() );
|
||||
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread2->Pause() );
|
||||
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread2->Delete() );
|
||||
|
||||
|
||||
// Delete a running joinable thread.
|
||||
MyJoinableThread thread3(20);
|
||||
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread3.Run() );
|
||||
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread3.Delete() );
|
||||
|
||||
// Delete a joinable thread which already terminated.
|
||||
MyJoinableThread thread4(2);
|
||||
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread4.Run() );
|
||||
thread4.Wait();
|
||||
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread4.Delete() );
|
||||
}
|
||||
|
||||
void MiscThreadTestCase::TestThreadRun()
|
||||
{
|
||||
MyJoinableThread thread1(2);
|
||||
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread1.Run() );
|
||||
thread1.Wait(); // wait until the thread ends
|
||||
|
||||
// verify that running twice the same thread fails
|
||||
WX_ASSERT_FAILS_WITH_ASSERT( thread1.Run() );
|
||||
}
|
||||
|
||||
void MiscThreadTestCase::TestThreadConditions()
|
||||
{
|
||||
wxMutex mutex;
|
||||
wxCondition condition(mutex);
|
||||
|
||||
// otherwise its difficult to understand which log messages pertain to
|
||||
// which condition
|
||||
//wxLogTrace(wxT("thread"), wxT("Local condition var is %08x, gs_cond = %08x"),
|
||||
// condition.GetId(), gs_cond.GetId());
|
||||
|
||||
// create and launch threads
|
||||
MyWaitingThread *threads[10];
|
||||
|
||||
size_t n;
|
||||
for ( n = 0; n < WXSIZEOF(threads); n++ )
|
||||
{
|
||||
threads[n] = new MyWaitingThread( &mutex, &condition );
|
||||
}
|
||||
|
||||
for ( n = 0; n < WXSIZEOF(threads); n++ )
|
||||
{
|
||||
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, threads[n]->Run() );
|
||||
}
|
||||
|
||||
// wait until all threads run
|
||||
size_t nRunning = 0;
|
||||
while ( nRunning < WXSIZEOF(threads) )
|
||||
{
|
||||
CPPUNIT_ASSERT_EQUAL( wxSEMA_NO_ERROR, gs_cond.Wait() );
|
||||
|
||||
nRunning++;
|
||||
}
|
||||
|
||||
wxMilliSleep(500);
|
||||
|
||||
// now wake one of them up
|
||||
CPPUNIT_ASSERT_EQUAL( wxCOND_NO_ERROR, condition.Signal() );
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL( wxSEMA_NO_ERROR, gs_cond.Wait() );
|
||||
size_t nFinished = 1;
|
||||
|
||||
// wake all the (remaining) threads up, so that they can exit
|
||||
CPPUNIT_ASSERT_EQUAL( wxCOND_NO_ERROR, condition.Broadcast() );
|
||||
|
||||
while ( nFinished < WXSIZEOF(threads) )
|
||||
{
|
||||
CPPUNIT_ASSERT_EQUAL( wxSEMA_NO_ERROR, gs_cond.Wait() );
|
||||
|
||||
nFinished++;
|
||||
}
|
||||
}
|
||||
217
libs/wxWidgets-3.3.1/tests/thread/queue.cpp
Normal file
217
libs/wxWidgets-3.3.1/tests/thread/queue.cpp
Normal file
@@ -0,0 +1,217 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: tests/thread/queue.cpp
|
||||
// Purpose: Unit test for wxMessageQueue
|
||||
// Author: Evgeniy Tarassov
|
||||
// Created: 31/10/2007
|
||||
// Copyright: (c) 2007 Evgeniy Tarassov
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "testprec.h"
|
||||
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/thread.h"
|
||||
#endif // WX_PRECOMP
|
||||
|
||||
#include "wx/msgqueue.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// thread class used in the tests
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
enum WaitTestType
|
||||
{
|
||||
WaitWithTimeout = 0,
|
||||
WaitInfinitlyLong
|
||||
};
|
||||
|
||||
typedef wxMessageQueue<int> Queue;
|
||||
|
||||
// This class represents a thread that waits (following WaitTestType type)
|
||||
// for exactly maxMsgCount messages from its message queue and if another
|
||||
// MyThread is specified, then every message received is posted
|
||||
// to that next thread.
|
||||
class MyThread : public wxThread
|
||||
{
|
||||
public:
|
||||
MyThread(WaitTestType type, MyThread *next, int maxMsgCount)
|
||||
: wxThread(wxTHREAD_JOINABLE),
|
||||
m_type(type), m_nextThread(next), m_maxMsgCount(maxMsgCount)
|
||||
{}
|
||||
|
||||
// thread execution starts here
|
||||
virtual void *Entry() override;
|
||||
|
||||
// Thread message queue
|
||||
Queue& GetQueue()
|
||||
{
|
||||
return m_queue;
|
||||
}
|
||||
|
||||
private:
|
||||
WaitTestType m_type;
|
||||
MyThread* m_nextThread;
|
||||
int m_maxMsgCount;
|
||||
Queue m_queue;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
// this function creates the given number of threads and posts msgCount
|
||||
// messages to the last created thread which, in turn, posts all the messages
|
||||
// it receives to the previously created thread which does the same and so on
|
||||
// in cascade -- at the end, each thread will have received all msgCount
|
||||
// messages directly or indirectly
|
||||
TEST_CASE("wxMessageQueue::Receive", "[msgqueue]")
|
||||
{
|
||||
const int msgCount = 100;
|
||||
const int threadCount = 10;
|
||||
|
||||
std::vector<std::unique_ptr<MyThread>> threads;
|
||||
|
||||
int i;
|
||||
for ( i = 0; i < threadCount; ++i )
|
||||
{
|
||||
MyThread *previousThread = i == 0 ? nullptr : threads[i-1].get();
|
||||
std::unique_ptr<MyThread>
|
||||
thread(new MyThread(WaitInfinitlyLong, previousThread, msgCount));
|
||||
|
||||
CHECK( thread->Create() == wxTHREAD_NO_ERROR );
|
||||
threads.push_back(std::move(thread));
|
||||
}
|
||||
|
||||
for ( i = 0; i < threadCount; ++i )
|
||||
{
|
||||
threads[i]->Run();
|
||||
}
|
||||
|
||||
MyThread* const lastThread = threads[threadCount - 1].get();
|
||||
|
||||
for ( i = 0; i < msgCount; ++i )
|
||||
{
|
||||
lastThread->GetQueue().Post(i);
|
||||
}
|
||||
|
||||
for ( i = 0; i < threadCount; ++i )
|
||||
{
|
||||
// each thread should return the number of messages received.
|
||||
// if it returns a negative, then it detected some problem.
|
||||
wxThread::ExitCode code = threads[i]->Wait();
|
||||
CHECK( code == (wxThread::ExitCode)wxMSGQUEUE_NO_ERROR );
|
||||
}
|
||||
}
|
||||
|
||||
// this function creates two threads, each one waiting (with a timeout) for
|
||||
// exactly two messages.
|
||||
// Exactly to messages are posted into first thread queue, but
|
||||
// only one message is posted to the second thread queue.
|
||||
// Therefore first thread should return with wxMSGQUEUE_NO_ERROR, but the second
|
||||
// should return wxMSGQUEUUE_TIMEOUT.
|
||||
TEST_CASE("wxMessageQueue::ReceiveTimeout", "[msgqueue]")
|
||||
{
|
||||
std::unique_ptr<MyThread> thread1(new MyThread(WaitWithTimeout, nullptr, 2));
|
||||
std::unique_ptr<MyThread> thread2(new MyThread(WaitWithTimeout, nullptr, 2));
|
||||
|
||||
CHECK( thread1->Create() == wxTHREAD_NO_ERROR );
|
||||
CHECK( thread2->Create() == wxTHREAD_NO_ERROR );
|
||||
|
||||
thread1->Run();
|
||||
thread2->Run();
|
||||
|
||||
// Post two messages to the first thread
|
||||
CHECK( thread1->GetQueue().Post(0) == wxMSGQUEUE_NO_ERROR );
|
||||
CHECK( thread1->GetQueue().Post(1) == wxMSGQUEUE_NO_ERROR );
|
||||
|
||||
// ...but only one message to the second
|
||||
CHECK( thread2->GetQueue().Post(0) == wxMSGQUEUE_NO_ERROR );
|
||||
|
||||
wxThread::ExitCode code1 = thread1->Wait();
|
||||
wxThread::ExitCode code2 = thread2->Wait();
|
||||
|
||||
CHECK( code1 == (wxThread::ExitCode)wxMSGQUEUE_NO_ERROR );
|
||||
CHECK( code2 == (wxThread::ExitCode)wxMSGQUEUE_TIMEOUT );
|
||||
}
|
||||
|
||||
// every thread tries to read exactly m_maxMsgCount messages from its queue
|
||||
// following the waiting strategy specified in m_type. If it succeeds then it
|
||||
// returns 0. Otherwise it returns the error code - one of wxMessageQueueError.
|
||||
void *MyThread::Entry()
|
||||
{
|
||||
int messagesReceived = 0;
|
||||
while ( messagesReceived < m_maxMsgCount )
|
||||
{
|
||||
wxMessageQueueError result;
|
||||
int msg = -1; // just to suppress "possibly uninitialized" warnings
|
||||
|
||||
if ( m_type == WaitWithTimeout )
|
||||
result = m_queue.ReceiveTimeout(1000, msg);
|
||||
else
|
||||
result = m_queue.Receive(msg);
|
||||
|
||||
if ( result == wxMSGQUEUE_MISC_ERROR )
|
||||
return (wxThread::ExitCode)wxMSGQUEUE_MISC_ERROR;
|
||||
|
||||
if ( result == wxMSGQUEUE_NO_ERROR )
|
||||
{
|
||||
if ( m_nextThread != nullptr )
|
||||
{
|
||||
wxMessageQueueError res = m_nextThread->GetQueue().Post(msg);
|
||||
|
||||
if ( res == wxMSGQUEUE_MISC_ERROR )
|
||||
return (wxThread::ExitCode)wxMSGQUEUE_MISC_ERROR;
|
||||
|
||||
// We can't use Catch asserts outside of the main thread
|
||||
// currently, unfortunately.
|
||||
wxASSERT( res == wxMSGQUEUE_NO_ERROR );
|
||||
}
|
||||
++messagesReceived;
|
||||
continue;
|
||||
}
|
||||
|
||||
wxASSERT( result == wxMSGQUEUE_TIMEOUT );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if ( messagesReceived != m_maxMsgCount )
|
||||
{
|
||||
wxASSERT( m_type == WaitWithTimeout );
|
||||
|
||||
return (wxThread::ExitCode)wxMSGQUEUE_TIMEOUT;
|
||||
}
|
||||
|
||||
return (wxThread::ExitCode)wxMSGQUEUE_NO_ERROR;
|
||||
}
|
||||
|
||||
TEST_CASE("wxMessageQueue::NonCopyable", "[msgqueue]")
|
||||
{
|
||||
struct NonCopyable
|
||||
{
|
||||
explicit NonCopyable(int n) : m_n(new int(n)) { }
|
||||
|
||||
NonCopyable(NonCopyable&& other) = default;
|
||||
NonCopyable& operator=(NonCopyable&& other) = default;
|
||||
|
||||
std::unique_ptr<int> m_n;
|
||||
};
|
||||
|
||||
wxMessageQueue<NonCopyable> queue;
|
||||
|
||||
NonCopyable nc(17);
|
||||
CHECK( queue.Post(std::move(nc)) == wxMSGQUEUE_NO_ERROR );
|
||||
|
||||
NonCopyable nc2(0);
|
||||
CHECK( queue.Receive(nc2) == wxMSGQUEUE_NO_ERROR );
|
||||
CHECK( *nc2.m_n == 17 );
|
||||
|
||||
CHECK( queue.ReceiveTimeout(0, nc2) == wxMSGQUEUE_TIMEOUT );
|
||||
}
|
||||
125
libs/wxWidgets-3.3.1/tests/thread/tls.cpp
Normal file
125
libs/wxWidgets-3.3.1/tests/thread/tls.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: tests/thread/tls.cpp
|
||||
// Purpose: wxTlsValue unit test
|
||||
// Author: Vadim Zeitlin
|
||||
// Created: 2008-08-28
|
||||
// Copyright: (c) 2008 Vadim Zeitlin
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "testprec.h"
|
||||
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#endif // WX_PRECOMP
|
||||
|
||||
#include "wx/thread.h"
|
||||
#include "wx/tls.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// globals
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// NB: this struct must be a POD, so don't use wxString as its member
|
||||
struct PerThreadData
|
||||
{
|
||||
const char *name;
|
||||
int number;
|
||||
};
|
||||
|
||||
wxTHREAD_SPECIFIC_DECL PerThreadData gs_threadData;
|
||||
wxTHREAD_SPECIFIC_DECL int gs_threadInt;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// test thread
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// this thread arbitrarily modifies all global thread-specific variables to
|
||||
// make sure that the changes in it are not visible from the main thread
|
||||
class TLSTestThread : public wxThread
|
||||
{
|
||||
public:
|
||||
// ctor both creates and starts the thread
|
||||
TLSTestThread() : wxThread(wxTHREAD_JOINABLE) { Create(); Run(); }
|
||||
|
||||
virtual void *Entry() override
|
||||
{
|
||||
gs_threadInt = 17;
|
||||
|
||||
gs_threadData.name = "worker";
|
||||
gs_threadData.number = 2;
|
||||
|
||||
// We can't use Catch asserts outside of the main thread,
|
||||
// unfortunately.
|
||||
wxASSERT( gs_threadData.name == std::string("worker") );
|
||||
wxASSERT( gs_threadData.number == 2 );
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// test class
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class TLSTestCase : public CppUnit::TestCase
|
||||
{
|
||||
public:
|
||||
TLSTestCase() { }
|
||||
|
||||
private:
|
||||
CPPUNIT_TEST_SUITE( TLSTestCase );
|
||||
CPPUNIT_TEST( TestInt );
|
||||
CPPUNIT_TEST( TestStruct );
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
void TestInt();
|
||||
void TestStruct();
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(TLSTestCase);
|
||||
};
|
||||
|
||||
// register in the unnamed registry so that these tests are run by default
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION( TLSTestCase );
|
||||
|
||||
// also include in its own registry so that these tests can be run alone
|
||||
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( TLSTestCase, "TLSTestCase" );
|
||||
|
||||
void TLSTestCase::TestInt()
|
||||
{
|
||||
CPPUNIT_ASSERT_EQUAL( 0, gs_threadInt );
|
||||
|
||||
gs_threadInt++;
|
||||
CPPUNIT_ASSERT_EQUAL( 1, gs_threadInt );
|
||||
|
||||
TLSTestThread().Wait();
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL( 1, gs_threadInt );
|
||||
}
|
||||
|
||||
void TLSTestCase::TestStruct()
|
||||
{
|
||||
CPPUNIT_ASSERT_EQUAL( nullptr, gs_threadData.name );
|
||||
CPPUNIT_ASSERT_EQUAL( 0, gs_threadData.number );
|
||||
|
||||
gs_threadData.name = "main";
|
||||
gs_threadData.number = 1;
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL( 1, gs_threadData.number );
|
||||
|
||||
TLSTestThread().Wait();
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL( std::string("main"), gs_threadData.name );
|
||||
CPPUNIT_ASSERT_EQUAL( 1, gs_threadData.number );
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user