From 89ca50a5810c45b5f26eebbebc3148c848e92de8 Mon Sep 17 00:00:00 2001 From: Aleksandar Fabijanic Date: Fri, 11 Apr 2008 01:37:49 +0000 Subject: [PATCH] SF 1939071 and 1928786 --- Foundation/Foundation_vs80.vcproj | 8 ++ Foundation/Foundation_vs90.vcproj | 8 ++ Foundation/Makefile | 2 +- Foundation/include/Poco/RunnableAdapter.h | 10 ++- Foundation/include/Poco/Thread.h | 27 ++++++ Foundation/include/Poco/ThreadTarget.h | 104 ++++++++++++++++++++++ Foundation/include/Poco/Thread_POSIX.h | 53 +++++++++-- Foundation/include/Poco/Thread_WIN32.h | 54 +++++++++-- Foundation/src/Thread.cpp | 6 ++ Foundation/src/ThreadTarget.cpp | 66 ++++++++++++++ Foundation/src/Thread_POSIX.cpp | 73 +++++++++++---- Foundation/src/Thread_WIN32.cpp | 77 ++++++++++++++-- Foundation/testsuite/src/ThreadTest.cpp | 98 +++++++++++++++++++- Foundation/testsuite/src/ThreadTest.h | 3 + 14 files changed, 548 insertions(+), 41 deletions(-) create mode 100644 Foundation/include/Poco/ThreadTarget.h create mode 100644 Foundation/src/ThreadTarget.cpp diff --git a/Foundation/Foundation_vs80.vcproj b/Foundation/Foundation_vs80.vcproj index dd00102bb..fcd3fc15d 100644 --- a/Foundation/Foundation_vs80.vcproj +++ b/Foundation/Foundation_vs80.vcproj @@ -1699,6 +1699,10 @@ RelativePath=".\src\ThreadPool.cpp" > + + @@ -1831,6 +1835,10 @@ RelativePath=".\include\Poco\ThreadPool.h" > + + diff --git a/Foundation/Foundation_vs90.vcproj b/Foundation/Foundation_vs90.vcproj index 99ec7ffff..3481c9340 100644 --- a/Foundation/Foundation_vs90.vcproj +++ b/Foundation/Foundation_vs90.vcproj @@ -1682,6 +1682,10 @@ /> + + @@ -1814,6 +1818,10 @@ RelativePath=".\include\Poco\Thread_WIN32.h" > + + diff --git a/Foundation/Makefile b/Foundation/Makefile index cce3f6c9c..14d79ede5 100644 --- a/Foundation/Makefile +++ b/Foundation/Makefile @@ -27,7 +27,7 @@ objects = ArchiveStrategy ASCIIEncoding AsyncChannel Base64Decoder Base64Encoder StreamTokenizer String StringTokenizer SynchronizedObject \ Task TaskManager TaskNotification TeeStream Hash HashStatistic \ TemporaryFile TextConverter TextEncoding TextIterator Thread ThreadLocal \ - ThreadPool ActiveDispatcher Timer Timespan Timestamp Timezone Token URI \ + ThreadPool ThreadTarget ActiveDispatcher Timer Timespan Timestamp Timezone Token URI \ FileStreamFactory URIStreamFactory URIStreamOpener UTF16Encoding Windows1252Encoding \ UTF8Encoding UnicodeConverter UUID UUIDGenerator Void Format \ Pipe PipeImpl PipeStream SharedMemory FileStream Unicode UTF8String \ diff --git a/Foundation/include/Poco/RunnableAdapter.h b/Foundation/include/Poco/RunnableAdapter.h index c1b1f7028..68944ef22 100644 --- a/Foundation/include/Poco/RunnableAdapter.h +++ b/Foundation/include/Poco/RunnableAdapter.h @@ -5,7 +5,7 @@ // // Library: Foundation // Package: Threading -// Module: Thread +// Module: RunnableAdapter // // Definition of the RunnableAdapter template class. // @@ -59,11 +59,15 @@ class RunnableAdapter: public Runnable public: typedef void (C::*Callback)(); - RunnableAdapter(C& object, Callback method): _pObject(&object), _method(method) + RunnableAdapter(C& object, Callback method): + _pObject(&object), + _method(method) { } - RunnableAdapter(const RunnableAdapter& ra): _pObject(ra._pObject), _method(ra._method) + RunnableAdapter(const RunnableAdapter& ra): + _pObject(ra._pObject), + _method(ra._method) { } diff --git a/Foundation/include/Poco/Thread.h b/Foundation/include/Poco/Thread.h index 5cda15e21..606efd826 100644 --- a/Foundation/include/Poco/Thread.h +++ b/Foundation/include/Poco/Thread.h @@ -68,6 +68,8 @@ class Foundation_API Thread: private ThreadImpl /// The name of a thread can be changed at any time. { public: + using ThreadImpl::Callback; + enum Priority /// Thread priorities. { @@ -108,9 +110,22 @@ public: Priority getPriority() const; /// Returns the thread's priority. + void setStackSize(std::size_t size); + /// Sets the thread's stack size in bytes. + /// Setting the stack size to 0 will use the default stack size. + /// Typically, the real stack size is rounded up to the nearest + /// page size multiple. + + std::size_t getStackSize() const; + /// Returns the thread's stack size in bytes. + /// If the default stack size is used, 0 is returned. + void start(Runnable& target); /// Starts the thread with the given target. + void start(Callback target, void* pData = 0); + /// Starts the thread with the given target and parameter. + void join(); /// Waits until the thread completes execution. /// If multiple threads try to join the same @@ -216,6 +231,18 @@ inline Thread* Thread::current() } +inline void Thread::setStackSize(std::size_t size) +{ + setStackSizeImpl(size); +} + + +inline std::size_t Thread::getStackSize() const +{ + return getStackSizeImpl(); +} + + } // namespace Poco diff --git a/Foundation/include/Poco/ThreadTarget.h b/Foundation/include/Poco/ThreadTarget.h new file mode 100644 index 000000000..125643cf9 --- /dev/null +++ b/Foundation/include/Poco/ThreadTarget.h @@ -0,0 +1,104 @@ +// +// ThreadTarget.h +// +// $Id: //poco/svn/Foundation/include/Poco/ThreadTarget.h#2 $ +// +// Library: Foundation +// Package: Threading +// Module: ThreadTarget +// +// Definition of the ThreadTarget class. +// +// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#ifndef Foundation_ThreadTarget_INCLUDED +#define Foundation_ThreadTarget_INCLUDED + + +#include "Poco/Foundation.h" +#include "Poco/Runnable.h" + + +namespace Poco { + + +class Foundation_API ThreadTarget: public Runnable + /// This adapter simplifies using static member functions as well as + /// standalone functions as targets for threads. + /// Note that it is possible to pass those entities directly to Thread::start(). + /// This adapter is provided as a convenience for higher abstraction level + /// scenarios where Runnable abstract class is used. + /// + /// Usage: + /// class MyObject + /// { + /// static void doSomething() {} + /// }; + /// ThreadTarget ra(&MyObject::doSomething)); + /// Thread thr; + /// thr.start(ra); + /// + /// or: + /// + /// void doSomething() {} + /// + /// ThreadTarget ra(doSomething)); + /// Thread thr; + /// thr.start(ra); + +{ +public: + typedef void (*Callback)(); + + ThreadTarget(Callback method); + + ThreadTarget(const ThreadTarget& te); + + ~ThreadTarget(); + + ThreadTarget& operator = (const ThreadTarget& te); + + void run(); + +private: + ThreadTarget(); + + Callback _method; +}; + + +inline void ThreadTarget::run() +{ + _method(); +} + + +} // namespace Poco + + +#endif // Foundation_ThreadTarget_INCLUDED diff --git a/Foundation/include/Poco/Thread_POSIX.h b/Foundation/include/Poco/Thread_POSIX.h index da5c9a391..41a257c3f 100644 --- a/Foundation/include/Poco/Thread_POSIX.h +++ b/Foundation/include/Poco/Thread_POSIX.h @@ -59,6 +59,8 @@ namespace Poco { class Foundation_API ThreadImpl { public: + typedef void (*Callback)(void*); + enum Priority { PRIO_LOWEST_IMPL, @@ -68,13 +70,25 @@ public: PRIO_HIGHEST_IMPL }; + struct CallbackData: public RefCountedObject + { + CallbackData(): callback(0), pData(0) + { + } + + Callback callback; + void* pData; + }; + ThreadImpl(); ~ThreadImpl(); - Runnable& targetImpl() const; void setPriorityImpl(int prio); int getPriorityImpl() const; + void setStackSizeImpl(std::size_t size); + std::size_t getStackSizeImpl() const; void startImpl(Runnable& target); + void startImpl(Callback target, void* pData = 0); void joinImpl(); bool joinImpl(long milliseconds); @@ -91,19 +105,23 @@ private: struct ThreadData: public RefCountedObject { ThreadData(): - pTarget(0), + pRunnableTarget(0), + pCallbackTarget(0), thread(0), prio(PRIO_NORMAL_IMPL), - done(false) + done(false), + stackSize(0) { } - Runnable* pTarget; - pthread_t thread; - int prio; - Event done; + Runnable* pRunnableTarget; + AutoPtr pCallbackTarget; + pthread_t thread; + int prio; + Event done; + std::size_t stackSize; }; - + AutoPtr _pData; static pthread_key_t _currentKey; @@ -142,12 +160,31 @@ inline void ThreadImpl::sleepImpl(long milliseconds) } +inline bool ThreadImpl::isRunningImpl() const +{ + return _pData->pRunnableTarget != 0 || + (_pData->pCallbackTarget.get() != 0 && _pData->pCallbackTarget->callback != 0); +} + + inline void ThreadImpl::yieldImpl() { sched_yield(); } +inline void ThreadImpl::setStackSizeImpl(std::size_t size) +{ + _pData->stackSize = size; +} + + +inline std::size_t ThreadImpl::getStackSizeImpl() const +{ + return _pData->stackSize; +} + + } // namespace Poco diff --git a/Foundation/include/Poco/Thread_WIN32.h b/Foundation/include/Poco/Thread_WIN32.h index b594646fd..ec9e43746 100644 --- a/Foundation/include/Poco/Thread_WIN32.h +++ b/Foundation/include/Poco/Thread_WIN32.h @@ -51,6 +51,24 @@ namespace Poco { class Foundation_API ThreadImpl { public: + typedef void (*Callback)(void*); + +#if defined(_DLL) + typedef DWORD (WINAPI *Entry)(LPVOID); +#else + typedef unsigned (__stdcall *Entry)(void*); +#endif + + struct CallbackData + { + CallbackData(): callback(0), pData(0) + { + } + + Callback callback; + void* pData; + }; + enum Priority { PRIO_LOWEST_IMPL = THREAD_PRIORITY_LOWEST, @@ -65,7 +83,10 @@ public: void setPriorityImpl(int prio); int getPriorityImpl() const; + void setStackSizeImpl(std::size_t size); + std::size_t getStackSizeImpl() const; void startImpl(Runnable& target); + void startImpl(Callback target, void* pData = 0); void joinImpl(); bool joinImpl(long milliseconds); @@ -76,15 +97,26 @@ public: protected: #if defined(_DLL) - static DWORD WINAPI entry(LPVOID pThread); + static DWORD WINAPI runnableEntry(LPVOID pThread); #else - static unsigned __stdcall entry(void* pThread); + static unsigned __stdcall runnableEntry(void* pThread); #endif +#if defined(_DLL) + static DWORD WINAPI functionEntry(LPVOID pThread); +#else + static unsigned __stdcall functionEntry(void* pThread); +#endif + + void createImpl(Entry ent, void* pData); + void threadCleanup(); + private: - Runnable* _pTarget; - HANDLE _thread; - int _prio; + Runnable* _pRunnableTarget; + CallbackData _callbackTarget; + HANDLE _thread; + int _prio; + std::size_t _stackSize; static DWORD _currentKey; }; @@ -111,6 +143,18 @@ inline void ThreadImpl::yieldImpl() } +inline void ThreadImpl::setStackSizeImpl(std::size_t size) +{ + _stackSize = size; +} + + +inline std::size_t ThreadImpl::getStackSizeImpl() const +{ + return _stackSize; +} + + } // namespace Poco diff --git a/Foundation/src/Thread.cpp b/Foundation/src/Thread.cpp index b7db7b85c..acc16f52f 100644 --- a/Foundation/src/Thread.cpp +++ b/Foundation/src/Thread.cpp @@ -91,6 +91,12 @@ void Thread::start(Runnable& target) } +void Thread::start(Callback target, void* pData) +{ + startImpl(target, pData); +} + + void Thread::join() { joinImpl(); diff --git a/Foundation/src/ThreadTarget.cpp b/Foundation/src/ThreadTarget.cpp new file mode 100644 index 000000000..7b1751219 --- /dev/null +++ b/Foundation/src/ThreadTarget.cpp @@ -0,0 +1,66 @@ +// +// ThreadTarget.cpp +// +// $Id: //poco/svn/Foundation/src/ThreadTarget.cpp#2 $ +// +// Library: Foundation +// Package: Threading +// Module: ThreadTarget +// +// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#include "Poco/ThreadTarget.h" + + + +namespace Poco { + + +ThreadTarget::ThreadTarget(Callback method): _method(method) +{ +} + + +ThreadTarget::ThreadTarget(const ThreadTarget& te): _method(te._method) +{ +} + + +ThreadTarget& ThreadTarget::operator = (const ThreadTarget& te) +{ + _method = te._method; + return *this; +} + + +ThreadTarget::~ThreadTarget() +{ +} + + +} // namespace Poco diff --git a/Foundation/src/Thread_POSIX.cpp b/Foundation/src/Thread_POSIX.cpp index ef3996488..93d639918 100644 --- a/Foundation/src/Thread_POSIX.cpp +++ b/Foundation/src/Thread_POSIX.cpp @@ -39,7 +39,6 @@ #include "Poco/ErrorHandler.h" #include - // // Block SIGPIPE in main thread. // @@ -87,7 +86,7 @@ ThreadImpl::ThreadImpl(): ThreadImpl::~ThreadImpl() { - if (_pData->pTarget) + if (isRunningImpl()) pthread_detach(_pData->thread); } @@ -97,7 +96,7 @@ void ThreadImpl::setPriorityImpl(int prio) if (prio != _pData->prio) { _pData->prio = prio; - if (_pData->pTarget) + if (isRunningImpl()) { struct sched_param par; par.sched_priority = mapPrio(_pData->prio); @@ -110,12 +109,52 @@ void ThreadImpl::setPriorityImpl(int prio) void ThreadImpl::startImpl(Runnable& target) { - if (_pData->pTarget) throw SystemException("thread already running"); + if (_pData->pRunnableTarget) throw SystemException("thread already running"); - _pData->pTarget = ⌖ - if (pthread_create(&_pData->thread, NULL, entry, this)) + pthread_attr_t attributes; + pthread_attr_init(&attributes); + + if (_pData->stackSize != 0) + pthread_attr_setstacksize(&attributes, _pData->stackSize); + + _pData->pRunnableTarget = ⌖ + if (pthread_create(&_pData->thread, &attributes, entry, this)) { - _pData->pTarget = 0; + _pData->pRunnableTarget = 0; + throw SystemException("cannot start thread"); + } + + if (_pData->prio != PRIO_NORMAL_IMPL) + { + struct sched_param par; + par.sched_priority = mapPrio(_pData->prio); + if (pthread_setschedparam(_pData->thread, SCHED_OTHER, &par)) + throw SystemException("cannot set thread priority"); + } +} + + +void ThreadImpl::startImpl(Callback target, void* pData) +{ + if (_pData->pCallbackTarget && _pData->pCallbackTarget->callback) + throw SystemException("thread already running"); + + pthread_attr_t attributes; + pthread_attr_init(&attributes); + + if (_pData->stackSize != 0) + pthread_attr_setstacksize(&attributes, _pData->stackSize); + + if (0 == _pData->pCallbackTarget.get()) + _pData->pCallbackTarget = new CallbackData; + + _pData->pCallbackTarget->callback = target; + _pData->pCallbackTarget->pData = pData; + + if (pthread_create(&_pData->thread, &attributes, entry, this)) + { + _pData->pCallbackTarget->callback = 0; + _pData->pCallbackTarget->pData = 0; throw SystemException("cannot start thread"); } @@ -151,12 +190,6 @@ bool ThreadImpl::joinImpl(long milliseconds) } -bool ThreadImpl::isRunningImpl() const -{ - return _pData->pTarget != 0; -} - - ThreadImpl* ThreadImpl::currentImpl() { if (_haveCurrentKey) @@ -183,7 +216,10 @@ void* ThreadImpl::entry(void* pThread) AutoPtr pData = pThreadImpl->_pData; try { - pData->pTarget->run(); + if (pData->pRunnableTarget) + pData->pRunnableTarget->run(); + else + pData->pCallbackTarget->callback(pData->pCallbackTarget->pData); } catch (Exception& exc) { @@ -197,7 +233,14 @@ void* ThreadImpl::entry(void* pThread) { ErrorHandler::handle(); } - pData->pTarget = 0; + if (pData->pRunnableTarget) + pData->pRunnableTarget = 0; + else + { + pData->pCallbackTarget->callback = 0; + pData->pCallbackTarget->pData = 0; + } + pData->done.set(); return 0; } diff --git a/Foundation/src/Thread_WIN32.cpp b/Foundation/src/Thread_WIN32.cpp index 73ff8098f..39452bc6c 100644 --- a/Foundation/src/Thread_WIN32.cpp +++ b/Foundation/src/Thread_WIN32.cpp @@ -46,7 +46,11 @@ namespace Poco { DWORD ThreadImpl::_currentKey = TLS_OUT_OF_INDEXES; -ThreadImpl::ThreadImpl(): _pTarget(0), _thread(0), _prio(PRIO_NORMAL_IMPL) +ThreadImpl::ThreadImpl(): + _pRunnableTarget(0), + _thread(0), + _prio(PRIO_NORMAL_IMPL), + _stackSize(0) { if (_currentKey == TLS_OUT_OF_INDEXES) { @@ -79,15 +83,35 @@ void ThreadImpl::setPriorityImpl(int prio) void ThreadImpl::startImpl(Runnable& target) { - if (_thread) throw SystemException("thread already running"); + if (isRunningImpl()) + throw SystemException("thread already running"); - _pTarget = ⌖ + _pRunnableTarget = ⌖ + + createImpl(runnableEntry, this); +} + + +void ThreadImpl::startImpl(Callback target, void* pData) +{ + if (isRunningImpl()) + throw SystemException("thread already running"); + + _callbackTarget.callback = target; + _callbackTarget.pData = pData; + + createImpl(functionEntry, this); +} + + +void ThreadImpl::createImpl(Entry ent, void* pData) +{ #if defined(_DLL) DWORD threadId; - _thread = CreateThread(NULL, 0, entry, this, 0, &threadId); + _thread = CreateThread(NULL, _stackSize, ent, pData, 0, &threadId); #else unsigned threadId; - _thread = (HANDLE) _beginthreadex(NULL, 0, entry, this, 0, &threadId); + _thread = (HANDLE) _beginthreadex(NULL, _stackSize, runnableEntry, this, 0, &threadId); #endif if (!_thread) throw SystemException("cannot create thread"); @@ -103,6 +127,7 @@ void ThreadImpl::joinImpl() switch (WaitForSingleObject(_thread, INFINITE)) { case WAIT_OBJECT_0: + threadCleanup(); return; default: throw SystemException("cannot join thread"); @@ -119,6 +144,7 @@ bool ThreadImpl::joinImpl(long milliseconds) case WAIT_TIMEOUT: return false; case WAIT_OBJECT_0: + threadCleanup(); return true; default: throw SystemException("cannot join thread"); @@ -137,6 +163,13 @@ bool ThreadImpl::isRunningImpl() const } +void ThreadImpl::threadCleanup() +{ + if (!_thread) return; + if (CloseHandle(_thread)) _thread = 0; +} + + ThreadImpl* ThreadImpl::currentImpl() { if (_currentKey == TLS_OUT_OF_INDEXES) @@ -147,15 +180,43 @@ ThreadImpl* ThreadImpl::currentImpl() #if defined(_DLL) -DWORD WINAPI ThreadImpl::entry(LPVOID pThread) +DWORD WINAPI ThreadImpl::runnableEntry(LPVOID pThread) #else -unsigned __stdcall ThreadImpl::entry(void* pThread) +unsigned __stdcall ThreadImpl::runnableEntry(void* pThread) #endif { TlsSetValue(_currentKey, pThread); try { - reinterpret_cast(pThread)->_pTarget->run(); + reinterpret_cast(pThread)->_pRunnableTarget->run(); + } + catch (Exception& exc) + { + ErrorHandler::handle(exc); + } + catch (std::exception& exc) + { + ErrorHandler::handle(exc); + } + catch (...) + { + ErrorHandler::handle(); + } + return 0; +} + + +#if defined(_DLL) +DWORD WINAPI ThreadImpl::functionEntry(LPVOID pThread) +#else +unsigned __stdcall ThreadImpl::functionEntry(void* pThread) +#endif +{ + TlsSetValue(_currentKey, pThread); + try + { + ThreadImpl* pTI = reinterpret_cast(pThread); + pTI->_callbackTarget.callback(pTI->_callbackTarget.pData); } catch (Exception& exc) { diff --git a/Foundation/testsuite/src/ThreadTest.cpp b/Foundation/testsuite/src/ThreadTest.cpp index 146fae819..b25a041e0 100644 --- a/Foundation/testsuite/src/ThreadTest.cpp +++ b/Foundation/testsuite/src/ThreadTest.cpp @@ -35,11 +35,13 @@ #include "CppUnit/TestSuite.h" #include "Poco/Thread.h" #include "Poco/Runnable.h" +#include "Poco/ThreadTarget.h" #include "Poco/Event.h" - +#include using Poco::Thread; using Poco::Runnable; +using Poco::ThreadTarget; using Poco::Event; @@ -74,6 +76,13 @@ public: _event.set(); } + static void staticFunc() + { + ++_staticVar; + } + + static int _staticVar; + private: bool _ran; std::string _threadName; @@ -81,6 +90,21 @@ private: }; +int MyRunnable::_staticVar = 0; + + +void freeFunc() +{ + ++MyRunnable::_staticVar; +} + + +void freeFunc(void* pData) +{ + MyRunnable::_staticVar += *reinterpret_cast(pData); +} + + ThreadTest::ThreadTest(const std::string& name): CppUnit::TestCase(name) { } @@ -195,6 +219,75 @@ void ThreadTest::testJoin() } +void ThreadTest::testThreadTarget() +{ + ThreadTarget te(&MyRunnable::staticFunc); + Thread thread; + + assert (!thread.isRunning()); + + int tmp = MyRunnable::_staticVar; + thread.start(te); + thread.join(); + assert (tmp + 1 == MyRunnable::_staticVar); + + ThreadTarget te1(freeFunc); + assert (!thread.isRunning()); + + tmp = MyRunnable::_staticVar; + thread.start(te1); + thread.join(); + assert (tmp + 1 == MyRunnable::_staticVar); +} + + +void ThreadTest::testThreadFunction() +{ + Thread thread; + + assert (!thread.isRunning()); + + int tmp = MyRunnable::_staticVar; + thread.start(freeFunc, &tmp); + thread.join(); + assert (tmp * 2 == MyRunnable::_staticVar); + + assert (!thread.isRunning()); + + tmp = MyRunnable::_staticVar = 0; + thread.start(freeFunc, &tmp); + thread.join(); + assert (0 == MyRunnable::_staticVar); +} + + +void ThreadTest::testThreadStackSize() +{ + Thread thread; + assert (0 == thread.getStackSize()); + thread.setStackSize(50000000); + assert (50000000 == thread.getStackSize()); + int tmp = MyRunnable::_staticVar; + thread.start(freeFunc, &tmp); + thread.join(); + assert (tmp * 2 == MyRunnable::_staticVar); + + thread.setStackSize(1); + assert (1 == thread.getStackSize()); + tmp = MyRunnable::_staticVar; + thread.start(freeFunc, &tmp); + thread.join(); + assert (tmp * 2 == MyRunnable::_staticVar); + + thread.setStackSize(0); + assert (0 == thread.getStackSize()); + tmp = MyRunnable::_staticVar; + thread.start(freeFunc, &tmp); + thread.join(); + assert (tmp * 2 == MyRunnable::_staticVar); +} + + void ThreadTest::setUp() { } @@ -214,6 +307,9 @@ CppUnit::Test* ThreadTest::suite() CppUnit_addTest(pSuite, ThreadTest, testCurrent); CppUnit_addTest(pSuite, ThreadTest, testThreads); CppUnit_addTest(pSuite, ThreadTest, testJoin); + CppUnit_addTest(pSuite, ThreadTest, testThreadTarget); + CppUnit_addTest(pSuite, ThreadTest, testThreadFunction); + CppUnit_addTest(pSuite, ThreadTest, testThreadStackSize); return pSuite; } diff --git a/Foundation/testsuite/src/ThreadTest.h b/Foundation/testsuite/src/ThreadTest.h index b2b67b276..d90b4fc87 100644 --- a/Foundation/testsuite/src/ThreadTest.h +++ b/Foundation/testsuite/src/ThreadTest.h @@ -51,6 +51,9 @@ public: void testCurrent(); void testThreads(); void testJoin(); + void testThreadTarget(); + void testThreadFunction(); + void testThreadStackSize(); void setUp(); void tearDown();