diff options
Diffstat (limited to 'sal/qa/osl/process')
-rwxr-xr-x | sal/qa/osl/process/batch.bat | 2 | ||||
-rw-r--r-- | sal/qa/osl/process/export.exp | 1 | ||||
-rw-r--r-- | sal/qa/osl/process/makefile.mk | 110 | ||||
-rw-r--r-- | sal/qa/osl/process/osl_Thread.cxx | 2344 | ||||
-rw-r--r-- | sal/qa/osl/process/osl_Thread.xsce | 1 | ||||
-rw-r--r-- | sal/qa/osl/process/osl_process.cxx | 684 | ||||
-rw-r--r-- | sal/qa/osl/process/osl_process_child.cxx | 131 |
7 files changed, 3273 insertions, 0 deletions
diff --git a/sal/qa/osl/process/batch.bat b/sal/qa/osl/process/batch.bat new file mode 100755 index 000000000000..7a47559e9b6e --- /dev/null +++ b/sal/qa/osl/process/batch.bat @@ -0,0 +1,2 @@ +@echo off +echo "Hello world"
\ No newline at end of file diff --git a/sal/qa/osl/process/export.exp b/sal/qa/osl/process/export.exp new file mode 100644 index 000000000000..a13529da5876 --- /dev/null +++ b/sal/qa/osl/process/export.exp @@ -0,0 +1 @@ +registerAllTestFunction diff --git a/sal/qa/osl/process/makefile.mk b/sal/qa/osl/process/makefile.mk new file mode 100644 index 000000000000..6bbee03b6aaf --- /dev/null +++ b/sal/qa/osl/process/makefile.mk @@ -0,0 +1,110 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* +PRJ=..$/..$/.. + +PRJNAME=sal +TARGET=qa_osl_process +# this is removed at the moment because we need some enhancements +# TESTDIR=TRUE + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +CFLAGS+= $(LFS_CFLAGS) +CXXFLAGS+= $(LFS_CFLAGS) + +# BEGIN ---------------------------------------------------------------- +# auto generated Target:testjob by codegen.pl + +.IF "$(GUI)" == "WNT" + CFLAGS+=/Ob1 +.ENDIF + +SHL1OBJS= \ + $(SLO)$/osl_Thread.obj + +SHL1TARGET= osl_Thread +SHL1STDLIBS= $(SALLIB) $(CPPUNITLIB) $(TESTSHL2LIB) + +SHL1IMPLIB= i$(SHL1TARGET) + +# SHL1DEF= $(MISC)$/$(SHL1TARGET).def + +DEF1NAME =$(SHL1TARGET) + +# DEF1EXPORTFILE= export.exp +SHL1VERSIONMAP = $(PRJ)$/qa$/export.map + +# END ------------------------------------------------------------------ + +#.IF "$(GUI)" == "WNT" + +SHL2OBJS=$(SLO)$/osl_process.obj +SHL2TARGET=osl_process +SHL2STDLIBS= $(SALLIB) $(CPPUNITLIB) $(TESTSHL2LIB) + +SHL2IMPLIB=i$(SHL2TARGET) +SHL2DEF=$(MISC)$/$(SHL2TARGET).def +DEF2NAME=$(SHL2TARGET) +DEF2EXPORTFILE=export.exp + +# END ------------------------------------------------------------------ + +OBJ3FILES=$(OBJ)$/osl_process_child.obj +APP3TARGET=osl_process_child +APP3OBJS=$(OBJ3FILES) + +# .IF "$(GUI)" == "UNX" +# APP3STDLIBS=$(LB)$/libsal.so +# .ENDIF +# .IF "$(GUI)" == "WNT" +# APP3STDLIBS=$(KERNEL32LIB) $(LB)$/isal.lib +# .ENDIF +APP3STDLIBS=$(SALLIB) + +#.ENDIF # "$(GUI)" == "WNT" + +#------------------------------- All object files ------------------------------- +# do this here, so we get right dependencies + +.IF "$(GUI)" == "OS2" + +SLOFILES=$(SHL2OBJS) + +.ELSE + +SLOFILES=$(SHL1OBJS) $(SHL2OBJS) + +.ENDIF + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk +.INCLUDE : _cppunit.mk diff --git a/sal/qa/osl/process/osl_Thread.cxx b/sal/qa/osl/process/osl_Thread.cxx new file mode 100644 index 000000000000..794fcc82f9c9 --- /dev/null +++ b/sal/qa/osl/process/osl_Thread.cxx @@ -0,0 +1,2344 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" +//------------------------------------------------------------------------ +// include files +//------------------------------------------------------------------------ +#include <sal/types.h> + +#ifndef _RTL_USTRING_HXX_ +#include <rtl/string.hxx> +#endif + +#ifndef _RTL_USTRING_HXX_ +#include <rtl/strbuf.hxx> +#endif + +#ifndef _OSL_THREAD_HXX +#include <osl/thread.hxx> +#endif + +#ifndef _OSL_MUTEX_HXX +#include <osl/mutex.hxx> +#endif +#include <osl/time.h> + +#include <testshl/simpleheader.hxx> + +using namespace osl; +using namespace rtl; + +#ifdef UNX +#include <unistd.h> +#include <time.h> +#endif +// ----------------------------------------------------------------------------- +// Kleine Stopuhr +class StopWatch { + TimeValue t1,t2; // Start und Stopzeit + +protected: + sal_Int32 m_nNanoSec; + sal_Int32 m_nSeconds; + + bool m_bIsValid; // TRUE, wenn gestartet und gestoppt + bool m_bIsRunning; // TRUE, wenn gestartet. + +public: + StopWatch(); + ~StopWatch() {} + + void start(); // Startet Timer + void stop(); // Stoppt Timer + + double getSeconds() const; + double getTenthSec() const; +}; + +// ================================= Stop Watch ================================= + +// Eine kleine Stop-Uhr fuer den internen Gebrauch. +// (c) Lars Langhans 29.12.1996 22:10 + +StopWatch::StopWatch():m_bIsValid(false),m_bIsRunning(false) {} + +void StopWatch::start() +{ +// pre: % +// post: Start Timer + + m_bIsValid = false; + m_bIsRunning = true; + osl_getSystemTime( &t1 ); + t_print("# %d %d nsecs\n", t1.Seconds, t1.Nanosec); + // gettimeofday(&t1, 0); +} + +void StopWatch::stop() +{ +// pre: Timer should be started +// post: Timer will stopped + + // gettimeofday(&t2, 0); // Timer ausfragen + osl_getSystemTime( &t2 ); + t_print("# %d %d nsecs\n", t2.Seconds, t2.Nanosec); + + if (m_bIsRunning) + { // check ob gestartet. +// LLA: old m_nNanoSec = static_cast<sal_Int32>(t2.Nanosec) - static_cast<sal_Int32>(t1.Nanosec); +// LLA: old m_nSeconds = static_cast<sal_Int32>(t2.Seconds) - static_cast<sal_Int32>(t1.Seconds); +// LLA: old if (m_nNanoSec < 0) +// LLA: old { +// LLA: old m_nNanoSec += 1000000000; +// LLA: old m_nSeconds -= 1; +// LLA: old } + //m_nNanoSec = t2.Nanosec - t1.Nanosec; + m_nSeconds = static_cast<sal_Int32>(t2.Seconds) - static_cast<sal_Int32>(t1.Seconds); + if ( t2.Nanosec > t1.Nanosec ) + m_nNanoSec = static_cast<sal_Int32>(t2.Nanosec) - static_cast<sal_Int32>(t1.Nanosec); + else + { + m_nNanoSec = 1000000000 + static_cast<sal_Int32>(t2.Nanosec) - static_cast<sal_Int32>(t1.Nanosec); + m_nSeconds -= 1; + } + t_print("# %d %d nsecs\n", m_nSeconds, m_nNanoSec ); + //if (m_nNanoSec < 0) + //{ + //m_nNanoSec += 1000000000; + //m_nSeconds -= 1; + //} + m_bIsValid = true; + m_bIsRunning = false; + } +} + +double StopWatch::getSeconds() const +{ +// pre: gueltig = TRUE +// BACK: Zeit in Sekunden. + + 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 ; +} + +// ----------------------------------------------------------------------------- +template <class T> +class ThreadSafeValue +{ + T m_nFlag; + Mutex m_aMutex; +public: + 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 addValue(T n) + { + //only one thread operate on the flag. + osl::MutexGuard g(m_aMutex); + m_nFlag += n; + } + void acquire() {m_aMutex.acquire();} + void release() {m_aMutex.release();} +}; + +// ----------------------------------------------------------------------------- +namespace ThreadHelper +{ + // typedef enum { + // QUIET=1, + // VERBOSE + // } eSleepVerboseMode; + + void thread_sleep_tenth_sec(sal_Int32 _nTenthSec/*, eSleepVerboseMode nVerbose = VERBOSE*/) + { + // if (nVerbose == VERBOSE) + // { + // t_print("wait %d tenth seconds. ", _nTenthSec ); + // fflush(stdout); + // } +#ifdef WNT //Windows + Sleep(_nTenthSec * 100 ); +#endif +#if ( defined UNX ) || ( defined OS2 ) //Unix + TimeValue nTV; + nTV.Seconds = static_cast<sal_uInt32>( _nTenthSec/10 ); + nTV.Nanosec = ( (_nTenthSec%10 ) * 100000000 ); + osl_waitThread(&nTV); +#endif + // if (nVerbose == VERBOSE) + // { + // t_print("done\n"); + // } + } + + 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"); + } + } +} + +/** Simple thread for testing Thread-create. + + Just add 1 of value 0, and after running, result is 1. + */ +class myThread : public Thread +{ + ThreadSafeValue<sal_Int32> m_aFlag; +public: + sal_Int32 getValue() { return m_aFlag.getValue(); } +protected: + /** guarded value which initialized 0 + + @see ThreadSafeValue + */ + void SAL_CALL run() + { + while(schedule()) + { + m_aFlag.addValue(1); + ThreadHelper::thread_sleep_tenth_sec(1); + } + } + +public: + + virtual void SAL_CALL suspend() + { + m_aFlag.acquire(); + ::osl::Thread::suspend(); + m_aFlag.release(); + } + + ~myThread() + { + if (isRunning()) + { + t_print("error: not terminated.\n"); + } + } + +}; + +// ----------------------------------------------------------------------------- +/** Thread which has a flag add 1 every second until 20 + */ +class OCountThread : public Thread +{ + ThreadSafeValue<sal_Int32> m_aFlag; +public: + OCountThread() + { + m_nWaitSec = 0; + t_print("new OCountThread thread %d!\n", 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() + { + m_aFlag.acquire(); + ::osl::Thread::suspend(); + m_aFlag.release(); + } + +protected: + //sal_Bool m_bWait; + sal_Int32 m_nWaitSec; + + void SAL_CALL run() + { + /// if the thread should terminate, schedule return false + while (m_aFlag.getValue() < 20 && schedule() == sal_True) + { + m_aFlag.addValue(1); + ThreadHelper::thread_sleep_tenth_sec(1); + // TimeValue nTV; + // nTV.Seconds = 1; + // nTV.Nanosec = 0; + // wait(nTV); + + if (m_nWaitSec != 0) + { + //ThreadHelper::thread_sleep_tenth_sec(m_nWaitSec * 10); + TimeValue nTV; + nTV.Seconds = m_nWaitSec / 10 ; + nTV.Nanosec = ( m_nWaitSec%10 ) * 100000000 ; + wait( nTV ); + m_nWaitSec = 0; + } + } + } + void SAL_CALL onTerminated() + { + t_print("normally terminate this thread %d!\n", getIdentifier()); + } +public: + + ~OCountThread() + { + if (isRunning()) + { + t_print("error: not terminated.\n"); + } + } + +}; + +/** call suspend in the run method +*/ +class OSuspendThread : public Thread +{ + ThreadSafeValue<sal_Int32> m_aFlag; +public: + OSuspendThread(){ m_bSuspend = sal_False; } + sal_Int32 getValue() { return m_aFlag.getValue(); } + void setSuspend() + { + m_bSuspend = sal_True; + } + virtual void SAL_CALL suspend() + { + m_aFlag.acquire(); + ::osl::Thread::suspend(); + m_aFlag.release(); + } +protected: + sal_Bool m_bSuspend; + void SAL_CALL run() + { + //if the thread should terminate, schedule return false + while (schedule() == sal_True) + { + m_aFlag.addValue(1); + + ThreadHelper::thread_sleep_tenth_sec(1); + // m_bWait = sal_False; + // TimeValue nTV; + // nTV.Seconds = 1; + // nTV.Nanosec = 0; + // wait(nTV); + if (m_bSuspend == sal_True) + { + suspend(); + m_bSuspend = sal_False; + } + } + } +public: + + ~OSuspendThread() + { + if (isRunning()) + { + t_print("error: not terminated.\n"); + } + } + +}; + +/** no call schedule in the run method +*/ +class ONoScheduleThread : public Thread +{ + ThreadSafeValue<sal_Int32> m_aFlag; +public: + sal_Int32 getValue() { return m_aFlag.getValue(); } + + virtual void SAL_CALL suspend() + { + m_aFlag.acquire(); + ::osl::Thread::suspend(); + m_aFlag.release(); + } +protected: + void SAL_CALL run() + { + while (m_aFlag.getValue() < 10) + { + m_aFlag.addValue(1); + ThreadHelper::thread_sleep_tenth_sec(1); + // TimeValue nTV; + // nTV.Seconds = 1; + // nTV.Nanosec = 0; + // wait(nTV); + } + } + void SAL_CALL onTerminated() + { + t_print("normally terminate this thread %d!\n", getIdentifier()); + } +public: + ONoScheduleThread() + { + t_print("new thread id %d!\n", getIdentifier()); + } + ~ONoScheduleThread() + { + if (isRunning()) + { + t_print("error: not terminated.\n"); + } + } + +}; + +/** +*/ +class OAddThread : public Thread +{ + ThreadSafeValue<sal_Int32> m_aFlag; +public: + //oslThreadIdentifier m_id, m_CurId; + OAddThread(){} + sal_Int32 getValue() { return m_aFlag.getValue(); } + + virtual void SAL_CALL suspend() + { + m_aFlag.acquire(); + ::osl::Thread::suspend(); + m_aFlag.release(); + } +protected: + void SAL_CALL run() + { + //if the thread should terminate, schedule return false + while (schedule() == sal_True) + { + m_aFlag.addValue(1); + } + } + void SAL_CALL onTerminated() + { + // t_print("normally terminate this thread %d!\n", getIdentifier()); + } +public: + + ~OAddThread() + { + if (isRunning()) + { + // t_print("error: not terminated.\n"); + } + } + +}; + +namespace osl_Thread +{ + + void resumeAndWaitThread(Thread* _pThread) + { + // This functions 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 WNT + t_print("resumeAndWaitThread\n"); + _pThread->resume(); + ThreadHelper::thread_sleep_tenth_sec(1); +#else + _pThread->resume(); +#endif + // ThreadHelper::thread_sleep_tenth_sec(1); + // _pThread->suspend(); + // ThreadHelper::thread_sleep_tenth_sec(1); + } + + // kill a running thread and join it, if it has terminated, do nothing + void termAndJoinThread(Thread* _pThread) + { + _pThread->terminate(); + +// LLA: Windows feature???, a suspended thread can not terminated, so we have to weak it up +#ifdef WNT + _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: + + // initialise your test code values here. + void setUp() + { + } + + void tearDown() + { + } + + /** 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(); + sal_Bool bRes = newthread->create(); + CPPUNIT_ASSERT_MESSAGE("Can not creates a new thread!\n", bRes == sal_True ); + + ThreadHelper::thread_sleep_tenth_sec(1); // wait short + sal_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", nValue); + t_print("isRunning = %d\n", isRunning); + + CPPUNIT_ASSERT_MESSAGE( + "Creates a new thread", + nValue >= 1 && isRunning == sal_True + ); + + } + + /** only one running thread per instance, return false if create secondly + */ + void create_002() + { + myThread* newthread = new myThread(); + sal_Bool res1 = newthread->create(); + sal_Bool res2 = newthread->create(); + t_print("In non pro, an assertion should occured. This behaviour is right.\n"); + termAndJoinThread(newthread); + delete newthread; + + CPPUNIT_ASSERT_MESSAGE( + "Creates a new thread: can not create two threads per instance", + res1 && !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: + // initialise your test code values here. + void setUp() + { + } + + void tearDown() + { + } + + /** 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(); + sal_Bool bRes = newthread->createSuspended(); + CPPUNIT_ASSERT_MESSAGE("Can not creates a new thread!", bRes == sal_True ); + + ThreadHelper::thread_sleep_tenth_sec(1); + sal_Bool isRunning = newthread->isRunning(); + ThreadHelper::thread_sleep_tenth_sec(3); + sal_Int32 nValue = newthread->getValue(); + + resumeAndWaitThread(newthread); + + termAndJoinThread(newthread); + delete newthread; + + CPPUNIT_ASSERT_MESSAGE( + "Creates a new suspended thread", + nValue == 0 && isRunning + ); + } + + void createSuspended_002() + { + myThread* newthread = new myThread(); + sal_Bool res1 = newthread->createSuspended(); + sal_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 && !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. + */ + void suspendCountThread(OCountThread* _pCountThread) + { + sal_Int32 nValue = 0; + while (1) + { + nValue = _pCountThread->getValue(); + if (nValue >= 3) + { + _pCountThread->suspend(); + break; + } + } + } + + /** Test of the osl::Thread::suspend method + */ + class suspend : public CppUnit::TestFixture + { + public: + // initialise your test code values here. + void setUp() + { + } + + void tearDown() + { + } + + /** 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(); + sal_Bool bRes = aCountThread->create(); + CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes == sal_True ); + // 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 == sal_True && nValue == nLaterValue + ); + + } + /** suspend a thread in it's worker-function, the ALGORITHM is same as suspend_001 + reason of deadlocked I think: no schedule can schedule other threads to go on excuting + */ + void suspend_002() + { + OSuspendThread* aThread = new OSuspendThread(); + sal_Bool bRes = aThread->create(); + CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes == sal_True ); + // first the thread run for some seconds, but not terminate + sal_Int32 nValue = 0; + //while (1) + //{ + ThreadHelper::thread_sleep_tenth_sec(3); + nValue = aThread->getValue(); // (1) + t_print(" getValue is %d !", nValue ); + if (nValue >= 2) + { + aThread->setSuspend(); + //break; + } + //} + t_print(" after while!"); + // the value just after calling suspend + nValue = aThread->getValue(); // (2) + + ThreadHelper::thread_sleep_tenth_sec(3); + t_print(" after sleep!"); + // the value after waiting 3 seconds + sal_Int32 nLaterValue = aThread->getValue(); // (3) + + //resumeAndWaitThread(aThread); + aThread->resume(); + termAndJoinThread(aThread); + delete aThread; + + CPPUNIT_ASSERT_MESSAGE( + "Suspend the thread", + bRes == sal_True && 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: + // initialise your test code values here. + void setUp() + { + } + + void tearDown() + { + } + + /** 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(); + sal_Bool bRes = pCountThread->create(); + CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes == sal_True ); + + 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", nSuspendValue); + t_print("ResumeValue: %d\n", nResumeValue); + t_print("LaterValue: %d\n", nLaterValue); + + /* LLA: this assumption is no longer relevant: nResumeValue == nSuspendValue && */ + CPPUNIT_ASSERT_MESSAGE( + "Suspend then resume the thread", + nLaterValue >= 9 && + nResumeValue > nSuspendValue && + nLaterValue > nResumeValue + ); + + } + + /** Create a suspended thread then resume, check if the thread has run + */ + void resume_002() + { + myThread* newthread = new myThread(); + sal_Bool bRes = newthread->createSuspended(); + CPPUNIT_ASSERT_MESSAGE ( "Can't create thread!", bRes == sal_True ); + + newthread->resume(); + ThreadHelper::thread_sleep_tenth_sec(2); + sal_Int32 nValue = newthread->getValue(); + + termAndJoinThread(newthread); + delete newthread; + + t_print(" nValue = %d\n", 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: + // initialise your test code values here. + void setUp() + { + } + + void tearDown() + { + } + + /** 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(); + sal_Bool bRes = aCountThread->create(); + CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes == sal_True ); + + 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 + sal_Bool isRunning = aCountThread->isRunning(); + aCountThread->join(); + delete aCountThread; + + t_print(" nValue = %d\n", nValue); + t_print("nLaterValue = %d\n", nLaterValue); + + CPPUNIT_ASSERT_MESSAGE( + "Terminate the thread", + isRunning == sal_False && 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(); + sal_Bool bRes = aCountThread->create(); + CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes == sal_True ); + + 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", nValue); + t_print("nLaterValue = %d\n", 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: + // initialise your test code values here. + void setUp() + { + } + + void tearDown() + { + } + + /** 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 terminate + ALGORITHM: + recode system time at the beginning of the thread run, call join, then record system time again, + the difference of the two time should be equal or more than 20 seconds, the CountThead normally terminate + */ + void join_001() + { + OCountThread *aCountThread = new OCountThread(); + sal_Bool bRes = aCountThread->create(); + CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes == sal_True ); + + 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(); + sal_Bool bRes = aCountThread->create(); + CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes == sal_True ); + + //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: + // initialise your test code values here. + void setUp() + { + } + + void tearDown() + { + } + + /** + */ + void isRunning_001() + { + OCountThread *aCountThread = new OCountThread(); + sal_Bool bRes = aCountThread->create(); + CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes == sal_True ); + + sal_Bool bRun = aCountThread->isRunning(); + + ThreadHelper::thread_sleep_tenth_sec(2); + termAndJoinThread(aCountThread); + sal_Bool bTer = aCountThread->isRunning(); + delete aCountThread; + + CPPUNIT_ASSERT_MESSAGE( + "Test isRunning", + bRun == sal_True && bTer == sal_False + ); + } + /** check the value of isRunning when suspending and after resume + */ + void isRunning_002() + { + OCountThread *aCountThread = new OCountThread(); + sal_Bool bRes = aCountThread->create(); + CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes == sal_True ); + + // sal_Bool bRunning = aCountThread->isRunning(); + // sal_Int32 nValue = 0; + suspendCountThread(aCountThread); + + sal_Bool bRunning_sup = aCountThread->isRunning(); + ThreadHelper::thread_sleep_tenth_sec(2); + aCountThread->resume(); + ThreadHelper::thread_sleep_tenth_sec(2); + sal_Bool bRunning_res = aCountThread->isRunning(); + termAndJoinThread(aCountThread); + sal_Bool bRunning_ter = aCountThread->isRunning(); + delete aCountThread; + + CPPUNIT_ASSERT_MESSAGE( + "Test isRunning", + bRes == sal_True && + bRunning_sup == sal_True && + bRunning_res == sal_True && + bRunning_ter == sal_False + ); + + } + + 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: + // initialise your test code values here. + void setUp() + { + } + + void tearDown() + { + } + + // insert your test code here. + rtl::OString getPrioName(oslThreadPriority _aPriority) + { + rtl::OString sPrioStr; + switch (_aPriority) + { + case osl_Thread_PriorityHighest: + sPrioStr = "Highest"; + break; + + case osl_Thread_PriorityAboveNormal: + sPrioStr = "AboveNormal"; + + case osl_Thread_PriorityNormal: + sPrioStr = "Normal"; + + 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 = 0; + nValueNormal = pThread->getValue(); + + sal_Int32 nValueNormal2 = 0; + nValueNormal2 = p2Thread->getValue(); + + rtl::OString sPrio = getPrioName(_aPriority); + t_print("After 10 tenth seconds\n"); + + t_print("nValue in %s Prio Thread is %d\n",sPrio.getStr(), nValueNormal); + t_print("nValue in %s Prio Thread is %d\n", sPrio.getStr(), 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",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 = 0; + nValueHighest = aHighestThread.getValue(); + + sal_Int32 nValueAboveNormal = 0; + nValueAboveNormal = aAboveNormalThread.getValue(); + + sal_Int32 nValueNormal = 0; + nValueNormal = aNormalThread.getValue(); + + // sal_Int32 nValueBelowNormal = 0; + //nValueBelowNormal = aBelowNormalThread->getValue(); + // sal_Int32 nValueLowest = 0; + //nValueLowest = aLowestThread->getValue(); + t_print("After 10 tenth seconds\n"); + t_print("nValue in Highest Prio Thread is %d\n",nValueHighest); + t_print("nValue in AboveNormal Prio Thread is %d\n",nValueAboveNormal); + t_print("nValue in Normal Prio Thread is %d\n",nValueNormal); + + // LLA: this is not a save test, so we only check if all values not zero + // LLA: CPPUNIT_ASSERT_MESSAGE( + // LLA: "SetPriority", + // LLA: nValueHighest >= nValueAboveNormal && + // LLA: nValueAboveNormal >= nValueNormal && + // LLA: nValueNormal > 0 + // LLA: ); + +// LLA: windows let starve threads with lower priority +#ifndef WNT + CPPUNIT_ASSERT_MESSAGE( + "SetPriority", + nValueHighest > 0 && + nValueAboveNormal > 0 && + nValueNormal > 0 + ); +#endif + } + + void setPriority_003() + { + // initial 5 threads with different priorities + OAddThread *pHighestThread = new OAddThread(); + OAddThread *pAboveNormalThread = new OAddThread(); + OAddThread *pNormalThread = new OAddThread(); + OAddThread *pBelowNormalThread = new OAddThread(); + OAddThread *pLowestThread = new OAddThread(); + + //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 = 0; + nValueNormal = pNormalThread->getValue(); + + sal_Int32 nValueBelowNormal = 0; + nValueBelowNormal = pBelowNormalThread->getValue(); + + sal_Int32 nValueLowest = 0; + nValueLowest = pLowestThread->getValue(); + + t_print("After 10 tenth seconds\n"); + t_print("nValue in Highest Prio Thread is %d\n",nValueHighest); + t_print("nValue in AboveNormal Prio Thread is %d\n",nValueAboveNormal); + t_print("nValue in Normal Prio Thread is %d\n",nValueNormal); + t_print("nValue in BelowNormal Prio Thread is %d\n",nValueBelowNormal); + t_print("nValue in Lowest Prio Thread is %d\n",nValueLowest); + + delete pHighestThread; + delete pAboveNormalThread; + delete pNormalThread; + delete pBelowNormalThread; + delete pLowestThread; + + // LLA: this is not a save test, so we only check if all values not zero + // LLA: CPPUNIT_ASSERT_MESSAGE( + // LLA: "SetPriority", + // LLA: nValueHighest > nValueAboveNormal && + // LLA: nValueAboveNormal > nValueNormal && + // LLA: nValueNormal > nValueBelowNormal && + // LLA: nValueBelowNormal > nValueLowest && + // LLA: nValueLowest > 0 + // LLA: ); + +// LLA: windows let starve threads with lower priority +#ifndef WNT + CPPUNIT_ASSERT_MESSAGE( + "SetPriority", + nValueHighest > 0 && + nValueAboveNormal > 0 && + nValueNormal > 0 && + nValueBelowNormal > 0 && + nValueLowest > 0 + ); +#endif + } + + void setPriority_004() + { + // initial 5 threads with different priorities + // OAddThread *pHighestThread = new OAddThread(); + OAddThread *pAboveNormalThread = new OAddThread(); + OAddThread *pNormalThread = new OAddThread(); + OAddThread *pBelowNormalThread = new OAddThread(); + OAddThread *pLowestThread = new OAddThread(); + + //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 = 0; + nValueNormal = pNormalThread->getValue(); + + sal_Int32 nValueBelowNormal = 0; + nValueBelowNormal = pBelowNormalThread->getValue(); + + sal_Int32 nValueLowest = 0; + nValueLowest = pLowestThread->getValue(); + + t_print("After 5 tenth seconds\n"); + // t_print("nValue in Highest Prio Thread is %d\n",nValueHighest); + t_print("nValue in AboveNormal Prio Thread is %d\n",nValueAboveNormal); + t_print("nValue in Normal Prio Thread is %d\n",nValueNormal); + t_print("nValue in BelowNormal Prio Thread is %d\n",nValueBelowNormal); + t_print("nValue in Lowest Prio Thread is %d\n",nValueLowest); + + // delete pHighestThread; + delete pAboveNormalThread; + delete pNormalThread; + delete pBelowNormalThread; + delete pLowestThread; + + // LLA: this is not a save test, so we only check if all values not zero + // LLA: CPPUNIT_ASSERT_MESSAGE( + // LLA: "SetPriority", + // LLA: nValueHighest > nValueAboveNormal && + // LLA: nValueAboveNormal > nValueNormal && + // LLA: nValueNormal > nValueBelowNormal && + // LLA: nValueBelowNormal > nValueLowest && + // LLA: nValueLowest > 0 + // LLA: ); + +// LLA: windows let starve threads with lower priority +#ifndef WNT + CPPUNIT_ASSERT_MESSAGE( + "SetPriority", + /* nValueHighest > 0 && */ + nValueAboveNormal > 0 && + nValueNormal > 0 && + nValueBelowNormal > 0 && + nValueLowest > 0 + ); +#endif + } + void setPriority_005() + { + // initial 5 threads with different priorities + // OAddThread *pHighestThread = new OAddThread(); + // OAddThread *pAboveNormalThread = new OAddThread(); + OAddThread *pNormalThread = new OAddThread(); + OAddThread *pBelowNormalThread = new OAddThread(); + OAddThread *pLowestThread = new OAddThread(); + + //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 = 0; + nValueNormal = pNormalThread->getValue(); + + sal_Int32 nValueBelowNormal = 0; + nValueBelowNormal = pBelowNormalThread->getValue(); + + sal_Int32 nValueLowest = 0; + nValueLowest = pLowestThread->getValue(); + + t_print("After 5 tenth seconds\n"); + // t_print("nValue in Highest Prio Thread is %d\n",nValueHighest); + // t_print("nValue in AboveNormal Prio Thread is %d\n",nValueAboveNormal); + t_print("nValue in Normal Prio Thread is %d\n",nValueNormal); + t_print("nValue in BelowNormal Prio Thread is %d\n",nValueBelowNormal); + t_print("nValue in Lowest Prio Thread is %d\n",nValueLowest); + + // delete pHighestThread; + // delete pAboveNormalThread; + delete pNormalThread; + delete pBelowNormalThread; + delete pLowestThread; + + // LLA: this is not a save test, so we only check if all values not zero + // LLA: CPPUNIT_ASSERT_MESSAGE( + // LLA: "SetPriority", + // LLA: nValueHighest > nValueAboveNormal && + // LLA: nValueAboveNormal > nValueNormal && + // LLA: nValueNormal > nValueBelowNormal && + // LLA: nValueBelowNormal > nValueLowest && + // LLA: nValueLowest > 0 + // LLA: ); + +// LLA: windows let starve threads with lower priority +#ifndef WNT + CPPUNIT_ASSERT_MESSAGE( + "SetPriority", + /* nValueHighest > 0 && */ + /* nValueAboveNormal > 0 && */ + nValueNormal > 0 && + nValueBelowNormal > 0 && + nValueLowest > 0 + ); +#endif + } + + + CPPUNIT_TEST_SUITE(setPriority); +#ifndef SOLARIS + 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: + // initialise your test code values here. + void setUp() + { + } + + void tearDown() + { + } + + // 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 WNT ) || ( defined SOLARIS ) + CPPUNIT_ASSERT_MESSAGE( + "getPriority", + aPriority == osl_Thread_PriorityHighest + ); +#else +// LLA: Linux +// NO_PTHREAD_PRIORITY ??? + CPPUNIT_ASSERT_MESSAGE( + "getPriority", + aPriority == osl_Thread_PriorityNormal + ); +#endif + } + + void getPriority_002() + { + + } + + CPPUNIT_TEST_SUITE(getPriority); + CPPUNIT_TEST(getPriority_001); + CPPUNIT_TEST(getPriority_002); + CPPUNIT_TEST_SUITE_END(); + }; // class getPriority + + + class getIdentifier : public CppUnit::TestFixture + { + public: + // initialise your test code values here. + void setUp() + { + } + + void tearDown() + { + } + + // insert your test code here. + void getIdentifier_001() + { + + } + + void getIdentifier_002() + { + + } + + CPPUNIT_TEST_SUITE(getIdentifier); + CPPUNIT_TEST(getIdentifier_001); + CPPUNIT_TEST(getIdentifier_002); + CPPUNIT_TEST_SUITE_END(); + }; // class getIdentifier + + /** Test of the osl::Thread::getCurrentIdentifier method + */ + class getCurrentIdentifier : public CppUnit::TestFixture + { + public: + // initialise your test code values here. + void setUp() + { + } + + void tearDown() + { + } + + // insert your test code here. + void getCurrentIdentifier_001() + { + oslThreadIdentifier oId; + OCountThread* pCountThread = new OCountThread; + //OCountThread* pCountThread2 = new OCountThread; + pCountThread->create(); + //pCountThread2->create(); + pCountThread->setWait(3); + oId = Thread::getCurrentIdentifier(); + oslThreadIdentifier oIdChild = pCountThread->getIdentifier(); + //t_print("CurrentId is %ld, Child1 id is %ld, Child2 id is %ld\n",oId, oIdChild,pCountThread2->m_id ); + termAndJoinThread(pCountThread); + delete pCountThread; + //termAndJoinThread(pCountThread2); + //delete pCountThread2; + + CPPUNIT_ASSERT_MESSAGE( + "Get the identifier for the current active thread.", + oId != oIdChild + ); + + } + + void getCurrentIdentifier_002() + { + } + + CPPUNIT_TEST_SUITE(getCurrentIdentifier); + CPPUNIT_TEST(getCurrentIdentifier_001); + //CPPUNIT_TEST(getCurrentIdentifier_002); + CPPUNIT_TEST_SUITE_END(); + }; // class getCurrentIdentifier + + /** Test of the osl::Thread::wait method + */ + class wait : public CppUnit::TestFixture + { + public: + // initialise your test code values here. + void setUp() + { + } + + void tearDown() + { + } + + /** 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. + sal_Bool bRes = aCountThread->create(); + CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes == sal_True ); + + //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", nValue); + + CPPUNIT_ASSERT_MESSAGE( + "Wait: Blocks the calling thread for the given number of time.", + nTenthSec >= 5 && nValue == 1 + ); + + } +// LLA: wait_001 does the same. +// LLA: /** wait then terminate the thread +// LLA: +// LLA: ALGORITHM: +// LLA: wait nWaitSec seconds, and terminate when the wait does not finish +// LLA: Windows & UNX: thread terminates immediatlly +// LLA: */ +// LLA: void wait_002() +// LLA: { +// LLA: OCountThread aThread; +// LLA: +// LLA: sal_Int32 nWaitSec = 3; +// LLA: aThread.setWait(nWaitSec); +// LLA: +// LLA: sal_Bool bRes = aThread.create(); +// LLA: CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes == sal_True ); +// LLA: +// LLA: StopWatch aStopWatch; +// LLA: // TimeValue aTimeVal_befor; +// LLA: // osl_getSystemTime( &aTimeVal_befor ); +// LLA: aStopWatch.start(); +// LLA: +// LLA: termAndJoinThread(&aThread); +// LLA: sal_Int32 nValue = aThread.getValue(); +// LLA: +// LLA: // TimeValue aTimeVal_after; +// LLA: // osl_getSystemTime( &aTimeVal_after ); +// LLA: aStopWatch.stop(); +// LLA: // sal_Int32 nSec = aTimeVal_after.Seconds - aTimeVal_befor.Seconds; +// LLA: double nSec = aStopWatch.getSeconds(); +// LLA: t_print("sec=%f\n", nSec); +// LLA: t_print("nValue = %d\n", nValue); +// LLA: +// LLA: CPPUNIT_ASSERT_MESSAGE( +// LLA: "Wait: Blocks the calling thread for the given number of time.", +// LLA: nSec < 1 && nValue == 0 +// LLA: ); +// LLA: } + + CPPUNIT_TEST_SUITE(wait); + CPPUNIT_TEST(wait_001); + // LLA: CPPUNIT_TEST(wait_002); + CPPUNIT_TEST_SUITE_END(); + }; // class wait + + /** osl::Thread::yield method: can not design good test scenario to test up to now + */ + class yield : public CppUnit::TestFixture + { + public: + void setUp() + { + } + + void tearDown() + { + } + + // insert your test code here. + void yield_001() + { + } + + + 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: + // initialise your test code values here. + void setUp() + { + } + + void tearDown() + { + } + + /** 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(); + sal_Bool bRes = aThread->create(); + CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes == sal_True ); + + 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", nValue); + t_print("later value = %d\n", nLaterValue); + // if value and latervalue not equal, than the thread would not suspended + + CPPUNIT_ASSERT_MESSAGE( + "Schedule: suspend works.", + nLaterValue == nValue + ); + + 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", nValue_term); + t_print("value after join = %d\n", 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 immediatlly return + CPPUNIT_ASSERT_MESSAGE( + "Schedule: Returns False if the thread should terminate.", + nValue_join - nValue_term <= 1 && 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) + sal_Bool bRes = aThread.create(); + CPPUNIT_ASSERT_MESSAGE ( "Can't start thread!", bRes == sal_True ); + + 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", nValue); + t_print("later value = %d\n", nLaterValue); + + //On windows, suspend works, so the values are same +#ifdef WNT + CPPUNIT_ASSERT_MESSAGE( + "Schedule: don't schedule in thread run method, suspend works.", + nLaterValue == nValue + ); +#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", nValue_term); + + CPPUNIT_ASSERT_MESSAGE( + "Schedule: don't schedule in thread run method, terminate failed.", + nValue_term == 10 + ); + } + + 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::wait, "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 +void SAL_CALL destroyCallback(void * data) +{ + t_print("destroying local data %s\n", (char *) data); + delete[] (char *) data; +} + +static ThreadData myThreadData(destroyCallback); + +/** +*/ +class myKeyThread : public Thread +{ +public: + // a public char member for test result checking + char m_Char_Test; + // for pass thread-special data to thread + myKeyThread(const char cData) + { + m_nData = cData; + } +private: + char m_nData; + + void SAL_CALL run() + { + char * pc = new char[2]; +// strcpy(pc, &m_nData); + memcpy(pc, &m_nData, 1); + pc[1] = '\0'; + + myThreadData.setData(pc); + char* pData = (char*)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: + ~myKeyThread() + { + if (isRunning()) + { + t_print("error: not terminated.\n"); + } + } +}; + +static ThreadData idData; + +class idThread: public Thread +{ +public: + oslThreadIdentifier m_Id; +private: + void SAL_CALL run() + { + oslThreadIdentifier* pId = new oslThreadIdentifier; + *pId = getIdentifier(); + idData.setData(pId); + oslThreadIdentifier* pIdData = (oslThreadIdentifier*)idData.getData(); + //t_print("Thread %d has Data %d\n", getIdentifier(), *pIdData); + m_Id = *pIdData; + delete pId; + } + +public: + ~idThread() + { + if (isRunning()) + { + t_print("error: not terminated.\n"); + } + } +}; + +namespace osl_ThreadData +{ + + class ctors : public CppUnit::TestFixture + { + public: + // initialise your test code values here. + void setUp() + { + } + + void tearDown() + { + } + + // 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: + // initialise your test code values here. + void setUp() + { + } + + void tearDown() + { + } + + /** 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_MESSAGE( + "ThreadData setData: ", + aThread1.m_Id == aThreadId1 && aThread2.m_Id == aThreadId2 + ); + + } + + void setData_002() + { + // at first, set the data a value + char* pc = new char[2]; + char m_nData = 'm'; +// LLA: this is a copy functions only and really only for \0 terminated strings +// m_nData is not a string, it's a character +// strcpy(pc, &m_nData); + memcpy(pc, &m_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, check current data, not 'a' 'b' + char* pChar = (char*)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_MESSAGE( + "ThreadData setData: ", + cData1 == 'a' && cData2 == 'b' && aChar == 'm' + ); + + } + /** setData the second time, and then getData + */ + void setData_003() + { + // at first, set the data a value + char* pc = new char[2]; + char m_nData = 'm'; +// strcpy(pc, &m_nData); + memcpy(pc, &m_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]; + m_nData = 'o'; +// strcpy(pc2, &m_nData); + memcpy(pc2, &m_nData, 1); + pc2[1] = '\0'; + + myThreadData.setData(pc2); + char* pChar = (char*)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_MESSAGE( + "ThreadData setData: ", + cData1 == 'a' && cData2 == 'b' && aChar == 'o' + ); + + } + + CPPUNIT_TEST_SUITE(setData); + CPPUNIT_TEST(setData_001); + CPPUNIT_TEST(setData_002); + CPPUNIT_TEST(setData_003); + CPPUNIT_TEST_SUITE_END(); + }; // class setData + + //sal_Bool buildTwoThreads(char) + + class getData : public CppUnit::TestFixture + { + public: + // initialise your test code values here. + void setUp() + { + } + + void tearDown() + { + } + + // After setData in child threads, get Data in the main thread, should be independent + void getData_001() + { + char* pc = new char[2]; + char m_nData[] = "i"; + strcpy(pc, m_nData); + t_print("pc %s\n", pc); + 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 = (char*)myThreadData.getData(); + char aChar = *pChar; + + CPPUNIT_ASSERT_MESSAGE( + "ThreadData setData: ", + cData1 == 'c' && cData2 == 'd' && aChar == 'i' + ); + + } + + // 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 m_nData = 'i'; +// strcpy(pc, &m_nData); + memcpy(pc, &m_nData, 1); + pc[1] = '\0'; +// strncpy(pc, &m_nData, sizeof(char); + + t_print("pc %s\n", pc); + myThreadData.setData(pc); + + myKeyThread aThread1('a'); + aThread1.create(); + myKeyThread aThread2('b'); + aThread2.create(); + + // change the value which pc points + char m_nData2 = 'j'; + // strcpy(pc, &m_nData2); + memcpy(pc, &m_nData2, 1); + pc[1] = '\0'; + + //t_print("pc %s\n", pc); + void* pChar = myThreadData.getData(); + char aChar = *(char*)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' && aChar == 'j' + ); + + } + + CPPUNIT_TEST_SUITE(getData); + CPPUNIT_TEST(getData_001); + CPPUNIT_TEST(getData_002); + CPPUNIT_TEST_SUITE_END(); + }; // class getData + +// ----------------------------------------------------------------------------- + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_ThreadData::ctors, "osl_ThreadData"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_ThreadData::setData, "osl_ThreadData"); + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_ThreadData::getData, "osl_ThreadData"); +} // namespace osl_ThreadData + +// this macro creates an empty function, which will called by the RegisterAllFunctions() +// to let the user the possibility to also register some functions by hand. +NOADDITIONAL; + diff --git a/sal/qa/osl/process/osl_Thread.xsce b/sal/qa/osl/process/osl_Thread.xsce new file mode 100644 index 000000000000..42d9ef269178 --- /dev/null +++ b/sal/qa/osl/process/osl_Thread.xsce @@ -0,0 +1 @@ +osl_Thread.setPriority.setPriority_001_1 unxsols4 diff --git a/sal/qa/osl/process/osl_process.cxx b/sal/qa/osl/process/osl_process.cxx new file mode 100644 index 000000000000..776aa42c0707 --- /dev/null +++ b/sal/qa/osl/process/osl_process.cxx @@ -0,0 +1,684 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + +#include <testshl/simpleheader.hxx> +#include <osl/process.h> +#include <osl/file.hxx> +#include <osl/thread.h> +#include <rtl/ustring.hxx> +#include <unistd.h> +#include <signal.h> + +#include <stdio.h> +#include <stdlib.h> +#include <osl/module.hxx> + +#if ( defined WNT ) // Windows +#include <tools/prewin.h> +# define WIN32_LEAN_AND_MEAN +// # include <windows.h> +# include <tchar.h> +#include <tools/postwin.h> +#endif + +#include "rtl/allocator.hxx" + +#include <iostream> +#include <fstream> +#include <vector> +#include <algorithm> +#include <iterator> +#include <string> + +#if defined(WNT) || defined(OS2) + const rtl::OUString EXECUTABLE_NAME = rtl::OUString::createFromAscii("osl_process_child.exe"); +#else + const rtl::OUString EXECUTABLE_NAME = rtl::OUString::createFromAscii("osl_process_child"); +#endif + + +//######################################## +std::string OUString_to_std_string(const rtl::OUString& oustr) +{ + rtl::OString ostr = rtl::OUStringToOString(oustr, osl_getThreadTextEncoding()); + return std::string(ostr.getStr()); +} + +//######################################## +using namespace osl; +using namespace rtl; + +/** print a UNI_CODE String. +*/ +inline void printUString( const ::rtl::OUString & str ) +{ + rtl::OString aString; + + t_print("#printUString_u# " ); + aString = ::rtl::OUStringToOString( str, RTL_TEXTENCODING_ASCII_US ); + t_print("%s\n", aString.getStr( ) ); +} + +/** get binary Path. +*/ +inline ::rtl::OUString getExecutablePath( void ) +{ + ::rtl::OUString dirPath; + osl::Module::getUrlFromAddress( ( void* ) &getExecutablePath, dirPath ); + dirPath = dirPath.copy( 0, dirPath.lastIndexOf('/') ); + dirPath = dirPath.copy( 0, dirPath.lastIndexOf('/') + 1); + dirPath += rtl::OUString::createFromAscii("bin"); + return dirPath; +} + +//rtl::OUString CWD = getExecutablePath(); + +//######################################## +class Test_osl_joinProcess : public CppUnit::TestFixture +{ + const OUString join_param_; + const OUString wait_time_; + OUString suCWD; + OUString suExecutableFileURL; + + rtl_uString* parameters_[2]; + int parameters_count_; + +public: + + Test_osl_joinProcess() : + join_param_(OUString::createFromAscii("-join")), + wait_time_(OUString::createFromAscii("1")), + parameters_count_(2) + { + parameters_[0] = join_param_.pData; + parameters_[1] = wait_time_.pData; + suCWD = getExecutablePath(); + suExecutableFileURL = suCWD; + suExecutableFileURL += rtl::OUString::createFromAscii("/"); + suExecutableFileURL += EXECUTABLE_NAME; + } + + /*------------------------------------- + Start a process and join with this + process specify a timeout so that + osl_joinProcessWithTimeout returns + osl_Process_E_TimedOut + -------------------------------------*/ + + void osl_joinProcessWithTimeout_timeout_failure() + { + oslProcess process; + oslProcessError osl_error = osl_executeProcess( + suExecutableFileURL.pData, + parameters_, + parameters_count_, + osl_Process_NORMAL, + osl_getCurrentSecurity(), + suCWD.pData, + NULL, + 0, + &process); + + CPPUNIT_ASSERT_MESSAGE + ( + "osl_createProcess failed", + osl_error == osl_Process_E_None + ); + + TimeValue timeout; + timeout.Seconds = 1; + timeout.Nanosec = 0; + + osl_error = osl_joinProcessWithTimeout(process, &timeout); + + CPPUNIT_ASSERT_MESSAGE + ( + "osl_joinProcessWithTimeout returned without timeout failure", + osl_Process_E_TimedOut == osl_error + ); + + osl_error = osl_terminateProcess(process); + + CPPUNIT_ASSERT_MESSAGE + ( + "osl_terminateProcess failed", + osl_error == osl_Process_E_None + ); + + osl_freeProcessHandle(process); + } + + /*------------------------------------- + Start a process and join with this + process specify a timeout so that + osl_joinProcessWithTimeout returns + osl_Process_E_None + -------------------------------------*/ + + void osl_joinProcessWithTimeout_without_timeout_failure() + { + oslProcess process; + oslProcessError osl_error = osl_executeProcess( + suExecutableFileURL.pData, + parameters_, + parameters_count_, + osl_Process_NORMAL, + osl_getCurrentSecurity(), + suCWD.pData, + NULL, + 0, + &process); + + CPPUNIT_ASSERT_MESSAGE + ( + "osl_createProcess failed", + osl_error == osl_Process_E_None + ); + + TimeValue timeout; + timeout.Seconds = 10; + timeout.Nanosec = 0; + + osl_error = osl_joinProcessWithTimeout(process, &timeout); + + CPPUNIT_ASSERT_MESSAGE + ( + "osl_joinProcessWithTimeout returned with failure", + osl_Process_E_None == osl_error + ); + + osl_freeProcessHandle(process); + } + + /*------------------------------------- + Start a process and join with this + process specify an infinite timeout + -------------------------------------*/ + + void osl_joinProcessWithTimeout_infinite() + { + oslProcess process; + oslProcessError osl_error = osl_executeProcess( + suExecutableFileURL.pData, + parameters_, + parameters_count_, + osl_Process_NORMAL, + osl_getCurrentSecurity(), + suCWD.pData, + NULL, + 0, + &process); + + CPPUNIT_ASSERT_MESSAGE + ( + "osl_createProcess failed", + osl_error == osl_Process_E_None + ); + + osl_error = osl_joinProcessWithTimeout(process, NULL); + + CPPUNIT_ASSERT_MESSAGE + ( + "osl_joinProcessWithTimeout returned with failure", + osl_Process_E_None == osl_error + ); + + osl_freeProcessHandle(process); + } + + /*------------------------------------- + Start a process and join with this + process using osl_joinProcess + -------------------------------------*/ + + void osl_joinProcess() + { + oslProcess process; + oslProcessError osl_error = osl_executeProcess( + suExecutableFileURL.pData, + parameters_, + parameters_count_, + osl_Process_NORMAL, + osl_getCurrentSecurity(), + suCWD.pData, + NULL, + 0, + &process); + + CPPUNIT_ASSERT_MESSAGE + ( + "osl_createProcess failed", + osl_error == osl_Process_E_None + ); + + osl_error = ::osl_joinProcess(process); + + CPPUNIT_ASSERT_MESSAGE + ( + "osl_joinProcess returned with failure", + osl_Process_E_None == osl_error + ); + + osl_freeProcessHandle(process); + } + + CPPUNIT_TEST_SUITE(Test_osl_joinProcess); + CPPUNIT_TEST(osl_joinProcessWithTimeout_timeout_failure); + CPPUNIT_TEST(osl_joinProcessWithTimeout_without_timeout_failure); + CPPUNIT_TEST(osl_joinProcessWithTimeout_infinite); + CPPUNIT_TEST(osl_joinProcess); + CPPUNIT_TEST_SUITE_END(); +}; + +//######################################################### + +typedef std::vector<std::string, rtl::Allocator<std::string> > string_container_t; +typedef string_container_t::const_iterator string_container_const_iter_t; +typedef string_container_t::iterator string_container_iter_t; + +//######################################################### +class exclude : public std::unary_function<std::string, bool> +{ +public: + //------------------------------------------------ + exclude(const string_container_t& exclude_list) + { + string_container_const_iter_t iter = exclude_list.begin(); + string_container_const_iter_t iter_end = exclude_list.end(); + for (/**/; iter != iter_end; ++iter) + exclude_list_.push_back(env_var_name(*iter)); + } + + //------------------------------------------------ + bool operator() (const std::string& env_var) const + { + return (exclude_list_.end() != + std::find( + exclude_list_.begin(), + exclude_list_.end(), + env_var_name(env_var))); + } + +private: + //------------------------------------------------- + // extract the name from an environment variable + // that is given in the form "NAME=VALUE" + std::string env_var_name(const std::string& env_var) const + { + std::string::size_type pos_equal_sign = + env_var.find_first_of("="); + + if (std::string::npos != pos_equal_sign) + return std::string(env_var, 0, pos_equal_sign); + + return std::string(); + } + +private: + string_container_t exclude_list_; +}; + +#ifdef WNT + void read_parent_environment(string_container_t* env_container) + { + LPTSTR env = reinterpret_cast<LPTSTR>(GetEnvironmentStrings()); + LPTSTR p = env; + + while (size_t l = _tcslen(p)) + { + env_container->push_back(std::string(p)); + p += l + 1; + } + FreeEnvironmentStrings(env); + } +#else + extern char** environ; + void read_parent_environment(string_container_t* env_container) + { + for (int i = 0; NULL != environ[i]; i++) + env_container->push_back(std::string(environ[i])); + } +#endif + +//######################################################### +class Test_osl_executeProcess : public CppUnit::TestFixture +{ + const OUString env_param_; + + OUString temp_file_path_; + rtl_uString* parameters_[2]; + int parameters_count_; + OUString suCWD; + OUString suExecutableFileURL; + +public: + + //------------------------------------------------ + // ctor + Test_osl_executeProcess() : + env_param_(OUString::createFromAscii("-env")), + parameters_count_(2) + { + parameters_[0] = env_param_.pData; + suCWD = getExecutablePath(); + suExecutableFileURL = suCWD; + suExecutableFileURL += rtl::OUString::createFromAscii("/"); + suExecutableFileURL += EXECUTABLE_NAME; + } + + //------------------------------------------------ + virtual void setUp() + { + temp_file_path_ = create_temp_file(); + parameters_[1] = temp_file_path_.pData; + } + + //------------------------------------------------ + OUString create_temp_file() + { + OUString temp_file_url; + FileBase::RC rc = FileBase::createTempFile(0, 0, &temp_file_url); + CPPUNIT_ASSERT_MESSAGE("createTempFile failed", FileBase::E_None == rc); + + OUString temp_file_path; + rc = FileBase::getSystemPathFromFileURL(temp_file_url, temp_file_path); + CPPUNIT_ASSERT_MESSAGE("getSystemPathFromFileURL failed", FileBase::E_None == rc); + + return temp_file_path; + } + + //------------------------------------------------ + void read_child_environment(string_container_t* env_container) + { + OString temp_file_name = OUStringToOString(OUString( + parameters_[1]), osl_getThreadTextEncoding()); + std::ifstream file(temp_file_name.getStr()); + + CPPUNIT_ASSERT_MESSAGE + ( + "I/O error, cannot open child environment file", + file.is_open() + ); + + std::string line; + while (std::getline(file, line)) + env_container->push_back(line); + } + + //------------------------------------------------ + void dump_env(const string_container_t& env, OUString file_name) + { + OString fname = OUStringToOString(file_name, osl_getThreadTextEncoding()); + std::ofstream file(fname.getStr()); + std::ostream_iterator<std::string> oi(file, "\n"); + std::copy(env.begin(), env.end(), oi); + } + + //------------------------------------------------ + // environment of the child process that was + // started. The child process writes his + // environment into a file + bool compare_environments() + { + string_container_t parent_env; + read_parent_environment(&parent_env); + + string_container_t child_env; + read_child_environment(&child_env); + + return ((parent_env.size() == child_env.size()) && + (std::equal(child_env.begin(), child_env.end(), parent_env.begin()))); + } + + //------------------------------------------------ + // compare the equal environment parts and the + // different part of the child environment + bool compare_merged_environments(const string_container_t& different_env_vars) + { + string_container_t parent_env; + read_parent_environment(&parent_env); + + //remove the environment variables that we have changed + //in the child environment from the read parent environment + parent_env.erase( + std::remove_if(parent_env.begin(), parent_env.end(), exclude(different_env_vars)), + parent_env.end()); + + //read the child environment and exclude the variables that + //are different + string_container_t child_env; + read_child_environment(&child_env); + + //partition the child environment into the variables that + //are different to the parent environment (they come first) + //and the variables that should be equal between parent + //and child environment + string_container_iter_t iter_logical_end = + std::stable_partition(child_env.begin(), child_env.end(), exclude(different_env_vars)); + + string_container_t different_child_env_vars(child_env.begin(), iter_logical_end); + child_env.erase(child_env.begin(), iter_logical_end); + + bool common_env_size_equals = (parent_env.size() == child_env.size()); + bool common_env_content_equals = std::equal(child_env.begin(), child_env.end(), parent_env.begin()); + + bool different_env_size_equals = (different_child_env_vars.size() == different_env_vars.size()); + bool different_env_content_equals = + std::equal(different_env_vars.begin(), different_env_vars.end(), different_child_env_vars.begin()); + + return (common_env_size_equals && common_env_content_equals && + different_env_size_equals && different_env_content_equals); + } + + //------------------------------------------------ + // test that parent and child process have the + // same environment when osl_executeProcess will + // be called with out setting new environment + // variables + void osl_execProc_parent_equals_child_environment() + { + oslProcess process; + oslProcessError osl_error = osl_executeProcess( + suExecutableFileURL.pData, + parameters_, + parameters_count_, + osl_Process_NORMAL, + NULL, + suCWD.pData, + NULL, + 0, + &process); + + CPPUNIT_ASSERT_MESSAGE + ( + "osl_createProcess failed", + osl_error == osl_Process_E_None + ); + + osl_error = ::osl_joinProcess(process); + + CPPUNIT_ASSERT_MESSAGE + ( + "osl_joinProcess returned with failure", + osl_Process_E_None == osl_error + ); + + osl_freeProcessHandle(process); + + CPPUNIT_ASSERT_MESSAGE + ( + "Parent an child environment not equal", + compare_environments() + ); + } + + //------------------------------------------------ + #define ENV1 "PAT=a:\\" + #define ENV2 "PATHb=b:\\" + #define ENV3 "Patha=c:\\" + #define ENV4 "Patha=d:\\" + + void osl_execProc_merged_child_environment() + { + rtl_uString* child_env[4]; + OUString env1 = OUString::createFromAscii(ENV1); + OUString env2 = OUString::createFromAscii(ENV2); + OUString env3 = OUString::createFromAscii(ENV3); + OUString env4 = OUString::createFromAscii(ENV4); + + child_env[0] = env1.pData; + child_env[1] = env2.pData; + child_env[2] = env3.pData; + child_env[3] = env4.pData; + + oslProcess process; + oslProcessError osl_error = osl_executeProcess( + suExecutableFileURL.pData, + parameters_, + parameters_count_, + osl_Process_NORMAL, + NULL, + suCWD.pData, + child_env, + sizeof(child_env)/sizeof(child_env[0]), + &process); + + CPPUNIT_ASSERT_MESSAGE + ( + "osl_createProcess failed", + osl_error == osl_Process_E_None + ); + + osl_error = ::osl_joinProcess(process); + + CPPUNIT_ASSERT_MESSAGE + ( + "osl_joinProcess returned with failure", + osl_Process_E_None == osl_error + ); + + osl_freeProcessHandle(process); + + string_container_t different_child_env_vars; + different_child_env_vars.push_back(ENV1); + different_child_env_vars.push_back(ENV2); + different_child_env_vars.push_back(ENV4); + + CPPUNIT_ASSERT_MESSAGE + ( + "osl_execProc_merged_child_environment", + compare_merged_environments(different_child_env_vars) + ); + } + + void osl_execProc_test_batch() + { + oslProcess process; + rtl::OUString suBatch = suCWD + rtl::OUString::createFromAscii("/") + rtl::OUString::createFromAscii("batch.bat"); + oslProcessError osl_error = osl_executeProcess( + suBatch.pData, + NULL, + 0, + osl_Process_NORMAL, + NULL, + suCWD.pData, + NULL, + 0, + &process); + + CPPUNIT_ASSERT_MESSAGE + ( + "osl_createProcess failed", + osl_error == osl_Process_E_None + ); + + osl_error = ::osl_joinProcess(process); + + CPPUNIT_ASSERT_MESSAGE + ( + "osl_joinProcess returned with failure", + osl_Process_E_None == osl_error + ); + + osl_freeProcessHandle(process); + } + + void osl_execProc_exe_name_in_argument_list() + { + rtl_uString* params[3]; + + params[0] = suExecutableFileURL.pData; + params[1] = env_param_.pData; + params[2] = temp_file_path_.pData; + oslProcess process; + oslProcessError osl_error = osl_executeProcess( + NULL, + params, + 3, + osl_Process_NORMAL, + NULL, + suCWD.pData, + NULL, + 0, + &process); + + CPPUNIT_ASSERT_MESSAGE + ( + "osl_createProcess failed", + osl_error == osl_Process_E_None + ); + + osl_error = ::osl_joinProcess(process); + + CPPUNIT_ASSERT_MESSAGE + ( + "osl_joinProcess returned with failure", + osl_Process_E_None == osl_error + ); + + osl_freeProcessHandle(process); + } + + CPPUNIT_TEST_SUITE(Test_osl_executeProcess); + CPPUNIT_TEST(osl_execProc_parent_equals_child_environment); + CPPUNIT_TEST(osl_execProc_merged_child_environment); + CPPUNIT_TEST(osl_execProc_test_batch); + CPPUNIT_TEST(osl_execProc_exe_name_in_argument_list); + CPPUNIT_TEST_SUITE_END(); +}; + +//##################################### +// register test suites +//CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(Test_osl_joinProcess, "Test_osl_joinProcess"); +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(Test_osl_executeProcess, "Test_osl_executeProcess"); + +NOADDITIONAL; + diff --git a/sal/qa/osl/process/osl_process_child.cxx b/sal/qa/osl/process/osl_process_child.cxx new file mode 100644 index 000000000000..8d488ad7c403 --- /dev/null +++ b/sal/qa/osl/process/osl_process_child.cxx @@ -0,0 +1,131 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + +//######################################## +// includes + +#if ( defined WNT ) // Windows +#include <tools/prewin.h> +# define UNICODE +# define _UNICODE +# define WIN32_LEAN_AND_MEAN +// # include <windows.h> +# include <tchar.h> +#include <tools/postwin.h> +#else +# include <unistd.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <iostream> +#include <fstream> + +#include <rtl/ustring.hxx> + +//######################################## +// defines + +#ifdef WNT +# define SLEEP(t) (Sleep((t)*1000)) +#else +# define SLEEP(t) (sleep((t))) +#endif + +//######################################## +void wait_for_seconds(char* time) +{ + SLEEP(atoi(time)); +} + +//######################################## + +#ifdef WNT +//######################################## +void w_to_a(LPCTSTR _strW, LPSTR strA, DWORD size) +{ + LPCWSTR strW = reinterpret_cast<LPCWSTR>(_strW); + WideCharToMultiByte(CP_ACP, 0, strW, -1, strA, size, NULL, NULL); +} +//######################################## + void dump_env(char* file_path) + { + LPTSTR env = reinterpret_cast<LPTSTR>( + GetEnvironmentStrings()); + LPTSTR p = env; + + std::ofstream file(file_path); + + char buffer[32767]; + while (size_t l = _tcslen(reinterpret_cast<wchar_t*>(p))) + { + w_to_a(p, buffer, sizeof(buffer)); + file << buffer << std::endl; + p += l + 1; + } + FreeEnvironmentStrings(env); + } +#else + extern char** environ; + + void dump_env(char* file_path) + { + std::ofstream file(file_path); + for (int i = 0; NULL != environ[i]; i++) + file << environ[i] << std::endl; + } +#endif + +//######################################## +int main(int argc, char* argv[]) +{ + rtl::OUString s; + + //t_print("Parameter: "); + printf("child process Parameter: "); + for (int i = 1; i < argc; i++) + printf("%s ", argv[i]); + printf("\n"); + + if (argc > 2) + { + if (0 == strcmp("-join", argv[1])) + { + wait_for_seconds(argv[2]); + } + else if (0 == strcmp("-env", argv[1])) + { + dump_env(argv[2]); + } + } + + return (0); +} + |