diff --git a/Foundation/Foundation_vs80.vcproj b/Foundation/Foundation_vs80.vcproj index 3fc78f495..cafea16a6 100644 --- a/Foundation/Foundation_vs80.vcproj +++ b/Foundation/Foundation_vs80.vcproj @@ -1691,6 +1691,10 @@ RelativePath=".\src\ThreadPool.cpp" > + + @@ -1823,6 +1827,10 @@ RelativePath=".\include\Poco\ThreadPool.h" > + + diff --git a/Foundation/include/Poco/Config.h b/Foundation/include/Poco/Config.h index abc1cf794..191fdb58c 100644 --- a/Foundation/include/Poco/Config.h +++ b/Foundation/include/Poco/Config.h @@ -9,7 +9,7 @@ // // Feature configuration for the POCO libraries. // -// Copyright (c) 2006, Applied Informatics Software Engineering GmbH. +// Copyright (c) 2006-2008, Applied Informatics Software Engineering GmbH. // and Contributors. // // Permission is hereby granted, free of charge, to any person or organization @@ -60,4 +60,9 @@ // #define POCO_NO_SHAREDMEMORY +// Define to desired default thread stack size +// Zero means OS default +#define POCO_THREAD_STACK_SIZE 0 + + #endif // Foundation_Config_INCLUDED diff --git a/Foundation/include/Poco/Thread.h b/Foundation/include/Poco/Thread.h index 8f9e66aa5..bfd0257bc 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::Callable; + enum Priority /// Thread priorities. { @@ -108,9 +110,39 @@ public: Priority getPriority() const; /// Returns the thread's priority. + void setOSPriority(int prio); + /// Sets the thread's priority, using an operating system specific + /// priority value. Use getMinOSPriority() and getMaxOSPriority() to + /// obtain mininum and maximum priority values. + + int getOSPriority() const; + /// Returns the thread's priority, expressed as an operating system + /// specific priority value. + + static int getMinOSPriority(); + /// Returns the mininum operating system-specific priority value, + /// which can be passed to setOSPriority(). + + static int getMaxOSPriority(); + /// Returns the maximum operating system-specific priority value, + /// which can be passed to setOSPriority(). + + void setStackSize(int 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. + + int 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(Callable 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 +248,42 @@ inline Thread* Thread::current() } +inline void Thread::setOSPriority(int prio) +{ + setOSPriorityImpl(prio); +} + + +inline int Thread::getOSPriority() const +{ + return getOSPriorityImpl(); +} + + +inline int Thread::getMinOSPriority() +{ + return ThreadImpl::getMinOSPriorityImpl(); +} + + +inline int Thread::getMaxOSPriority() +{ + return ThreadImpl::getMaxOSPriorityImpl(); +} + + +inline void Thread::setStackSize(int size) +{ + setStackSizeImpl(size); +} + + +inline int Thread::getStackSize() const +{ + return getStackSizeImpl(); +} + + } // namespace Poco diff --git a/Foundation/include/Poco/ThreadPool.h b/Foundation/include/Poco/ThreadPool.h index e4eca293d..4df208dec 100644 --- a/Foundation/include/Poco/ThreadPool.h +++ b/Foundation/include/Poco/ThreadPool.h @@ -69,14 +69,21 @@ class Foundation_API ThreadPool /// from the pool. { public: - ThreadPool(int minCapacity = 2, int maxCapacity = 16, int idleTime = 60); - ThreadPool(const std::string& name, int minCapacity = 2, int maxCapacity = 16, int idleTime = 60); + ThreadPool(int minCapacity = 2, + int maxCapacity = 16, + int idleTime = 60, + int stackSize = POCO_THREAD_STACK_SIZE); + ThreadPool(const std::string& name, + int minCapacity = 2, + int maxCapacity = 16, + int idleTime = 60, + int stackSize = POCO_THREAD_STACK_SIZE); /// Creates a thread pool with minCapacity threads. /// If required, up to maxCapacity threads are created /// a NoThreadAvailableException exception is thrown. /// If a thread is running idle for more than idleTime seconds, /// and more than minCapacity threads are running, the thread - /// is killed. + /// is killed. Threads are created with given stack size. ~ThreadPool(); /// Currently running threads will remain active @@ -89,6 +96,13 @@ public: int capacity() const; /// Returns the maximum capacity of threads. + void setStackSize(int stackSize); + /// Sets the stack size for threads. + /// New stack size applies only for newly created threads. + + int getStackSize() const; + /// Returns the stack size used to create new threads. + int used() const; /// Returns the number of currently used threads. @@ -159,11 +173,26 @@ private: int _idleTime; int _serial; int _age; + int _stackSize; ThreadVec _threads; mutable FastMutex _mutex; }; +// inlines + +inline void ThreadPool::setStackSize(int stackSize) +{ + _stackSize = stackSize; +} + + +inline int ThreadPool::getStackSize() const +{ + return _stackSize; +} + + } // namespace Poco diff --git a/Foundation/include/Poco/Thread_POSIX.h b/Foundation/include/Poco/Thread_POSIX.h index 84c2574c2..29cbc2c1f 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 (*Callable)(void*); + enum Priority { PRIO_LOWEST_IMPL, @@ -68,13 +70,29 @@ public: PRIO_HIGHEST_IMPL }; + struct CallbackData: public RefCountedObject + { + CallbackData(): callback(0), pData(0) + { + } + + Callable callback; + void* pData; + }; + ThreadImpl(); ~ThreadImpl(); - Runnable& targetImpl() const; void setPriorityImpl(int prio); int getPriorityImpl() const; + void setOSPriorityImpl(int prio); + int getOSPriorityImpl() const; + static int getMinOSPriorityImpl(); + static int getMaxOSPriorityImpl(); + void setStackSizeImpl(int size); + int getStackSizeImpl() const; void startImpl(Runnable& target); + void startImpl(Callable target, void* pData = 0); void joinImpl(); bool joinImpl(long milliseconds); @@ -84,28 +102,35 @@ public: static ThreadImpl* currentImpl(); protected: - static void* entry(void* pThread); + static void* runnableEntry(void* pThread); + static void* callableEntry(void* pThread); static int mapPrio(int prio); + static int reverseMapPrio(int osPrio); private: struct ThreadData: public RefCountedObject { ThreadData(): - pTarget(0), + pRunnableTarget(0), + pCallbackTarget(0), thread(0), prio(PRIO_NORMAL_IMPL), - done(false) + done(false), + stackSize(POCO_THREAD_STACK_SIZE) { } - Runnable* pTarget; - pthread_t thread; - int prio; - Event done; + Runnable* pRunnableTarget; + AutoPtr pCallbackTarget; + pthread_t thread; + int prio; + int osPrio; + Event done; + std::size_t stackSize; }; - + AutoPtr _pData; - + static pthread_key_t _currentKey; static bool _haveCurrentKey; @@ -125,6 +150,12 @@ inline int ThreadImpl::getPriorityImpl() const } +inline int ThreadImpl::getOSPriorityImpl() const +{ + return _pData->osPrio; +} + + inline void ThreadImpl::sleepImpl(long milliseconds) { #if defined(__VMS) || defined(__digital__) @@ -142,12 +173,25 @@ 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 int 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 f5b349cc5..2a87162f0 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 (*Callable)(void*); + +#if defined(_DLL) + typedef DWORD (WINAPI *Entry)(LPVOID); +#else + typedef unsigned (__stdcall *Entry)(void*); +#endif + + struct CallbackData + { + CallbackData(): callback(0), pData(0) + { + } + + Callable callback; + void* pData; + }; + enum Priority { PRIO_LOWEST_IMPL = THREAD_PRIORITY_LOWEST, @@ -65,7 +83,14 @@ public: void setPriorityImpl(int prio); int getPriorityImpl() const; + void setOSPriorityImpl(int prio); + int getOSPriorityImpl() const; + static int getMinOSPriorityImpl(); + static int getMaxOSPriorityImpl(); + void setStackSizeImpl(int size); + int getStackSizeImpl() const; void startImpl(Runnable& target); + void startImpl(Callable target, void* pData = 0); void joinImpl(); bool joinImpl(long milliseconds); @@ -76,15 +101,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 callableEntry(LPVOID pThread); +#else + static unsigned __stdcall callableEntry(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; + int _stackSize; static DWORD _currentKey; }; @@ -99,6 +135,24 @@ inline int ThreadImpl::getPriorityImpl() const } +inline int ThreadImpl::getOSPriorityImpl() const +{ + return _prio; +} + + +inline int ThreadImpl::getMinOSPriorityImpl() +{ + return PRIO_LOWEST_IMPL; +} + + +inline int ThreadImpl::getMaxOSPriorityImpl() +{ + return PRIO_HIGHEST_IMPL; +} + + inline void ThreadImpl::sleepImpl(long milliseconds) { Sleep(DWORD(milliseconds)); @@ -111,6 +165,18 @@ inline void ThreadImpl::yieldImpl() } +inline void ThreadImpl::setStackSizeImpl(int size) +{ + _stackSize = size; +} + + +inline int ThreadImpl::getStackSizeImpl() const +{ + return _stackSize; +} + + } // namespace Poco diff --git a/Foundation/src/Thread.cpp b/Foundation/src/Thread.cpp index 884d7261f..276a451df 100644 --- a/Foundation/src/Thread.cpp +++ b/Foundation/src/Thread.cpp @@ -91,6 +91,12 @@ void Thread::start(Runnable& target) } +void Thread::start(Callable target, void* pData) +{ + startImpl(target, pData); +} + + void Thread::join() { joinImpl(); diff --git a/Foundation/src/ThreadPool.cpp b/Foundation/src/ThreadPool.cpp index c0d5625cb..4c2d70340 100644 --- a/Foundation/src/ThreadPool.cpp +++ b/Foundation/src/ThreadPool.cpp @@ -50,7 +50,7 @@ namespace Poco { class PooledThread: public Runnable { public: - PooledThread(const std::string& name); + PooledThread(const std::string& name, int stackSize = POCO_THREAD_STACK_SIZE); ~PooledThread(); void start(); @@ -66,17 +66,17 @@ public: private: volatile bool _idle; volatile std::time_t _idleTime; - Runnable* _pTarget; - std::string _name; - Thread _thread; - Event _targetReady; - Event _targetCompleted; - Event _started; - FastMutex _mutex; + Runnable* _pTarget; + std::string _name; + Thread _thread; + Event _targetReady; + Event _targetCompleted; + Event _started; + FastMutex _mutex; }; -PooledThread::PooledThread(const std::string& name): +PooledThread::PooledThread(const std::string& name, int stackSize): _idle(true), _idleTime(0), _pTarget(0), @@ -84,6 +84,8 @@ PooledThread::PooledThread(const std::string& name): _thread(name), _targetCompleted(false) { + poco_assert_dbg (stackSize >= 0); + _thread.setStackSize(stackSize); _idleTime = time(NULL); } @@ -231,12 +233,16 @@ void PooledThread::run() } -ThreadPool::ThreadPool(int minCapacity, int maxCapacity, int idleTime): +ThreadPool::ThreadPool(int minCapacity, + int maxCapacity, + int idleTime, + int stackSize): _minCapacity(minCapacity), _maxCapacity(maxCapacity), _idleTime(idleTime), _serial(0), - _age(0) + _age(0), + _stackSize(stackSize) { poco_assert (minCapacity >= 1 && maxCapacity >= minCapacity && idleTime > 0); @@ -249,13 +255,18 @@ ThreadPool::ThreadPool(int minCapacity, int maxCapacity, int idleTime): } -ThreadPool::ThreadPool(const std::string& name, int minCapacity, int maxCapacity, int idleTime): +ThreadPool::ThreadPool(const std::string& name, + int minCapacity, + int maxCapacity, + int idleTime, + int stackSize): _name(name), _minCapacity(minCapacity), _maxCapacity(maxCapacity), _idleTime(idleTime), _serial(0), - _age(0) + _age(0), + _stackSize(stackSize) { poco_assert (minCapacity >= 1 && maxCapacity >= minCapacity && idleTime > 0); @@ -452,7 +463,7 @@ PooledThread* ThreadPool::createThread() { std::ostringstream name; name << _name << "[#" << ++_serial << "]"; - return new PooledThread(name.str()); + return new PooledThread(name.str(), _stackSize); } @@ -474,6 +485,8 @@ public: if (!_pPool) { _pPool = new ThreadPool("default"); + if (POCO_THREAD_STACK_SIZE > 0) + _pPool->setStackSize(POCO_THREAD_STACK_SIZE); } return _pPool; } diff --git a/Foundation/src/Thread_POSIX.cpp b/Foundation/src/Thread_POSIX.cpp index 773153638..a71610364 100644 --- a/Foundation/src/Thread_POSIX.cpp +++ b/Foundation/src/Thread_POSIX.cpp @@ -38,6 +38,10 @@ #include "Poco/Exception.h" #include "Poco/ErrorHandler.h" #include +#if defined(__sun) && defined(__SVR4) +#define __EXTENSIONS__ +#include +#endif // @@ -87,7 +91,7 @@ ThreadImpl::ThreadImpl(): ThreadImpl::~ThreadImpl() { - if (_pData->pTarget) + if (isRunningImpl()) pthread_detach(_pData->thread); } @@ -97,7 +101,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); @@ -108,14 +112,111 @@ void ThreadImpl::setPriorityImpl(int prio) } +void ThreadImpl::setOSPriorityImpl(int prio) +{ + if (prio != _pData->osPrio) + { + if (_pData->pRunnableTarget || _pData->pCallbackTarget) + { + struct sched_param par; + par.sched_priority = prio; + if (pthread_setschedparam(_pData->thread, SCHED_OTHER, &par)) + throw SystemException("cannot set thread priority"); + } + _pData->prio = reverseMapPrio(prio); + _pData->osPrio = prio; + } +} + + +int ThreadImpl::getMinOSPriorityImpl() +{ +#if defined(__VMS) || defined(__digital__) + return PRI_OTHER_MIN; +#else + return sched_get_priority_min(SCHED_OTHER); +#endif +} + + +int ThreadImpl::getMaxOSPriorityImpl() +{ +#if defined(__VMS) || defined(__digital__) + return PRI_OTHER_MAX; +#else + return sched_get_priority_max(SCHED_OTHER); +#endif +} + + +void ThreadImpl::setStackSizeImpl(int size) +{ +#ifdef POCO_OS_CYGWIN + _pData->stackSize = 0; +#else + if (size !=0 && size < PTHREAD_STACK_MIN) + size = PTHREAD_STACK_MIN; + + _pData->stackSize = size; +#endif +} + + 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) { - _pData->pTarget = 0; + if (0 != pthread_attr_setstacksize(&attributes, _pData->stackSize)) + throw SystemException("cannot set thread stack size"); + } + + _pData->pRunnableTarget = ⌖ + if (pthread_create(&_pData->thread, &attributes, runnableEntry, this)) + { + _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(Callable 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) + { + if (0 != pthread_attr_setstacksize(&attributes, _pData->stackSize)) + throw SystemException("can not set thread stack size"); + } + + if (0 == _pData->pCallbackTarget.get()) + _pData->pCallbackTarget = new CallbackData; + + _pData->pCallbackTarget->callback = target; + _pData->pCallbackTarget->pData = pData; + + if (pthread_create(&_pData->thread, &attributes, callableEntry, this)) + { + _pData->pCallbackTarget->callback = 0; + _pData->pCallbackTarget->pData = 0; throw SystemException("cannot start thread"); } @@ -151,12 +252,6 @@ bool ThreadImpl::joinImpl(long milliseconds) } -bool ThreadImpl::isRunningImpl() const -{ - return _pData->pTarget != 0; -} - - ThreadImpl* ThreadImpl::currentImpl() { if (_haveCurrentKey) @@ -166,7 +261,7 @@ ThreadImpl* ThreadImpl::currentImpl() } -void* ThreadImpl::entry(void* pThread) +void* ThreadImpl::runnableEntry(void* pThread) { pthread_setspecific(_currentKey, pThread); @@ -183,7 +278,7 @@ void* ThreadImpl::entry(void* pThread) AutoPtr pData = pThreadImpl->_pData; try { - pData->pTarget->run(); + pData->pRunnableTarget->run(); } catch (Exception& exc) { @@ -197,7 +292,48 @@ void* ThreadImpl::entry(void* pThread) { ErrorHandler::handle(); } - pData->pTarget = 0; + + pData->pRunnableTarget = 0; + pData->done.set(); + return 0; +} + + +void* ThreadImpl::callableEntry(void* pThread) +{ + pthread_setspecific(_currentKey, pThread); + +#if defined(POCO_OS_FAMILY_UNIX) + sigset_t sset; + sigemptyset(&sset); + sigaddset(&sset, SIGQUIT); + sigaddset(&sset, SIGTERM); + sigaddset(&sset, SIGPIPE); + pthread_sigmask(SIG_BLOCK, &sset, 0); +#endif + + ThreadImpl* pThreadImpl = reinterpret_cast(pThread); + AutoPtr pData = pThreadImpl->_pData; + try + { + pData->pCallbackTarget->callback(pData->pCallbackTarget->pData); + } + catch (Exception& exc) + { + ErrorHandler::handle(exc); + } + catch (std::exception& exc) + { + ErrorHandler::handle(exc); + } + catch (...) + { + ErrorHandler::handle(); + } + + pData->pCallbackTarget->callback = 0; + pData->pCallbackTarget->pData = 0; + pData->done.set(); return 0; } @@ -232,4 +368,22 @@ int ThreadImpl::mapPrio(int prio) } +int ThreadImpl::reverseMapPrio(int prio) +{ + int pmin = getMinOSPriorityImpl(); + int pmax = getMaxOSPriorityImpl(); + int normal = pmin + (pmax - pmin)/2; + if (prio == pmax) + return PRIO_HIGHEST_IMPL; + if (prio > normal) + return PRIO_HIGH_IMPL; + else if (prio == normal) + return PRIO_NORMAL_IMPL; + else if (prio > pmin) + return PRIO_LOW_IMPL; + else + return PRIO_LOWEST_IMPL; +} + + } // namespace Poco diff --git a/Foundation/src/Thread_WIN32.cpp b/Foundation/src/Thread_WIN32.cpp index 7fb9a102a..ed6b5941c 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(POCO_THREAD_STACK_SIZE) { if (_currentKey == TLS_OUT_OF_INDEXES) { @@ -77,17 +81,43 @@ void ThreadImpl::setPriorityImpl(int prio) } +void ThreadImpl::setOSPriorityImpl(int prio) +{ + setPriorityImpl(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(Callable target, void* pData) +{ + if (isRunningImpl()) + throw SystemException("thread already running"); + + _callbackTarget.callback = target; + _callbackTarget.pData = pData; + + createImpl(callableEntry, 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 +133,7 @@ void ThreadImpl::joinImpl() switch (WaitForSingleObject(_thread, INFINITE)) { case WAIT_OBJECT_0: + threadCleanup(); return; default: throw SystemException("cannot join thread"); @@ -119,6 +150,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 +169,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 +186,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::callableEntry(LPVOID pThread) +#else +unsigned __stdcall ThreadImpl::callableEntry(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/ThreadPoolTest.cpp b/Foundation/testsuite/src/ThreadPoolTest.cpp index a9122ca73..8081e1e47 100644 --- a/Foundation/testsuite/src/ThreadPoolTest.cpp +++ b/Foundation/testsuite/src/ThreadPoolTest.cpp @@ -57,7 +57,8 @@ ThreadPoolTest::~ThreadPoolTest() void ThreadPoolTest::testThreadPool() { ThreadPool pool(2, 3, 3); - + pool.setStackSize(1); + assert (pool.allocated() == 2); assert (pool.used() == 0); assert (pool.capacity() == 3); diff --git a/Foundation/testsuite/src/ThreadTest.cpp b/Foundation/testsuite/src/ThreadTest.cpp index 17f8b949b..aecc3f20f 100644 --- a/Foundation/testsuite/src/ThreadTest.cpp +++ b/Foundation/testsuite/src/ThreadTest.cpp @@ -35,11 +35,18 @@ #include "CppUnit/TestSuite.h" #include "Poco/Thread.h" #include "Poco/Runnable.h" +#include "Poco/ThreadTarget.h" #include "Poco/Event.h" +#include +#if defined(__sun) && defined(__SVR4) +#define __EXTENSIONS__ +#include +#endif using Poco::Thread; using Poco::Runnable; +using Poco::ThreadTarget; using Poco::Event; @@ -74,6 +81,13 @@ public: _event.set(); } + static void staticFunc() + { + ++_staticVar; + } + + static int _staticVar; + private: bool _ran; std::string _threadName; @@ -81,6 +95,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 +224,82 @@ 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() +{ + int stackSize = 50000000; + + Thread thread; + assert (0 == thread.getStackSize()); + thread.setStackSize(stackSize); + assert (stackSize == thread.getStackSize()); + int tmp = MyRunnable::_staticVar; + thread.start(freeFunc, &tmp); + thread.join(); + assert (tmp * 2 == MyRunnable::_staticVar); + + stackSize = 1; + thread.setStackSize(stackSize); +#if defined(POCO_OS_FAMILY_UNIX) && !defined(POCO_OS_CYGWIN) + assert (PTHREAD_STACK_MIN == thread.getStackSize()); +#else + assert (stackSize == thread.getStackSize()); +#endif + 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 +319,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 bf1aafa5c..ef65fdfae 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();