/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #ifdef _WIN32 #if !defined WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN #endif #include #else #include #include #endif // include files #include #include #include #include #include #include #include #include #include #include #include #define t_print printf using namespace osl; namespace { // Small stopwatch class StopWatch { TimeValue t1,t2; // Start and stoptime protected: sal_Int32 m_nNanoSec; sal_Int32 m_nSeconds; bool m_bIsValid; // TRUE, when started and stopped bool m_bIsRunning; // TRUE, when started public: StopWatch(); void start(); // Starts time void stop(); // Stops time double getSeconds() const; double getTenthSec() const; }; } // ================================= Stop Watch ================================= // A small stopwatch for internal use // (c) Lars Langhans 29.12.1996 22:10 StopWatch::StopWatch() : m_nNanoSec(0) , m_nSeconds(0) , m_bIsValid(false) , m_bIsRunning(false) { t1.Seconds = 0; t1.Nanosec = 0; t2.Seconds = 0; t2.Nanosec = 0; } void StopWatch::start() { // pre: % // post: Start Timer m_bIsValid = false; m_bIsRunning = true; osl_getSystemTime( &t1 ); t_print("# %u %u nsecs\n", static_cast(t1.Seconds), static_cast(t1.Nanosec)); // gettimeofday(&t1, 0); } void StopWatch::stop() { // pre: Timer should be started // post: Timer will stopped osl_getSystemTime( &t2 ); t_print("# %u %u nsecs\n", static_cast(t2.Seconds), static_cast(t2.Nanosec)); if (m_bIsRunning) { // check if started. m_nSeconds = static_cast(t2.Seconds) - static_cast(t1.Seconds); if ( t2.Nanosec > t1.Nanosec ) m_nNanoSec = static_cast(t2.Nanosec) - static_cast(t1.Nanosec); else { m_nNanoSec = 1000000000 + static_cast(t2.Nanosec) - static_cast(t1.Nanosec); m_nSeconds -= 1; } t_print("# %u %u nsecs\n", static_cast(m_nSeconds), static_cast(m_nNanoSec) ); m_bIsValid = true; m_bIsRunning = false; } } double StopWatch::getSeconds() const { // pre: valid = TRUE // BACK: time in seconds double nValue = 0.0; if (m_bIsValid) { nValue = double(m_nNanoSec) / 1000000000.0 + m_nSeconds; // milli micro nano } return nValue; } double StopWatch::getTenthSec() const { double nValue = 0.0; if (m_bIsValid) { nValue = double(m_nNanoSec) / 100000000.0 + m_nSeconds * 10; } return nValue ; } namespace { template class ThreadSafeValue { T m_nFlag; Mutex m_aMutex; public: explicit ThreadSafeValue(T n = 0): m_nFlag(n) {} T getValue() { //block if already acquired by another thread. osl::MutexGuard g(m_aMutex); return m_nFlag; } void incValue() { //only one thread operate on the flag. osl::MutexGuard g(m_aMutex); m_nFlag++; } void acquire() {m_aMutex.acquire();} void release() {m_aMutex.release();} }; } namespace ThreadHelper { static void thread_sleep_tenth_sec(sal_Int32 _nTenthSec) { osl::Thread::wait(std::chrono::milliseconds(_nTenthSec * 100)); } static void outputPriority(oslThreadPriority const& _aPriority) { // LLA: output the priority if (_aPriority == osl_Thread_PriorityHighest) { t_print("Prio is High\n"); } else if (_aPriority == osl_Thread_PriorityAboveNormal) { t_print("Prio is above normal\n"); } else if (_aPriority == osl_Thread_PriorityNormal) { t_print("Prio is normal\n"); } else if (_aPriority == osl_Thread_PriorityBelowNormal) { t_print("Prio is below normal\n"); } else if (_aPriority == osl_Thread_PriorityLowest) { t_print("Prio is lowest\n"); } else { t_print("Prio is unknown\n"); } } } namespace { /** Simple thread for testing Thread-create. Just add 1 of value 0, and after running, result is 1. */ class myThread : public Thread { ThreadSafeValue m_aFlag; public: sal_Int32 getValue() { return m_aFlag.getValue(); } protected: /** guarded value which initialized 0 @see ThreadSafeValue */ void SAL_CALL run() override { while(schedule()) { m_aFlag.incValue(); ThreadHelper::thread_sleep_tenth_sec(1); } } public: virtual void SAL_CALL suspend() override { m_aFlag.acquire(); ::osl::Thread::suspend(); m_aFlag.release(); } virtual ~myThread() override { if (isRunning()) { t_print("error: not terminated.\n"); } } }; /** Thread which has a flag add 1 every second until 20 */ class OCountThread : public Thread { ThreadSafeValue m_aFlag; public: OCountThread() : m_nWaitSec(0) { t_print("new OCountThread thread %u!\n", static_cast(getIdentifier())); } sal_Int32 getValue() { return m_aFlag.getValue(); } void setWait(sal_Int32 nSec) { m_nWaitSec = nSec; //m_bWait = sal_True; } virtual void SAL_CALL suspend() override { m_aFlag.acquire(); ::osl::Thread::suspend(); m_aFlag.release(); } protected: //sal_Bool m_bWait; sal_Int32 m_nWaitSec; void SAL_CALL run() override { /// if the thread should terminate, schedule return false while (m_aFlag.getValue() < 20 && schedule()) { m_aFlag.incValue(); ThreadHelper::thread_sleep_tenth_sec(1); if (m_nWaitSec != 0) { TimeValue nTV; nTV.Seconds = m_nWaitSec / 10 ; nTV.Nanosec = ( m_nWaitSec%10 ) * 100000000 ; wait( nTV ); m_nWaitSec = 0; } } } void SAL_CALL onTerminated() override { t_print("normally terminate this thread %u!\n", static_cast(getIdentifier())); } public: virtual ~OCountThread() override { if (isRunning()) { t_print("error: not terminated.\n"); } } }; /** no call schedule in the run method */ class ONoScheduleThread : public Thread { ThreadSafeValue m_aFlag; public: sal_Int32 getValue() { return m_aFlag.getValue(); } virtual void SAL_CALL suspend() override { m_aFlag.acquire(); ::osl::Thread::suspend(); m_aFlag.release(); } protected: void SAL_CALL run() override { while (m_aFlag.getValue() < 10) { m_aFlag.incValue(); ThreadHelper::thread_sleep_tenth_sec(1); } } void SAL_CALL onTerminated() override { t_print("normally terminate this thread %u!\n", static_cast(getIdentifier())); } public: ONoScheduleThread() { t_print("new thread id %u!\n", static_cast(getIdentifier())); } virtual ~ONoScheduleThread() override { if (isRunning()) { t_print("error: not terminated.\n"); } } }; class OAddThread : public Thread { ThreadSafeValue m_aFlag; public: //oslThreadIdentifier m_id, m_CurId; OAddThread(){} sal_Int32 getValue() { return m_aFlag.getValue(); } virtual void SAL_CALL suspend() override { m_aFlag.acquire(); ::osl::Thread::suspend(); m_aFlag.release(); } protected: void SAL_CALL run() override { //if the thread should terminate, schedule return false while (schedule()) { m_aFlag.incValue(); } } void SAL_CALL onTerminated() override { // t_print("normally terminate this thread %d!\n", getIdentifier()); } public: virtual ~OAddThread() override { if (isRunning()) { // t_print("error: not terminated.\n"); } } }; } namespace osl_Thread { static void resumeAndWaitThread(Thread* _pThread) { // This function starts a thread, wait a second and suspends the thread // Due to the fact, that a suspend and never run thread never really exists. // Note: on UNX, after createSuspended, and then terminate the thread, it performs well; // while on Windows, after createSuspended, the thread can not terminate, wait endlessly, // so here call resume at first, then call terminate. #ifdef _WIN32 t_print("resumeAndWaitThread\n"); _pThread->resume(); ThreadHelper::thread_sleep_tenth_sec(1); #else _pThread->resume(); #endif } // kill a running thread and join it, if it has terminated, do nothing static void termAndJoinThread(Thread* _pThread) { _pThread->terminate(); // LLA: Windows feature???, a suspended thread can not terminated, so we have to weak it up #ifdef _WIN32 _pThread->resume(); ThreadHelper::thread_sleep_tenth_sec(1); #endif t_print("#wait for join.\n"); _pThread->join(); } /** Test of the osl::Thread::create method */ class create : public CppUnit::TestFixture { public: /** Simple create a thread. Create a simple thread, it just does add 1 to value(which initialized 0), if the thread run, the value should be 1. */ void create_001() { myThread* newthread = new myThread; bool bRes = newthread->create(); CPPUNIT_ASSERT_MESSAGE("Can not creates a new thread!\n", bRes); ThreadHelper::thread_sleep_tenth_sec(1); // wait short bool isRunning = newthread->isRunning(); // check if thread is running /// wait for the new thread to assure it has run ThreadHelper::thread_sleep_tenth_sec(3); sal_Int32 nValue = newthread->getValue(); /// to assure the new thread has terminated termAndJoinThread(newthread); delete newthread; t_print(" nValue = %d\n", static_cast(nValue)); t_print("isRunning = %s\n", isRunning ? "true" : "false"); CPPUNIT_ASSERT_MESSAGE( "Creates a new thread", nValue >= 1 ); CPPUNIT_ASSERT_MESSAGE( "Creates a new thread", isRunning ); } /** only one running thread per instance, return false if create secondly */ void create_002() { myThread* newthread = new myThread; bool res1 = newthread->create(); bool res2 = newthread->create(); t_print("In non pro, an assertion should occurred. This behaviour is right.\n"); termAndJoinThread(newthread); delete newthread; CPPUNIT_ASSERT_MESSAGE( "Creates a new thread: can not create two threads per instance", res1 ); CPPUNIT_ASSERT_MESSAGE( "Creates a new thread: can not create two threads per instance", !res2 ); } CPPUNIT_TEST_SUITE(create); CPPUNIT_TEST(create_001); CPPUNIT_TEST(create_002); CPPUNIT_TEST_SUITE_END(); }; // class create /** Test of the osl::Thread::createSuspended method */ class createSuspended : public CppUnit::TestFixture { public: /** Create a suspended thread, use the same class as create_001 after create, wait enough time, check the value, if it's still the initial value, pass */ void createSuspended_001() { myThread* newthread = new myThread; bool bRes = newthread->createSuspended(); CPPUNIT_ASSERT_MESSAGE("Can not creates a new thread!", bRes); ThreadHelper::thread_sleep_tenth_sec(1); bool isRunning = newthread->isRunning(); ThreadHelper::thread_sleep_tenth_sec(3); sal_Int32 nValue = newthread->getValue(); resumeAndWaitThread(newthread); termAndJoinThread(newthread); delete newthread; CPPUNIT_ASSERT_EQUAL_MESSAGE( "Creates a new suspended thread", sal_Int32(0), nValue ); CPPUNIT_ASSERT_MESSAGE( "Creates a new suspended thread", isRunning ); } void createSuspended_002() { myThread* newthread = new myThread; bool res1 = newthread->createSuspended(); bool res2 = newthread->createSuspended(); resumeAndWaitThread(newthread); termAndJoinThread(newthread); delete newthread; CPPUNIT_ASSERT_MESSAGE( "Creates a new thread: can not create two threads per instance", res1 ); CPPUNIT_ASSERT_MESSAGE( "Creates a new thread: can not create two threads per instance", !res2 ); } CPPUNIT_TEST_SUITE(createSuspended); CPPUNIT_TEST(createSuspended_001); // LLA: Deadlocked!!! CPPUNIT_TEST(createSuspended_002); CPPUNIT_TEST_SUITE_END(); }; // class createSuspended /** when the count value equal to or more than 3, suspend the thread. */ static void suspendCountThread(OCountThread* _pCountThread) { sal_Int32 nValue = 0; while (true) { nValue = _pCountThread->getValue(); if (nValue >= 3) { _pCountThread->suspend(); break; } } } /** Test of the osl::Thread::suspend method */ class suspend : public CppUnit::TestFixture { public: /** Use a thread which has a flag added 1 every second ALGORITHM: create the thread, after running special time, record value of flag, then suspend it, wait a long time, check the flag, if it remains unchanged during suspending */ void suspend_001() { OCountThread* aCountThread = new OCountThread(); bool bRes = aCountThread->create(); CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes ); // the thread run for some seconds, but not terminate suspendCountThread( aCountThread ); // the value just after calling suspend sal_Int32 nValue = aCountThread->getValue(); // (2) ThreadHelper::thread_sleep_tenth_sec(3); // the value after waiting 3 seconds sal_Int32 nLaterValue = aCountThread->getValue(); // (3) resumeAndWaitThread(aCountThread); termAndJoinThread(aCountThread); delete aCountThread; CPPUNIT_ASSERT_MESSAGE( "Suspend the thread", bRes ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Suspend the thread", nValue, nLaterValue ); } CPPUNIT_TEST_SUITE(suspend); CPPUNIT_TEST(suspend_001); // LLA: Deadlocked!!! // CPPUNIT_TEST(createSuspended_002); CPPUNIT_TEST_SUITE_END(); }; // class suspend /** Test of the osl::Thread::resume method */ class resume : public CppUnit::TestFixture { public: /** check if the thread run samely as usual after suspend and resume ALGORITHM: compare the values before and after suspend, they should be same, then compare values before and after resume, the difference should be same as the sleep seconds number */ void resume_001() { OCountThread* pCountThread = new OCountThread(); bool bRes = pCountThread->create(); CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes ); suspendCountThread(pCountThread); sal_Int32 nSuspendValue = pCountThread->getValue(); // (2) // suspend for 3 seconds ThreadHelper::thread_sleep_tenth_sec(3); pCountThread->resume(); ThreadHelper::thread_sleep_tenth_sec(3); sal_Int32 nResumeValue = pCountThread->getValue(); ThreadHelper::thread_sleep_tenth_sec(3); sal_Int32 nLaterValue = pCountThread->getValue(); termAndJoinThread(pCountThread); delete pCountThread; t_print("SuspendValue: %d\n", static_cast(nSuspendValue)); t_print("ResumeValue: %d\n", static_cast(nResumeValue)); t_print("LaterValue: %d\n", static_cast(nLaterValue)); /* LLA: this assumption is no longer relevant: nResumeValue == nSuspendValue && */ CPPUNIT_ASSERT_MESSAGE( "Suspend then resume the thread", nLaterValue >= 9 ); CPPUNIT_ASSERT_MESSAGE( "Suspend then resume the thread", nResumeValue > nSuspendValue ); CPPUNIT_ASSERT_MESSAGE( "Suspend then resume the thread", nLaterValue > nResumeValue ); } /** Create a suspended thread then resume, check if the thread has run */ void resume_002() { myThread* newthread = new myThread; bool bRes = newthread->createSuspended(); CPPUNIT_ASSERT_MESSAGE ( "Can't create thread!", bRes ); newthread->resume(); ThreadHelper::thread_sleep_tenth_sec(2); sal_Int32 nValue = newthread->getValue(); termAndJoinThread(newthread); delete newthread; t_print(" nValue = %d\n", static_cast(nValue)); CPPUNIT_ASSERT_MESSAGE( "Creates a suspended thread, then resume", nValue >= 1 ); } CPPUNIT_TEST_SUITE(resume); CPPUNIT_TEST(resume_001); CPPUNIT_TEST(resume_002); CPPUNIT_TEST_SUITE_END(); }; // class resume /** Test of the osl::Thread::terminate method */ class terminate : public CppUnit::TestFixture { public: /** Check after call terminate if the running thread running go on executing ALGORITHM: before and after call terminate, the values should be the same */ void terminate_001() { OCountThread* aCountThread = new OCountThread(); bool bRes = aCountThread->create(); CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes ); ThreadHelper::thread_sleep_tenth_sec(2); sal_Int32 nValue = aCountThread->getValue(); aCountThread->terminate(); ThreadHelper::thread_sleep_tenth_sec(2); sal_Int32 nLaterValue = aCountThread->getValue(); // isRunning should be false after terminate bool isRunning = aCountThread->isRunning(); aCountThread->join(); delete aCountThread; t_print(" nValue = %d\n", static_cast(nValue)); t_print("nLaterValue = %d\n", static_cast(nLaterValue)); CPPUNIT_ASSERT_MESSAGE( "Terminate the thread", !isRunning ); CPPUNIT_ASSERT_MESSAGE( "Terminate the thread", nLaterValue >= nValue ); } /** Check if a suspended thread will terminate after call terminate, different on w32 and on UNX */ void terminate_002() { OCountThread* aCountThread = new OCountThread(); bool bRes = aCountThread->create(); CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes ); ThreadHelper::thread_sleep_tenth_sec(1); suspendCountThread(aCountThread); sal_Int32 nValue = aCountThread->getValue(); // seems a suspended thread can not be terminated on W32, while on Solaris can resumeAndWaitThread(aCountThread); ThreadHelper::thread_sleep_tenth_sec(2); termAndJoinThread(aCountThread); sal_Int32 nLaterValue = aCountThread->getValue(); delete aCountThread; t_print(" nValue = %d\n", static_cast(nValue)); t_print("nLaterValue = %d\n", static_cast(nLaterValue)); CPPUNIT_ASSERT_MESSAGE( "Suspend then resume the thread", nLaterValue > nValue ); } CPPUNIT_TEST_SUITE(terminate); CPPUNIT_TEST(terminate_001); CPPUNIT_TEST(terminate_002); CPPUNIT_TEST_SUITE_END(); }; // class terminate /** Test of the osl::Thread::join method */ class join : public CppUnit::TestFixture { public: /** Check after call terminate if the thread running function will not go on executing the next statement after join will not exec before the thread terminates ALGORITHM: recode system time at the beginning of the thread run, call join, then record system time again, the difference of the two times should be equal or more than 20 seconds, the CountThread normally terminates */ void join_001() { OCountThread *aCountThread = new OCountThread(); bool bRes = aCountThread->create(); CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes ); StopWatch aStopWatch; aStopWatch.start(); // TimeValue aTimeVal_befor; // osl_getSystemTime( &aTimeVal_befor ); //t_print("#join:the system time is %d,%d\n", pTimeVal_befor->Seconds,pTimeVal_befor->Nanosec); aCountThread->join(); //the below line will be executed after aCountThread terminate // TimeValue aTimeVal_after; // osl_getSystemTime( &aTimeVal_after ); aStopWatch.stop(); // sal_uInt32 nSec = aTimeVal_after.Seconds - aTimeVal_befor.Seconds; double nSec = aStopWatch.getSeconds(); t_print("join_001 nSec=%f\n", nSec); delete aCountThread; CPPUNIT_ASSERT_MESSAGE( "Join the thread: after the thread terminate", nSec >= 2 ); } /** after terminated by another thread, join exited immediately ALGORITHM: terminate the thread when value>=3, call join, check the beginning time and time after join, the difference should be 3 seconds, join costs little time */ void join_002() { OCountThread *aCountThread = new OCountThread(); bool bRes = aCountThread->create(); CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes ); //record the time when the running begin // TimeValue aTimeVal_befor; // osl_getSystemTime( &aTimeVal_befor ); StopWatch aStopWatch; aStopWatch.start(); ThreadHelper::thread_sleep_tenth_sec(10); termAndJoinThread(aCountThread); //the below line will be executed after aCountThread terminate // TimeValue aTimeVal_after; // osl_getSystemTime( &aTimeVal_after ); // sal_uInt32 nSec = aTimeVal_after.Seconds - aTimeVal_befor.Seconds; aStopWatch.stop(); double nSec = aStopWatch.getSeconds(); t_print("join_002 nSec=%f\n", nSec); delete aCountThread; CPPUNIT_ASSERT_MESSAGE( "Join the thread: after thread terminate by another thread", nSec >= 1 ); } CPPUNIT_TEST_SUITE(join); CPPUNIT_TEST(join_001); CPPUNIT_TEST(join_002); CPPUNIT_TEST_SUITE_END(); }; // class join /** Test of the osl::Thread::isRunning method */ class isRunning : public CppUnit::TestFixture { public: void isRunning_001() { OCountThread *aCountThread = new OCountThread(); bool bRes = aCountThread->create(); CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes ); bool bRun = aCountThread->isRunning(); ThreadHelper::thread_sleep_tenth_sec(2); termAndJoinThread(aCountThread); bool bTer = aCountThread->isRunning(); delete aCountThread; CPPUNIT_ASSERT_MESSAGE( "Test isRunning", bRun ); CPPUNIT_ASSERT_MESSAGE( "Test isRunning", !bTer ); } /** check the value of isRunning when suspending and after resume */ void isRunning_002() { OCountThread *aCountThread = new OCountThread(); bool bRes = aCountThread->create(); CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes ); // sal_Bool bRunning = aCountThread->isRunning(); // sal_Int32 nValue = 0; suspendCountThread(aCountThread); bool bRunning_sup = aCountThread->isRunning(); ThreadHelper::thread_sleep_tenth_sec(2); aCountThread->resume(); ThreadHelper::thread_sleep_tenth_sec(2); bool bRunning_res = aCountThread->isRunning(); termAndJoinThread(aCountThread); bool bRunning_ter = aCountThread->isRunning(); delete aCountThread; CPPUNIT_ASSERT_MESSAGE( "Test isRunning", bRes && bRunning_sup ); CPPUNIT_ASSERT_MESSAGE( "Test isRunning", bRunning_res ); CPPUNIT_ASSERT_MESSAGE( "Test isRunning", !bRunning_ter ); } CPPUNIT_TEST_SUITE(isRunning); CPPUNIT_TEST(isRunning_001); CPPUNIT_TEST(isRunning_002); CPPUNIT_TEST_SUITE_END(); }; // class isRunning /// check osl::Thread::setPriority class setPriority : public CppUnit::TestFixture { public: // insert your test code here. OString getPrioName(oslThreadPriority _aPriority) { OString sPrioStr; switch (_aPriority) { case osl_Thread_PriorityHighest: sPrioStr = "Highest"; break; case osl_Thread_PriorityAboveNormal: sPrioStr = "AboveNormal"; break; case osl_Thread_PriorityNormal: sPrioStr = "Normal"; break; case osl_Thread_PriorityBelowNormal: sPrioStr = "BelowNormal"; break; case osl_Thread_PriorityLowest: sPrioStr = "Lowest"; break; default: sPrioStr = "unknown"; } return sPrioStr; } /** check 2 threads. ALGORITHM: Here the function should show, that 2 different threads, which only increase a value, should run at the same time with same prio. The test fails, if the difference between the two values is more than 5% but IMHO this isn't a failure, it's only a feature of the OS. */ void check2Threads(oslThreadPriority _aPriority) { // initial 5 threads with different priorities OAddThread* pThread = new OAddThread(); OAddThread* p2Thread = new OAddThread(); //Create them and start running at the same time pThread->create(); pThread->setPriority(_aPriority); p2Thread->create(); p2Thread->setPriority(_aPriority); ThreadHelper::thread_sleep_tenth_sec(5); pThread->terminate(); p2Thread->terminate(); sal_Int32 nValueNormal = pThread->getValue(); sal_Int32 nValueNormal2 = p2Thread->getValue(); OString sPrio = getPrioName(_aPriority); t_print("After 10 tenth seconds\n"); t_print("nValue in %s Prio Thread is %d\n",sPrio.getStr(), static_cast(nValueNormal)); t_print("nValue in %s Prio Thread is %d\n", sPrio.getStr(), static_cast(nValueNormal2)); // ThreadHelper::thread_sleep_tenth_sec(1); pThread->join(); p2Thread->join(); delete pThread; delete p2Thread; sal_Int32 nDelta = abs(nValueNormal - nValueNormal2); double nQuotient = std::max(nValueNormal, nValueNormal2); CPPUNIT_ASSERT_MESSAGE( "Quotient is zero, which means, there exist no right values.", nQuotient != 0 ); double nDeltaPercent = nDelta / nQuotient * 100; t_print("Delta value %d, percent %f\n", static_cast(nDelta), nDeltaPercent); // LLA: it's not a bug if the current OS is not able to handle thread scheduling right and good. // like Windows XP // LLA: CPPUNIT_ASSERT_MESSAGE( // LLA: "Run 2 normal threads, the count diff more than 5 percent.", // LLA: nDeltaPercent <= 5 // LLA: ); } void setPriority_001_1() { check2Threads(osl_Thread_PriorityHighest); } void setPriority_001_2() { check2Threads(osl_Thread_PriorityAboveNormal); } void setPriority_001_3() { check2Threads(osl_Thread_PriorityNormal); } void setPriority_001_4() { check2Threads(osl_Thread_PriorityBelowNormal); } void setPriority_001_5() { check2Threads(osl_Thread_PriorityLowest); } void setPriority_002() { // initial 5 threads with different priorities OAddThread aHighestThread; OAddThread aAboveNormalThread; OAddThread aNormalThread; //OAddThread *aBelowNormalThread = new OAddThread(); //OAddThread *aLowestThread = new OAddThread(); //Create them and start running at the same time aHighestThread.createSuspended(); aHighestThread.setPriority(osl_Thread_PriorityHighest); aAboveNormalThread.createSuspended(); aAboveNormalThread.setPriority(osl_Thread_PriorityAboveNormal); aNormalThread.createSuspended(); aNormalThread.setPriority(osl_Thread_PriorityNormal); /*aBelowNormalThread->create(); aBelowNormalThread->setPriority(osl_Thread_PriorityBelowNormal); aLowestThread->create(); aLowestThread->setPriority(osl_Thread_PriorityLowest); */ aHighestThread.resume(); aAboveNormalThread.resume(); aNormalThread.resume(); ThreadHelper::thread_sleep_tenth_sec(5); aHighestThread.suspend(); aAboveNormalThread.suspend(); aNormalThread.suspend(); termAndJoinThread(&aNormalThread); termAndJoinThread(&aAboveNormalThread); termAndJoinThread(&aHighestThread); //aBelowNormalThread->terminate(); //aLowestThread->terminate(); sal_Int32 nValueHighest = aHighestThread.getValue(); sal_Int32 nValueAboveNormal = aAboveNormalThread.getValue(); sal_Int32 nValueNormal = aNormalThread.getValue(); t_print("After 10 tenth seconds\n"); t_print("nValue in Highest Prio Thread is %d\n", static_cast(nValueHighest)); t_print("nValue in AboveNormal Prio Thread is %d\n", static_cast(nValueAboveNormal)); t_print("nValue in Normal Prio Thread is %d\n", static_cast(nValueNormal)); #ifndef _WIN32 CPPUNIT_ASSERT_MESSAGE( "SetPriority", nValueHighest > 0 ); CPPUNIT_ASSERT_MESSAGE( "SetPriority", nValueAboveNormal > 0 ); CPPUNIT_ASSERT_MESSAGE( "SetPriority", nValueNormal > 0 ); #endif } void setPriority_003() { // initial 5 threads with different priorities OAddThread pHighestThread; OAddThread pAboveNormalThread; OAddThread pNormalThread; OAddThread pBelowNormalThread; OAddThread pLowestThread; //Create them and start running at the same time pHighestThread.createSuspended(); pHighestThread.setPriority(osl_Thread_PriorityHighest); pAboveNormalThread.createSuspended(); pAboveNormalThread.setPriority(osl_Thread_PriorityAboveNormal); pNormalThread.createSuspended(); pNormalThread.setPriority(osl_Thread_PriorityNormal); pBelowNormalThread.createSuspended(); pBelowNormalThread.setPriority(osl_Thread_PriorityBelowNormal); pLowestThread.createSuspended(); pLowestThread.setPriority(osl_Thread_PriorityLowest); pHighestThread.resume(); pAboveNormalThread.resume(); pNormalThread.resume(); pBelowNormalThread.resume(); pLowestThread.resume(); ThreadHelper::thread_sleep_tenth_sec(5); pHighestThread.suspend(); pAboveNormalThread.suspend(); pNormalThread.suspend(); pBelowNormalThread.suspend(); pLowestThread.suspend(); termAndJoinThread(&pHighestThread); termAndJoinThread(&pAboveNormalThread); termAndJoinThread(&pNormalThread); termAndJoinThread(&pBelowNormalThread); termAndJoinThread(&pLowestThread); sal_Int32 nValueHighest = pHighestThread.getValue(); sal_Int32 nValueAboveNormal = pAboveNormalThread.getValue(); sal_Int32 nValueNormal = pNormalThread.getValue(); sal_Int32 nValueBelowNormal = pBelowNormalThread.getValue(); sal_Int32 nValueLowest = pLowestThread.getValue(); t_print("After 10 tenth seconds\n"); t_print("nValue in Highest Prio Thread is %d\n", static_cast(nValueHighest)); t_print("nValue in AboveNormal Prio Thread is %d\n", static_cast(nValueAboveNormal)); t_print("nValue in Normal Prio Thread is %d\n", static_cast(nValueNormal)); t_print("nValue in BelowNormal Prio Thread is %d\n", static_cast(nValueBelowNormal)); t_print("nValue in Lowest Prio Thread is %d\n", static_cast(nValueLowest)); #ifndef _WIN32 CPPUNIT_ASSERT_MESSAGE( "SetPriority", nValueHighest > 0 && nValueAboveNormal > 0 && nValueNormal > 0 ); CPPUNIT_ASSERT_MESSAGE( "SetPriority", nValueBelowNormal > 0 ); CPPUNIT_ASSERT_MESSAGE( "SetPriority", nValueLowest > 0 ); #endif } void setPriority_004() { // initial 5 threads with different priorities // OAddThread *pHighestThread = new OAddThread(); OAddThread pAboveNormalThread; OAddThread pNormalThread; OAddThread pBelowNormalThread; OAddThread pLowestThread; //Create them and start running at the same time // pHighestThread->createSuspended(); // pHighestThread->setPriority(osl_Thread_PriorityHighest); pAboveNormalThread.createSuspended(); pAboveNormalThread.setPriority(osl_Thread_PriorityAboveNormal); pNormalThread.createSuspended(); pNormalThread.setPriority(osl_Thread_PriorityNormal); pBelowNormalThread.createSuspended(); pBelowNormalThread.setPriority(osl_Thread_PriorityBelowNormal); pLowestThread.createSuspended(); pLowestThread.setPriority(osl_Thread_PriorityLowest); // pHighestThread->resume(); pAboveNormalThread.resume(); pNormalThread.resume(); pBelowNormalThread.resume(); pLowestThread.resume(); ThreadHelper::thread_sleep_tenth_sec(5); // pHighestThread->suspend(); pAboveNormalThread.suspend(); pNormalThread.suspend(); pBelowNormalThread.suspend(); pLowestThread.suspend(); // termAndJoinThread(pHighestThread); termAndJoinThread(&pAboveNormalThread); termAndJoinThread(&pNormalThread); termAndJoinThread(&pBelowNormalThread); termAndJoinThread(&pLowestThread); // sal_Int32 nValueHighest = 0; // nValueHighest = pHighestThread->getValue(); sal_Int32 nValueAboveNormal = pAboveNormalThread.getValue(); sal_Int32 nValueNormal = pNormalThread.getValue(); sal_Int32 nValueBelowNormal = pBelowNormalThread.getValue(); sal_Int32 nValueLowest = pLowestThread.getValue(); t_print("After 5 tenth seconds\n"); t_print("nValue in AboveNormal Prio Thread is %d\n", static_cast(nValueAboveNormal)); t_print("nValue in Normal Prio Thread is %d\n", static_cast(nValueNormal)); t_print("nValue in BelowNormal Prio Thread is %d\n", static_cast(nValueBelowNormal)); t_print("nValue in Lowest Prio Thread is %d\n", static_cast(nValueLowest)); // delete pHighestThread; #ifndef _WIN32 CPPUNIT_ASSERT_MESSAGE( "SetPriority", /* nValueHighest > 0 && */ nValueAboveNormal > 0 && nValueNormal > 0 ); CPPUNIT_ASSERT_MESSAGE( "SetPriority", nValueBelowNormal > 0 ); CPPUNIT_ASSERT_MESSAGE( "SetPriority", nValueLowest > 0 ); #endif } void setPriority_005() { // initial 5 threads with different priorities // OAddThread *pHighestThread = new OAddThread(); // OAddThread *pAboveNormalThread = new OAddThread(); OAddThread pNormalThread; OAddThread pBelowNormalThread; OAddThread pLowestThread; //Create them and start running at the same time // pHighestThread->createSuspended(); // pHighestThread->setPriority(osl_Thread_PriorityHighest); // pAboveNormalThread->createSuspended(); // pAboveNormalThread->setPriority(osl_Thread_PriorityAboveNormal); pNormalThread.createSuspended(); pNormalThread.setPriority(osl_Thread_PriorityNormal); pBelowNormalThread.createSuspended(); pBelowNormalThread.setPriority(osl_Thread_PriorityBelowNormal); pLowestThread.createSuspended(); pLowestThread.setPriority(osl_Thread_PriorityLowest); // pHighestThread->resume(); // pAboveNormalThread->resume(); pNormalThread.resume(); pBelowNormalThread.resume(); pLowestThread.resume(); ThreadHelper::thread_sleep_tenth_sec(5); // pHighestThread->suspend(); // pAboveNormalThread->suspend(); pNormalThread.suspend(); pBelowNormalThread.suspend(); pLowestThread.suspend(); // termAndJoinThread(pHighestThread); // termAndJoinThread(pAboveNormalThread); termAndJoinThread(&pNormalThread); termAndJoinThread(&pBelowNormalThread); termAndJoinThread(&pLowestThread); // sal_Int32 nValueHighest = 0; // nValueHighest = pHighestThread->getValue(); // sal_Int32 nValueAboveNormal = 0; // nValueAboveNormal = pAboveNormalThread->getValue(); sal_Int32 nValueNormal = pNormalThread.getValue(); sal_Int32 nValueBelowNormal = pBelowNormalThread.getValue(); sal_Int32 nValueLowest = pLowestThread.getValue(); t_print("After 5 tenth seconds\n"); t_print("nValue in Normal Prio Thread is %d\n", static_cast(nValueNormal)); t_print("nValue in BelowNormal Prio Thread is %d\n", static_cast(nValueBelowNormal)); t_print("nValue in Lowest Prio Thread is %d\n", static_cast(nValueLowest)); #ifndef _WIN32 CPPUNIT_ASSERT_MESSAGE( "SetPriority", /* nValueHighest > 0 && */ /* nValueAboveNormal > 0 && */ nValueNormal > 0 ); CPPUNIT_ASSERT_MESSAGE( "SetPriority", nValueBelowNormal > 0 ); CPPUNIT_ASSERT_MESSAGE( "SetPriority", nValueLowest > 0 ); #endif } CPPUNIT_TEST_SUITE(setPriority); #ifndef __sun CPPUNIT_TEST(setPriority_002); CPPUNIT_TEST(setPriority_003); CPPUNIT_TEST(setPriority_004); CPPUNIT_TEST(setPriority_005); #endif CPPUNIT_TEST(setPriority_001_1); CPPUNIT_TEST(setPriority_001_2); CPPUNIT_TEST(setPriority_001_3); CPPUNIT_TEST(setPriority_001_4); CPPUNIT_TEST(setPriority_001_5); CPPUNIT_TEST_SUITE_END(); }; // class setPriority /** Test of the osl::Thread::getPriority method */ class getPriority : public CppUnit::TestFixture { public: // insert your test code here. void getPriority_001() { OAddThread *pHighestThread = new OAddThread(); //Create them and start running at the same time pHighestThread->create(); pHighestThread->setPriority(osl_Thread_PriorityHighest); oslThreadPriority aPriority = pHighestThread->getPriority(); termAndJoinThread(pHighestThread); delete pHighestThread; ThreadHelper::outputPriority(aPriority); // LLA: Priority settings may not work within some OS versions. #if defined(_WIN32) || defined(__sun) CPPUNIT_ASSERT_EQUAL_MESSAGE( "getPriority", osl_Thread_PriorityHighest, aPriority ); #else // LLA: Linux // NO_PTHREAD_PRIORITY ??? CPPUNIT_ASSERT_EQUAL_MESSAGE( "getPriority", osl_Thread_PriorityNormal, aPriority ); #endif } CPPUNIT_TEST_SUITE(getPriority); CPPUNIT_TEST(getPriority_001); CPPUNIT_TEST_SUITE_END(); }; // class getPriority class getIdentifier : public CppUnit::TestFixture { public: // initialise your test code values here. void getIdentifier_001() { // insert your test code here. } CPPUNIT_TEST_SUITE(getIdentifier); CPPUNIT_TEST(getIdentifier_001); CPPUNIT_TEST_SUITE_END(); }; // class getIdentifier /** Test of the osl::Thread::getCurrentIdentifier method */ class getCurrentIdentifier : public CppUnit::TestFixture { public: void getCurrentIdentifier_001() { oslThreadIdentifier oId; OCountThread* pCountThread = new OCountThread; pCountThread->create(); pCountThread->setWait(3); oId = Thread::getCurrentIdentifier(); oslThreadIdentifier oIdChild = pCountThread->getIdentifier(); termAndJoinThread(pCountThread); delete pCountThread; CPPUNIT_ASSERT_MESSAGE( "Get the identifier for the current active thread.", oId != oIdChild); } CPPUNIT_TEST_SUITE(getCurrentIdentifier); CPPUNIT_TEST(getCurrentIdentifier_001); CPPUNIT_TEST_SUITE_END(); }; // class getCurrentIdentifier /** Test of the osl::Thread::wait method */ class waittest : public CppUnit::TestFixture { public: /** call wait in the run method ALGORITHM: tested thread wait nWaitSec seconds, main thread sleep (2) seconds, then terminate the tested thread, due to the fact that the thread do a sleep(1) + wait(5) it's finish after 6 seconds. */ void wait_001() { OCountThread *aCountThread = new OCountThread(); sal_Int32 nWaitSec = 5; aCountThread->setWait(nWaitSec); // thread runs at least 5 seconds. bool bRes = aCountThread->create(); CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes ); //record the time when the running begin StopWatch aStopWatch; aStopWatch.start(); // wait a little bit, to let the thread the time, to start ThreadHelper::thread_sleep_tenth_sec( 4 ); // if wait works, // this function returns, after 4 sec. later termAndJoinThread(aCountThread); // value should be one. sal_Int32 nValue = aCountThread->getValue(); aStopWatch.stop(); // sal_uInt32 nSec = aTimeVal_after.Seconds - aTimeVal_befor.Seconds; double nTenthSec = aStopWatch.getTenthSec(); double nSec = aStopWatch.getSeconds(); delete aCountThread; t_print("nTenthSec = %f \n", nTenthSec); t_print("nSec = %f \n", nSec); t_print("nValue = %d \n", static_cast(nValue)); CPPUNIT_ASSERT_MESSAGE( "Wait: Blocks the calling thread for the given number of time.", nTenthSec >= 5 ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wait: Blocks the calling thread for the given number of time.", sal_Int32(1), nValue ); } CPPUNIT_TEST_SUITE(waittest); CPPUNIT_TEST(wait_001); CPPUNIT_TEST_SUITE_END(); }; // class waittest /** osl::Thread::yield method: can not design good test scenario to test up to now */ class yield : public CppUnit::TestFixture { public: void yield_001() { // insert your test code here. } CPPUNIT_TEST_SUITE(yield); CPPUNIT_TEST(yield_001); CPPUNIT_TEST_SUITE_END(); }; // class yield /** Test of the osl::Thread::schedule method */ class schedule : public CppUnit::TestFixture { public: /** The requested thread will get terminate the next time schedule() is called. Note: on UNX, if call suspend thread is not the to be suspended thread, the to be suspended thread will get suspended the next time schedule() is called, while on w32, it's nothing with schedule. check if suspend and terminate work well via schedule */ void schedule_001() { OAddThread* aThread = new OAddThread(); bool bRes = aThread->create(); CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes ); ThreadHelper::thread_sleep_tenth_sec(2); aThread->suspend(); ThreadHelper::thread_sleep_tenth_sec(1); sal_Int32 nValue = aThread->getValue(); ThreadHelper::thread_sleep_tenth_sec(3); sal_Int32 nLaterValue = aThread->getValue(); // resumeAndWaitThread(aThread); t_print(" value = %d\n", static_cast(nValue)); t_print("later value = %d\n", static_cast(nLaterValue)); // if value and latervalue not equal, then the thread would not suspended CPPUNIT_ASSERT_EQUAL_MESSAGE( "Schedule: suspend works.", nValue, nLaterValue ); aThread->resume(); ThreadHelper::thread_sleep_tenth_sec(2); aThread->terminate(); sal_Int32 nValue_term = aThread->getValue(); aThread->join(); sal_Int32 nValue_join = aThread->getValue(); t_print("value after term = %d\n", static_cast(nValue_term)); t_print("value after join = %d\n", static_cast(nValue_join)); // nValue_term and nValue_join should be the same // but should be differ from nValue delete aThread; //check if thread really terminate after call terminate, if join immediately return CPPUNIT_ASSERT_MESSAGE( "Schedule: Returns False if the thread should terminate.", nValue_join - nValue_term <= 1 ); CPPUNIT_ASSERT_MESSAGE( "Schedule: Returns False if the thread should terminate.", nValue_join - nValue_term >= 0 ); } /** design a thread that has not call schedule in the workfunction--run method */ void schedule_002() { ONoScheduleThread aThread; // this thread runs 10 sec. (no schedule() used) bool bRes = aThread.create(); CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes ); ThreadHelper::thread_sleep_tenth_sec(2); aThread.suspend(); sal_Int32 nValue = aThread.getValue(); ThreadHelper::thread_sleep_tenth_sec(3); sal_Int32 nLaterValue = aThread.getValue(); ThreadHelper::thread_sleep_tenth_sec(5); resumeAndWaitThread(&aThread); t_print(" value = %d\n", static_cast(nValue)); t_print("later value = %d\n", static_cast(nLaterValue)); //On windows, suspend works, so the values are same #ifdef _WIN32 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Schedule: don't schedule in thread run method, suspend works.", nValue, nLaterValue ); #endif //On UNX, suspend does not work, so the difference of the values equals to sleep seconds number #ifdef UNX aThread.resume(); CPPUNIT_ASSERT_MESSAGE( "Schedule: don't schedule in thread run method, suspend does not work too.", nLaterValue > nValue ); #endif // terminate will not work if no schedule in thread's work function termAndJoinThread(&aThread); sal_Int32 nValue_term = aThread.getValue(); t_print(" value term = %d\n", static_cast(nValue_term)); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Schedule: don't schedule in thread run method, terminate failed.", static_cast(10), nValue_term ); } CPPUNIT_TEST_SUITE(schedule); CPPUNIT_TEST(schedule_001); CPPUNIT_TEST(schedule_002); CPPUNIT_TEST_SUITE_END(); }; // class schedule CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Thread::create, "osl_Thread"); CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Thread::createSuspended, "osl_Thread"); CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Thread::suspend, "osl_Thread"); CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Thread::resume, "osl_Thread"); CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Thread::terminate, "osl_Thread"); CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Thread::join, "osl_Thread"); CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Thread::isRunning, "osl_Thread"); CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Thread::setPriority, "osl_Thread"); CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Thread::getPriority, "osl_Thread"); CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Thread::getIdentifier, "osl_Thread"); CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Thread::getCurrentIdentifier, "osl_Thread"); CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Thread::waittest, "osl_Thread"); CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Thread::yield, "osl_Thread"); CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Thread::schedule, "osl_Thread"); } // namespace osl_Thread // destroy function when the binding thread terminate static void destroyCallback(void * data) { delete[] static_cast(data); } static ThreadData myThreadData(destroyCallback); namespace { class myKeyThread : public Thread { public: // a public char member for test result checking char m_Char_Test; // for pass thread-special data to thread explicit myKeyThread(const char cData) : m_Char_Test(0) { m_nData = cData; } private: char m_nData; void SAL_CALL run() override { char * pc = new char[2]; // strcpy(pc, &m_nData); memcpy(pc, &m_nData, 1); pc[1] = '\0'; myThreadData.setData(pc); char* pData = static_cast(myThreadData.getData()); m_Char_Test = *pData; // wait for long time to check the data value in main thread ThreadHelper::thread_sleep_tenth_sec(3); } public: virtual ~myKeyThread() override { if (isRunning()) { t_print("error: not terminated.\n"); } } }; } static ThreadData idData; namespace { class idThread: public Thread { public: oslThreadIdentifier m_Id; private: void SAL_CALL run() override { std::unique_ptr pId( new oslThreadIdentifier ); *pId = getIdentifier(); idData.setData(pId.get()); oslThreadIdentifier* pIdData = static_cast(idData.getData()); //t_print("Thread %d has Data %d\n", getIdentifier(), *pIdData); m_Id = *pIdData; } public: virtual ~idThread() override { if (isRunning()) { t_print("error: not terminated.\n"); } } }; } namespace osl_ThreadData { class ctors : public CppUnit::TestFixture { public: // insert your test code here. void ctor_001() { } CPPUNIT_TEST_SUITE(ctors); CPPUNIT_TEST(ctor_001); CPPUNIT_TEST_SUITE_END(); }; // class ctors class setData : public CppUnit::TestFixture { public: /** the same instance of the class can have different values in different threads */ void setData_001() { idThread aThread1; aThread1.create(); idThread aThread2; aThread2.create(); aThread1.join(); aThread2.join(); oslThreadIdentifier aThreadId1 = aThread1.getIdentifier(); oslThreadIdentifier aThreadId2 = aThread2.getIdentifier(); CPPUNIT_ASSERT_EQUAL_MESSAGE( "ThreadData setData: ", aThread1.m_Id, aThreadId1 ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "ThreadData setData: ", aThread2.m_Id, aThreadId2 ); } void setData_002() { // at first, set the data a value char* pc = new char[2]; char nData = 'm'; pc[0] = nData; pc[1] = '\0'; myThreadData.setData(pc); myKeyThread aThread1('a'); aThread1.create(); myKeyThread aThread2('b'); aThread2.create(); // aThread1 and aThread2 should have not terminated yet, check current data, not 'a' 'b' char* pChar = static_cast(myThreadData.getData()); char aChar = *pChar; aThread1.join(); aThread2.join(); // the saved thread data of aThread1 & aThread2, different char cData1 = aThread1.m_Char_Test; char cData2 = aThread2.m_Char_Test; CPPUNIT_ASSERT_EQUAL_MESSAGE( "ThreadData setData: ", 'a', cData1 ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "ThreadData setData: ", 'b', cData2 ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "ThreadData setData: ", 'm', aChar ); } /** setData the second time, and then getData */ void setData_003() { // at first, set the data a value char* pc = new char[2]; char nData = 'm'; memcpy(pc, &nData, 1); pc[1] = '\0'; myThreadData.setData(pc); myKeyThread aThread1('a'); aThread1.create(); myKeyThread aThread2('b'); aThread2.create(); // aThread1 and aThread2 should have not terminated yet // setData the second time char* pc2 = new char[2]; nData = 'o'; memcpy(pc2, &nData, 1); pc2[1] = '\0'; myThreadData.setData(pc2); char* pChar = static_cast(myThreadData.getData()); char aChar = *pChar; aThread1.join(); aThread2.join(); // the saved thread data of aThread1 & aThread2, different char cData1 = aThread1.m_Char_Test; char cData2 = aThread2.m_Char_Test; CPPUNIT_ASSERT_EQUAL_MESSAGE( "ThreadData setData: ", 'a', cData1 ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "ThreadData setData: ", 'b', cData2 ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "ThreadData setData: ", 'o', aChar ); } CPPUNIT_TEST_SUITE(setData); CPPUNIT_TEST(setData_001); CPPUNIT_TEST(setData_002); CPPUNIT_TEST(setData_003); CPPUNIT_TEST_SUITE_END(); }; // class setData class getData : public CppUnit::TestFixture { public: // After setData in child threads, get Data in the main thread, should be independent void getData_001() { char* pc = new char[2]; strcpy(pc, "i"); myThreadData.setData(pc); myKeyThread aThread1('c'); aThread1.create(); myKeyThread aThread2('d'); aThread2.create(); aThread1.join(); aThread2.join(); char cData1 = aThread1.m_Char_Test; char cData2 = aThread2.m_Char_Test; char* pChar = static_cast(myThreadData.getData()); char aChar = *pChar; CPPUNIT_ASSERT_EQUAL_MESSAGE( "ThreadData setData: ", 'c', cData1 ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "ThreadData setData: ", 'd', cData2 ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "ThreadData setData: ", 'i', aChar ); } // setData then change the value in the address data pointer points, // and then getData, should get the new value void getData_002() { char* pc = new char[2]; char nData = 'i'; memcpy(pc, &nData, 1); pc[1] = '\0'; myThreadData.setData(pc); myKeyThread aThread1('a'); aThread1.create(); myKeyThread aThread2('b'); aThread2.create(); // change the value which pc points char nData2 = 'j'; memcpy(pc, &nData2, 1); pc[1] = '\0'; void* pChar = myThreadData.getData(); char aChar = *static_cast(pChar); aThread1.join(); aThread2.join(); char cData1 = aThread1.m_Char_Test; char cData2 = aThread2.m_Char_Test; CPPUNIT_ASSERT_MESSAGE( "ThreadData setData: ", cData1 == 'a' && cData2 == 'b' ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "ThreadData setData: ", 'j', aChar ); } CPPUNIT_TEST_SUITE(getData); CPPUNIT_TEST(getData_001); CPPUNIT_TEST(getData_002); CPPUNIT_TEST_SUITE_END(); }; // class getData CPPUNIT_TEST_SUITE_REGISTRATION(osl_ThreadData::ctors); CPPUNIT_TEST_SUITE_REGISTRATION(osl_ThreadData::setData); CPPUNIT_TEST_SUITE_REGISTRATION(osl_ThreadData::getData); } // namespace osl_ThreadData /* vim:set shiftwidth=4 softtabstop=4 expandtab: */